Sign Up
Skip to content

Using Unity IAP to Sell NFTs

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.

Deploy a Smart Contract

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.

Deploy a Remote Minter

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.

How We Did It in Jelly Forest

In Jelly Forest, all the coins you collect during gameplay are minted as ERC1155 tokens. Here's how we did it:

  1. Sign up for Cloudflare - this is how we host the minting service code; please feel free to use any other method you prefer
  2. Open terminal or other command line
  3. git clone https://github.com/0xsequence-demos/cloudflare-worker-sequence-relayer.git then cd cloudflare-worker-sequence-relayer
  4. git checkout permissionedMinter
  5. pnpm install - to install dependancies
  6. Install wrangler
pnpm install wrangler --save-dev
alias wrangler='./node_modules/.bin/wrangler'

and login

wrangler login
  1. Open wrangler.toml
    1. Give your server a name by changing the name string
    2. 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
    3. Set the CONTRACT_ADDRESS
    4. 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
    5. 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.
  2. pnpm dev - this will deploy the server locally. You should see which localhost it is deployed to in the command line
  3. Open another command line window
  4. curl http://localhost:8787 - substitute whichever localhost you are given. This will ping the server.
  5. In the command line where the localhost server is running, you should see that the minter's wallet address has been logged
  6. Grant this address minting permissions in the Builder Console
    1. Find the contract under Contracts and click to open it
    2. Click Write Contract
    3. Expand grantRole
    4. Under role enter 0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6 - this is the Keccak-256 hash of MINTER_ROLE
    5. Under account paste the minter's wallet address
  7. 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.

Unity Implementation

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.