How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games
Most of your players will not have cryptocurrencies in their wallets. Onboarding funds into cryptocurrencies using traditional means can be a hassle for players and may be too stressful for users who have less technical experience. In any case, minimizing payment friction has always been a very important requirement to an effective monetization strategy. The most frictionless method for making microtransactions for the majority of users on mobile will be with the in-app purchasing method they are already used to: IAP via the iOS App Store and Android Google Play Store. This is especially true if your are using Embedded Wallets and building games where the blockchain is invisible.This guide will explain how we updated Jelly Forest, our embedded wallet showcase game made with Unity, to add an IAP that mints you a goofy hot dog hat for your Jelly.
The first step, if you haven’t done so already, is to deploy a smart contract that will define and represent the NFTs you aim to sell to your players and display in your game.Once you’ve deployed your smart contract, don’t forget to add your contract address as a Sponsored Address on the “Gas Sponsoring” page on the Builder Console! This will make it so that your users have their gas fees automatically sponsored using your compute credits when interacting with your game’s smart contracts.
By default, ERC1155/721 contracts deployed via the Builder Console require callers to have the appropriate permissions in order to mint a token. While this may seem like a nuisance at first glance, this is a good thing! Without this, anyone could call the mint method on your contract and give themselves infinite in-game items!You’ll want to deploy a server with a Sequence wallet (or other) and give it minting permissions in the builder.
Give your server a name by changing the name string
Create a new EOA wallet and export the private key. Any EOA wallet is fine. Metamask can be used to easily setup a wallet and export the private key. Please be very careful with the private key and don’t store it in plain text on your computer or commit it to version control! Set this under PKEY
Set the CONTRACT_ADDRESS
Set the PROJECT_ACCESS_KEY - this is your prod API key from the Builder Console you retrieved earlier when setting up the SequenceConfig scriptable object
Set the CHAIN_HANDLE - if you’re not sure what this is, you can see the CHAIN_HANDLE for each respective network on the Node Gateway page of the Builder Console.
pnpm dev - this will deploy the server locally. You should see which localhost it is deployed to in the command line
Open another command line window
curl http://localhost:8787 - substitute whichever localhost you are given. This will ping the server.
In the command line where the localhost server is running, you should see that the minter’s wallet address has been logged
Grant this address minting permissions in the Builder Console
Find the contract under Contracts and click to open it
Click Write Contract
Expand grantRole
Under role enter 0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6 - this is the Keccak-256 hash of MINTER_ROLE
Under account paste the minter’s wallet address
wrangler deploy - this will deploy the code to a Cloudflare Worker and give you a minting URL
Great! Now, when we send a POST request to our server with a body defined in C#, where the proof is generated by the client sending the minting request. In the Unity SDK this is implemented by the MintingRequestProver.
Handle IAP Purchased Tokens with the Remote Minter
Above, we’ve deployed a remote minter that is useful for minting tokens that can be earned through in-game actions. Let’s see how we can leverage this server so that we can also mint tokens that are purchasable via IAP.You’ll notice that a receipt can also be included in the payload sent to the remote minter. This is where you’ll include the IAP receive from Google/Apple. Unity recommends using Nobuyori Takahashi’s IAP project to verify IAP receipts received via Unity IAP on the server side.Once you’ve validated the receipt on the server side, you can proceed with your minting logic, using the provided sample code above as a reference.
On the Unity side, the first step is integrating Unity IAP into your project.In your ProcessPurchase methods in your IStoreListener from the integration process, you’ll want to initiate the minting process. In Jelly Forest, this is done via the UnityIAP and PremiumItem scripts.In terms of the payload, you can see in the PremiumItem implementation that I am adding a PermissionedMintTransaction to a TransactionQueuer.
public void AddToPremiumTransactionQueue(PermissionedMintTransaction payload, string iapReceipt){ PremiumIAPMinter minter = new PremiumIAPMinter(new MintingRequestProver(Wallet, Chain), _mintEndpoint, ContractAddress, iapReceipt); _permissionedMinterTransactionQueuer.Enqueue((payload, minter));}
where _permissionedMinterTransactionQueuer is a PermissionedMinterTransactionQueuer.This will send a payload in this format:
ProofPayload: { "app": "Made with Sequence Unity SDK App", "iat": (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds(), // issued at time "exp": (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 300, // expiry time "ogn": "Sequence Unity SDK", "payload": { "contractAddress": "0xabc123...", "tokenId": "11", "amount": 5, "receipt": <IAP Receipt String here> }}This JSON get stringified and included in the MintingRequestProof:{ "Proof": "{\"app\": \"Made with Sequence Unity SDK App\", \"iat\": ...}", "SignedProof": "0x123def...", // proof signed by the player's embedded wallet "SigningAddress": "0xa1b2c3..." // the player's embedded wallet address}
For more information on the transaction queuers, please checkout this doc.
Apple and Google allow users the option to chargeback an IAP made by mistake. In this case, your user will still have the token(s) minted to them. While you can handle this via traditional means (e.g. banning players who frequently chargeback purchases), you should be careful not to sell high-value NFTs via this method due to fraudulent chargeback risk.
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Sequence Docs","colors":{"primary":"#B1A9FF","light":"#B1A9FF","dark":"#111111"},"logo":{"light":"https://mintcdn.com/sequence-0fb8d9e6/9rKTa07iWJtIbdn7/logo/sequence-composite-light.svg?fit=max\u0026auto=format\u0026n=9rKTa07iWJtIbdn7\u0026q=85\u0026s=18750aafea1146db72d2e3b695536390","dark":"https://mintcdn.com/sequence-0fb8d9e6/9rKTa07iWJtIbdn7/logo/sequence-composite-dark.svg?fit=max\u0026auto=format\u0026n=9rKTa07iWJtIbdn7\u0026q=85\u0026s=6efde0d56c8457026275cc8f3e34f0a4"},"favicon":"https://mintcdn.com/sequence-0fb8d9e6/Trdl1z4HOb4QxorB/favicon.png?fit=max\u0026auto=format\u0026n=Trdl1z4HOb4QxorB\u0026q=85\u0026s=d076be8f12c5eccec147aaca12dad634","appearance":{"default":"light","strict":false},"background":{"decoration":"gradient"},"navbar":{"primary":{"type":"button","label":"Sign In","href":"https://sequence.build"}},"footer":{"socials":{"x":"https://twitter.com/0xsequence","github":"https://github.com/0xsequence","discord":"https://discord.com/invite/YnGKP7d3vS"}},"fonts":{"heading":{"family":"Inter"},"body":{"family":"Inter"}},"integrations":{"gtm":{"tagId":"GTM-MJL772VN"}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"styling":{"latex":false},"navigation":{"global":{"anchors":[{"anchor":"Supported Chains","icon":"heart-pulse","href":"https://status.sequence.info/"},{"anchor":"Changelog","icon":"map","href":"https://0xsequence.featurebase.app/changelog"}]},"languages":[{"language":"en","href":"home"},{"language":"ja","href":"ja/home"},{"language":"es","href":"es/home"}]}},"deployment":{"deploymentMetadataValue":{"subdomain":"sequence-0fb8d9e6","hasAudioNarration":false,"actualSubdomain":"sequence-0fb8d9e6","customDomains":["docs.sequence.xyz"],"gitSource":{"type":"github","owner":"0xsequence","repo":"docs","deployBranch":"master","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6a6b4f53bf20c4c03c2d22f7","collectionId":"4bb0d586-b014-44f6-932e-3be852309503","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6a6b4f53bf20c4c03c2d22f7"},"feedback":{"thumbs":true,"edits":true,"issues":false},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"REMOVE_BRANDING":{"status":"ENABLED"},"CONTEXTUAL_FEEDBACK":{"status":"ENABLED"},"CODE_SNIPPET_FEEDBACK":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae9253b7669ca8a6a0b3aaa:success","clientVersion":"0.0.4054","searchFilterCounts":[{"language":"en","tag":"SDKs","count":193},{"language":"en","tag":"APIs","count":184},{"language":"ja","tag":"API","count":181},{"language":"en","tag":"Endpoints","count":150},{"language":"ja","tag":"エンドポイント","count":147},{"language":"en","tag":"Web SDKs","count":107},{"language":"ja","tag":"SDK","count":97},{"language":"en","tag":"Hooks","count":83},{"language":"en","tag":"Solutions","count":81},{"language":"en","tag":"Game Engine SDKs","count":71},{"language":"en","tag":"secret","count":70},{"language":"ja","tag":"シークレット","count":70},{"language":"en","tag":"Marketplace","count":59},{"language":"es","tag":"SDKs","count":54},{"language":"ja","tag":"ソリューション","count":52},{"language":"en","tag":"Wallets","count":49},{"language":"ja","tag":"アナリティクス","count":46},{"language":"ja","tag":"メタデータ","count":44},{"language":"ja","tag":"ゲームエンジンSDK","count":44},{"language":"es","tag":"SDKs Web","count":38},{"language":"ja","tag":"インデクサー","count":38},{"language":"ja","tag":"Web SDK","count":38},{"language":"es","tag":"Hooks","count":27},{"language":"es","tag":"Connect","count":27},{"language":"es","tag":"Soluciones","count":23},{"language":"es","tag":"Cartera del Ecosistema (v6)","count":14},{"language":"es","tag":"Cartera Incrustada (v5)","count":13},{"language":"es","tag":"SDKs de Motor de Juego","count":10},{"language":"es","tag":"Plataforma de Desarrollador","count":8},{"language":"es","tag":"Carteras","count":8}]},"assistantConfig":{},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":".bg-matrix-dark,.dark .bg-matrix-light{background:linear-gradient(0deg,#0d0d0f 0,rgba(13,13,15,.95) 5%,rgba(13,13,15,.8) 15%,rgba(17,17,17,.1) 30%,rgba(17,17,17,.1) 70%,rgba(13,13,15,.8) 85%,rgba(13,13,15,.95) 95%,#0d0d0f 100%),linear-gradient(90deg,transparent 0,rgba(17,17,17,.6) 40%,rgba(17,17,17,.6) 60%,transparent 100%),url(https://pub-f048362b915448c9b012a2e03c189024.r2.dev/matrix-bg-dark.svg);background-size:cover;background-position:center center}img[alt=US]{display:none!important}div.relative.w-4.h-4.rounded-full:has(img[alt=US]){display:none!important}.bg-matrix-light{background:linear-gradient(0deg,#fff 0,rgba(240,240,240,.6) 30%,rgba(240,240,240,.6) 70%,#fff 100%),linear-gradient(90deg,transparent 0,rgba(240,240,240,.6) 40%,rgba(240,240,240,.6) 60%,transparent 100%),url(https://pub-f048362b915448c9b012a2e03c189024.r2.dev/matrix-bg-light.svg);background-size:cover;background-position:center center}.bg-gradient-dark{background:linear-gradient(90deg,rgba(17,17,17,0) 0,rgba(17,17,17,.75) 50%,rgba(17,17,17,0) 100%),linear-gradient(180deg,#111 0,rgba(17,17,17,0) 40%,rgba(17,17,17,0) 60%,#111 100%),linear-gradient(270deg,rgba(11,106,249,.25) 0,rgba(29,146,255,.3) 100%)}.bg-gradient-light{background:linear-gradient(180deg,#f0f0f0 0,rgba(255,255,255,0) 49.83%,#f0f0f0 100%),linear-gradient(90deg,#d2e4ff 0,rgba(210,228,255,.5) 25.3%,rgba(255,255,255,0) 49.83%,rgba(210,228,255,.5) 75.47%,#d2e4ff 100%)}"}],"page":{"pagePath":"guides/using-unity-iap-to-sell-nfts","slug":"/guides/using-unity-iap-to-sell-nfts","pageMetadata":{"title":"Using Unity IAP to Sell NFTs","description":"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games","sidebarTitle":"Using Unity IAP to Sell NFTs","href":"/guides/using-unity-iap-to-sell-nfts"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,..._provideComponents(),...props.components},{CodeBlock,Heading,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`Most of your players will not have cryptocurrencies in their wallets. Onboarding funds into cryptocurrencies using traditional means can be a hassle for players and may be too stressful for users who have less technical experience. In any case, minimizing payment friction has always been a very important requirement to an effective monetization strategy. The most frictionless method for making microtransactions for the majority of users on mobile will be with the in-app purchasing method they are already used to: IAP via the iOS App Store and Android Google Play Store. This is especially true if your are using Embedded Wallets and building games where the blockchain is invisible.`}),`\n`,_jsxs(_components.p,{children:[`This guide will explain how we updated `,_jsx(_components.a,{href:`/guides/jelly-forest-unity-guide`,children:`Jelly Forest, our embedded wallet showcase game made with Unity`}),`, to add an IAP that mints you a goofy hot dog hat for your Jelly.`]}),`\n`,_jsx(Heading,{level:`2`,id:`deploy-a-smart-contract`,children:`Deploy a Smart Contract`}),`\n`,_jsxs(_components.p,{children:[`The first step, if you haven’t done so already, is to `,_jsx(_components.a,{href:`/solutions/builder/contracts/deploy-an-item-collection`,children:`deploy a smart contract`}),` that will define and represent the NFTs you aim to sell to your players and display in your game.`]}),`\n`,_jsxs(_components.p,{children:[`Once you’ve deployed your smart contract, don’t forget to `,_jsx(_components.a,{href:`/solutions/builder/gas-sponsorship#gas-sponsorship-in-builder`,children:`add your contract address as a Sponsored Address on the “Gas Sponsoring”`}),` page on the Builder Console! This will make it so that your users have their gas fees automatically sponsored using your compute credits when interacting with your game’s smart contracts.`]}),`\n`,_jsx(Heading,{level:`2`,id:`deploy-a-remote-minter`,children:`Deploy a Remote Minter`}),`\n`,_jsx(_components.p,{children:`By default, ERC1155/721 contracts deployed via the Builder Console require callers to have the appropriate permissions in order to mint a token. While this may seem like a nuisance at first glance, this is a good thing! Without this, anyone could call the mint method on your contract and give themselves infinite in-game items!`}),`\n`,_jsx(_components.p,{children:`You’ll want to deploy a server with a Sequence wallet (or other) and give it minting permissions in the builder.`}),`\n`,_jsx(Heading,{level:`3`,id:`how-we-did-it-in-jelly-forest`,children:`How We Did It in Jelly Forest`}),`\n`,_jsx(_components.p,{children:`In Jelly Forest, all the coins you collect during gameplay are minted as ERC1155 tokens. Here’s how we did it:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Sign up for `,_jsx(_components.a,{href:`https://www.cloudflare.com/`,children:`Cloudflare`}),` - this is how we host the minting service code; please feel free to use any other method you prefer`]}),`\n`,_jsx(_components.li,{children:`Open terminal or other command line`}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`git clone https://github.com/0xsequence-demos/cloudflare-worker-sequence-relayer.git`}),` then `,_jsx(_components.code,{children:`cd cloudflare-worker-sequence-relayer`})]}),`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`git checkout permissionedMinter`})}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`pnpm install`}),` - to install dependancies`]}),`\n`,_jsx(_components.li,{children:`Install wrangler`}),`\n`]}),`\n`,_jsx(CodeBlock,{numberOfLines:`3`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`3`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`pnpm install wrangler --save-dev`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`alias wrangler='./node_modules/.bin/wrangler'`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),`\n`,_jsx(_components.p,{children:`and login`}),`\n`,_jsx(CodeBlock,{numberOfLines:`2`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`2`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`wrangler login`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),`\n`,_jsxs(_components.ol,{start:`7`,children:[`\n`,_jsxs(_components.li,{children:[`Open `,_jsx(_components.code,{children:`wrangler.toml`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Give your server a name by changing the `,_jsx(_components.code,{children:`name`}),` string`]}),`\n`,_jsxs(_components.li,{children:[`Create a new `,_jsx(_components.a,{href:`https://ethereum.stackexchange.com/questions/5828/what-is-an-eoa-account`,children:`EOA wallet`}),` and export the private key. Any EOA wallet is fine. Metamask can be used to easily `,_jsx(_components.a,{href:`https://support.metamask.io/hc/en-us/articles/360015489531-Getting-started-with-MetaMask`,children:`setup a wallet`}),` and `,_jsx(_components.a,{href:`https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key`,children:`export the private key`}),`. Please be very careful with the private key and don’t store it in plain text on your computer or commit it to version control! Set this under `,_jsx(_components.code,{children:`PKEY`})]}),`\n`,_jsxs(_components.li,{children:[`Set the `,_jsx(_components.code,{children:`CONTRACT_ADDRESS`})]}),`\n`,_jsxs(_components.li,{children:[`Set the `,_jsx(_components.code,{children:`PROJECT_ACCESS_KEY`}),` - this is your prod API key from the Builder Console you retrieved earlier when setting up the `,_jsx(_components.code,{children:`SequenceConfig`}),` scriptable object`]}),`\n`,_jsxs(_components.li,{children:[`Set the `,_jsx(_components.code,{children:`CHAIN_HANDLE`}),` - if you’re not sure what this is, you can see the `,_jsx(_components.code,{children:`CHAIN_HANDLE`}),` for each respective network on the Node Gateway page of the Builder Console.`]}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`pnpm dev`}),` - this will deploy the server locally. You should see which localhost it is deployed to in the command line`]}),`\n`,_jsx(_components.li,{children:`Open another command line window`}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`curl http://localhost:8787`}),` - substitute whichever localhost you are given. This will ping the server.`]}),`\n`,_jsx(_components.li,{children:`In the command line where the localhost server is running, you should see that the minter’s wallet address has been logged`}),`\n`,_jsxs(_components.li,{children:[`Grant this address minting permissions in the Builder Console`,`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Find the contract under `,_jsx(_components.code,{children:`Contracts`}),` and click to open it`]}),`\n`,_jsxs(_components.li,{children:[`Click `,_jsx(_components.code,{children:`Write Contract`})]}),`\n`,_jsxs(_components.li,{children:[`Expand `,_jsx(_components.code,{children:`grantRole`})]}),`\n`,_jsxs(_components.li,{children:[`Under `,_jsx(_components.code,{children:`role`}),` enter `,_jsx(_components.code,{children:`0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6`}),` - this is the Keccak-256 hash of `,_jsx(_components.code,{children:`MINTER_ROLE`})]}),`\n`,_jsxs(_components.li,{children:[`Under `,_jsx(_components.code,{children:`account`}),` paste the minter’s wallet address`]}),`\n`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`wrangler deploy`}),` - this will deploy the code to a `,_jsx(_components.a,{href:`https://developers.cloudflare.com/workers/`,children:`Cloudflare Worker`}),` and give you a minting URL`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`Great! Now, when we send a POST request to our server with a body `,_jsx(_components.a,{href:`https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Relayer/MintingRequestProver.cs#L103`,children:`defined in C#`}),`, where the `,_jsx(_components.code,{children:`proof`}),` is generated by the client sending the minting request. In the Unity SDK this is implemented by the `,_jsx(_components.a,{href:`https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Relayer/MintingRequestProver.cs#L27`,children:`MintingRequestProver`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`handle-iap-purchased-tokens-with-the-remote-minter`,children:`Handle IAP Purchased Tokens with the Remote Minter`}),`\n`,_jsx(_components.p,{children:`Above, we’ve deployed a remote minter that is useful for minting tokens that can be earned through in-game actions. Let’s see how we can leverage this server so that we can also mint tokens that are purchasable via IAP.`}),`\n`,_jsxs(_components.p,{children:[`You’ll notice that a receipt can also be included in the payload sent to the remote minter. This is where you’ll include the IAP receive from Google/Apple. `,_jsx(_components.a,{href:`https://docs.unity3d.com/Packages/com.unity.purchasing@4.0/manual/BackendReceiptValidation.html`,children:`Unity recommends`}),` using `,_jsx(_components.a,{href:`https://github.com/voltrue2/in-app-purchase`,children:`Nobuyori Takahashi’s IAP project`}),` to verify IAP receipts received via Unity IAP on the server side.`]}),`\n`,_jsx(_components.p,{children:`Once you’ve validated the receipt on the server side, you can proceed with your minting logic, using the provided sample code above as a reference.`}),`\n`,_jsx(Heading,{level:`2`,id:`unity-implementation`,children:`Unity Implementation`}),`\n`,_jsxs(_components.p,{children:[`On the Unity side, the first step is integrating `,_jsx(_components.a,{href:`https://docs.unity3d.com/Manual/UnityIAP.html`,children:`Unity IAP`}),` into your project.`]}),`\n`,_jsxs(_components.p,{children:[`In your `,_jsx(_components.code,{children:`ProcessPurchase`}),` methods in your `,_jsx(_components.code,{children:`IStoreListener`}),` from the integration process, you’ll want to initiate the minting process. In Jelly Forest, this is done via the `,_jsx(_components.a,{href:`https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/UnityIAP.cs`,children:`UnityIAP`}),` and `,_jsx(_components.a,{href:`https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Items/PremiumItem.cs`,children:`PremiumItem`}),` scripts.`]}),`\n`,_jsxs(_components.p,{children:[`In terms of the payload, you can see in the `,_jsx(_components.code,{children:`PremiumItem`}),` implementation that I am adding a PermissionedMintTransaction to a `,_jsx(_components.code,{children:`TransactionQueuer`}),`.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`csharp`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`csharp`,children:_jsxs(_components.code,{language:`csharp`,numberOfLines:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`public`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` void`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` AddToPremiumTransactionQueue`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#4EC9B0`},children:`PermissionedMintTransaction`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#9CDCFE`},children:` payload`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`string`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#9CDCFE`},children:` iapReceipt`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#4EC9B0`},children:` PremiumIAPMinter`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#9CDCFE`},children:` minter`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` new`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#4EC9B0`},children:` PremiumIAPMinter`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`new`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#4EC9B0`},children:` MintingRequestProver`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`Wallet`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`Chain`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`),`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` _mintEndpoint`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`ContractAddress`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`iapReceipt`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` _permissionedMinterTransactionQueuer`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`Enqueue`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`((`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`payload`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`minter`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`));`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`where `,_jsx(_components.code,{children:`_permissionedMinterTransactionQueuer`}),` is a `,_jsx(_components.code,{children:`PermissionedMinterTransactionQueuer`}),`.`]}),`\n`,_jsx(_components.p,{children:`This will send a payload in this format:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`20`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`20`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`ProofPayload: `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"app\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Made with Sequence Unity SDK App\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"iat\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#82071E`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#F44747`,\"--shiki-dark-font-style\":`inherit`},children:`(uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds()`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// issued at time `})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"exp\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#82071E`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#F44747`,\"--shiki-dark-font-style\":`inherit`},children:`(uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds()`}),_jsx(_components.span,{style:{color:`#82071E`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#F44747`,\"--shiki-dark-font-style\":`inherit`},children:` +`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:` 300`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// expiry time `})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"ogn\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Sequence Unity SDK\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"payload\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"contractAddress\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"0xabc123...\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"tokenId\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"11\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"amount\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`5`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"receipt\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#82071E`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#F44747`,\"--shiki-dark-font-style\":`inherit`},children:`\u003cIAP`}),_jsx(_components.span,{style:{color:`#82071E`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#F44747`,\"--shiki-dark-font-style\":`inherit`},children:` Receipt`}),_jsx(_components.span,{style:{color:`#82071E`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#F44747`,\"--shiki-dark-font-style\":`inherit`},children:` String`}),_jsx(_components.span,{style:{color:`#82071E`,\"--shiki-light-font-style\":`italic`,\"--shiki-dark\":`#F44747`,\"--shiki-dark-font-style\":`inherit`},children:` here>`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`This JSON get stringified and included in the MintingRequestProof:`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"Proof\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:`\\\\\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`app`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:`\\\\\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:`\\\\\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Made with Sequence Unity SDK App`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:`\\\\\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`, `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:`\\\\\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`iat`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:`\\\\\"`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`: ...}\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"SignedProof\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"0x123def...\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// proof signed by the player's embedded wallet`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"SigningAddress\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"0xa1b2c3...\"`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` // the player's embedded wallet address`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`For more information on the transaction queuers, please checkout `,_jsx(_components.a,{href:`/sdk/unity/wallets/embedded-wallet/blockchain-interactions#transaction-queuers`,children:`this doc`}),`.`]}),`\n`,_jsx(Warning,{children:_jsx(_components.p,{children:`Apple and Google allow users the option to chargeback an IAP made by mistake. In this case, your user will still have the token(s) minted to them. While you can handle this via traditional means (e.g. banning players who frequently chargeback purchases), you should be careful not to sell high-value NFTs via this method due to fraudulent chargeback risk.`})})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Using Unity IAP to Sell NFTs","description":"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games","sidebarTitle":"Using Unity IAP to Sell NFTs","href":"/guides/using-unity-iap-to-sell-nfts"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Deploy a Smart Contract","slug":"deploy-a-smart-contract","depth":2,"children":[]},{"title":"Deploy a Remote Minter","slug":"deploy-a-remote-minter","depth":2,"children":[{"title":"How We Did It in Jelly Forest","slug":"how-we-did-it-in-jelly-forest","depth":3,"children":[]},{"title":"Handle IAP Purchased Tokens with the Remote Minter","slug":"handle-iap-purchased-tokens-with-the-remote-minter","depth":3,"children":[]}]},{"title":"Unity Implementation","slug":"unity-implementation","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/_mintlify/custom/sequence-0fb8d9e6/5928f07079c865a1/scripts/update_security_schemas.js","/_mintlify/custom/sequence-0fb8d9e6/b206a90082858d4a/snippets/databeat-tracker.js","/_mintlify/custom/sequence-0fb8d9e6/0281ffbe15eb5584/snippets/dist/databeat-tracker.umd.js"],"subdomain":"sequence-0fb8d9e6","siteName":"Sequence Docs","title":"Using Unity IAP to Sell NFTs - Sequence Docs","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{"en":{"href":"/guides/using-unity-iap-to-sell-nfts","matchLevel":0},"ja":{"href":"/ja/guides/using-unity-iap-to-sell-nfts","matchLevel":1},"es":{"href":"/es/guides/using-unity-iap-to-sell-nfts","matchLevel":1}}},"lastModified":"2025-12-12T14:17:57.270Z","originalFileLocation":"guides/using-unity-iap-to-sell-nfts.mdx","locale":"en"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games\">\u003cmeta data-mint-head name=\"application-name\" content=\"Sequence Docs\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Using Unity IAP to Sell NFTs - Sequence Docs\">\u003cmeta data-mint-head property=\"og:description\" content=\"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Sequence Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://sequence-0fb8d9e6.mintlify.app/_mintlify/api/og/v2?division=Game+Developers\u0026amp;title=Using+Unity+IAP+to+Sell+NFTs\u0026amp;description=How+we+added+NFTs+purchaseable+via+IAP+%28in-app+purchase%29+on+the+iOS+App+Store+and+Google+Play+Store+to+Jelly+Forest+and+how+you+can+do+something+similar+in+your\u0026amp;theme=3cfa20f380481c9c1062693e\u0026amp;signature=320e321d10557f260af1a715af9c50b6ca80a4595790fa9d2a9a4b1b0985d076\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Using Unity IAP to Sell NFTs - Sequence Docs\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://sequence-0fb8d9e6.mintlify.app/_mintlify/api/og/v2?division=Game+Developers\u0026amp;title=Using+Unity+IAP+to+Sell+NFTs\u0026amp;description=How+we+added+NFTs+purchaseable+via+IAP+%28in-app+purchase%29+on+the+iOS+App+Store+and+Google+Play+Store+to+Jelly+Forest+and+how+you+can+do+something+similar+in+your\u0026amp;theme=3cfa20f380481c9c1062693e\u0026amp;signature=320e321d10557f260af1a715af9c50b6ca80a4595790fa9d2a9a4b1b0985d076\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/sequence-0fb8d9e6/WZ0nVbE4CcPhWh5d/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Sequence Docs\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#B1A9FF\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/guides/using-unity-iap-to-sell-nfts.md\">\u003clink data-mint-head rel=\"alternate\" hreflang=\"en\" href=\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts\">\u003clink data-mint-head rel=\"alternate\" hreflang=\"ja\" href=\"https://docs.sequence.xyz/ja/guides/using-unity-iap-to-sell-nfts\">\u003clink data-mint-head rel=\"alternate\" hreflang=\"es\" href=\"https://docs.sequence.xyz/es/guides/using-unity-iap-to-sell-nfts\">\u003clink data-mint-head rel=\"alternate\" hreflang=\"x-default\" href=\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.sequence.xyz/#organization\",\"name\":\"Sequence Docs\",\"url\":\"https://docs.sequence.xyz\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/sequence-0fb8d9e6/9rKTa07iWJtIbdn7/logo/sequence-composite-light.svg?fit=max\u0026auto=format\u0026n=9rKTa07iWJtIbdn7\u0026q=85\u0026s=18750aafea1146db72d2e3b695536390\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.sequence.xyz#website\",\"name\":\"Sequence Docs\",\"url\":\"https://docs.sequence.xyz\",\"publisher\":{\"@id\":\"https://docs.sequence.xyz/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts#webpage\",\"url\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts\",\"name\":\"Using Unity IAP to Sell NFTs\",\"description\":\"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games\",\"dateModified\":\"2025-12-12T14:17:57.270Z\",\"isPartOf\":{\"@id\":\"https://docs.sequence.xyz#website\"},\"breadcrumb\":{\"@id\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Guides\",\"item\":\"https://docs.sequence.xyz/guides/guide-overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Game Developers\",\"item\":\"https://docs.sequence.xyz/guides/webgl-guide\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Using Unity IAP to Sell NFTs\",\"item\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts#article\",\"headline\":\"Using Unity IAP to Sell NFTs\",\"name\":\"Using Unity IAP to Sell NFTs\",\"description\":\"How we added NFTs purchaseable via IAP (in-app purchase) on the iOS App Store and Google Play Store to Jelly Forest and how you can do something similar in your own games\",\"url\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts\",\"mainEntityOfPage\":{\"@id\":\"https://docs.sequence.xyz/guides/using-unity-iap-to-sell-nfts#webpage\"},\"dateModified\":\"2025-12-12T14:17:57.270Z\",\"publisher\":{\"@id\":\"https://docs.sequence.xyz/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.sequence.xyz#website\"}}]}\u003c/script>","siteName":"Sequence Docs","nav":{"global":{"anchors":[{"anchor":"Supported Chains","icon":"heart-pulse","href":"https://status.sequence.info/"},{"anchor":"Changelog","icon":"map","href":"https://0xsequence.featurebase.app/changelog"}]},"languages":[{"language":"en","tabs":[{"tab":"Home","pages":[{"title":"Home","href":"/home"}]},{"tab":"Solutions","pages":[{"title":"Solutions","href":"/solutions/overview"}]},{"tab":"SDKs","pages":[{"title":"SDKs","href":"/sdk/overview"}]},{"tab":"APIs","pages":[{"title":"APIs","href":"/api-references/overview"}]},{"tab":"Resources","groups":[{"group":"Guides","pages":[{"title":"Guides","mode":"wide","sidebarTitle":"Overview","href":"/guides/guide-overview"},{"group":"Blockchain Integrations","pages":[{"title":"Mint Collectibles Using a Gasless Serverless Transactions API","sidebarTitle":"Build a Collectibles Minting Service","href":"/guides/mint-collectibles-serverless"},{"title":"Collection Metadata Management","sidebarTitle":"Manage Collection Metadata","href":"/guides/metadata-guide"},{"title":"Treasure Chests with AI Minting","sidebarTitle":"Build a Treasure Chest with AI Minting","href":"/guides/treasure-chest-guide"},{"title":"Verified Typed Data \u0026 Validated Signature Messages On-chain","sidebarTitle":"Build On-chain Typed Data \u0026 Signature Validation","href":"/guides/typed-on-chain-signatures"},{"title":"Building a Relaying Transaction Server","sidebarTitle":"Build a Backend Transaction Service","href":"/guides/building-relaying-server"},{"title":"Sequence Analytics API in Dune","sidebarTitle":"Leverage Sequence Analytics API in Dune","href":"/guides/analytics-guide"},{"sidebarTitle":"Build an Embedded Wallet Linking Service","url":"/solutions/wallets/developers/embedded-wallet/wallet-linking","title":null,"href":"/guides/build-embedding-wallet"},{"title":"Connect Privy with Sequence","href":"/guides/use-with-privy"},{"title":"Build a Yield Flow with Embedded Wallet + Trails","sidebarTitle":"Embedded Wallet Yield with Trails","href":"/guides/embedded-wallet-yield-with-trails"}]},{"group":"Marketplaces \u0026 Shops","pages":[{"title":"Build a Custom Marketplace","sidebarTitle":"Build a Custom Marketplace","href":"/guides/custom-marketplace"},{"title":"Sell your Game Items via a Web Shop","sidebarTitle":"Sell your ERC-1155 Game Items via Web Shop","href":"/guides/primary-sales"},{"title":"Create NFT Drop Sales with Sequence","sidebarTitle":"Create NFT Drop Sales","href":"/guides/primary-drop-sales-erc721"}]},{"group":"Game Developers","pages":[{"title":"Aviator Web3 Game with WebGL","sidebarTitle":"Build a Game with WebGL","href":"/guides/webgl-guide"},{"title":"Intro to Jelly Forest - Unity Game Guide","sidebarTitle":"Build a Unity Game","href":"/guides/jelly-forest-unity-guide"},{"title":"Building Transaction Heavy Games with Unity","sidebarTitle":"Building Transaction Heavy Games with Unity","href":"/guides/building-transaction-heavy-games-with-unity"},{"title":"Building and Integrating Web3 Game Features with Sequence's Unreal Engine SDK","description":"Integrate the Sequence Wallet, fetch your players assets, sign messages, send transactions and more using Sequence's Unreal SDK.","sidebarTitle":"Build an Unreal Engine Web 3 Game","href":"/guides/unreal-ew-guide"},{"title":"Using Unity IAP to Sell NFTs","sidebarTitle":"Using Unity IAP to Sell NFTs","href":"/guides/using-unity-iap-to-sell-nfts"},{"title":"How to do Primary Sales for On-Chain Items in Unity","description":"This guide covers the creation of a Primary Sale with Sequence's Unity SDK.","sidebarTitle":"How to do Primary Sales for On-Chain Items in Unity","href":"/guides/unity-primary-sales"},{"title":"Build a Telegram Mini-Game in Unity","sidebarTitle":"Build a Telegram Mini-Game in Unity","href":"/guides/unity-webgl-telegram"},{"title":"Integrating Web SDK with Telegram Mini-apps","sidebarTitle":"Build a Telegram Mini-App with Sequence","href":"/guides/telegram-integration"},{"title":"How to Configure a ERC1155Pack Contract in Sequence Builder","sidebarTitle":"Using a ERC1155Pack Contract","href":"/guides/packs"}]}]},{"group":"Boilerplates","pages":[{"title":"Templates","mode":"wide","sidebarTitle":"Overview","href":"/guides/template-overview"}]}]},{"tab":"Support","pages":[{"title":"Support","href":"/support"}]}]},{"language":"ja","pages":[{"title":"ja","href":"/ja/guides/using-unity-iap-to-sell-nfts"}]},{"language":"es","pages":[{"title":"es","href":"/es/guides/using-unity-iap-to-sell-nfts"}]}]},"basePath":"","title":"Using Unity IAP to Sell NFTs - Sequence Docs","buildId":"dpl_345ReqzYaAjzS9QpeJemsKdb7KDj","deploymentId":"dpl_345ReqzYaAjzS9QpeJemsKdb7KDj","dynamics":[],"chunks":[]}