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:
- Sign up for Cloudflare - this is how we host the minting service code; please feel free to use any other method you prefer
- Open terminal or other command line
git clone https://github.com/0xsequence-demos/cloudflare-worker-sequence-relayer.git
thencd cloudflare-worker-sequence-relayer
git checkout permissionedMinter
pnpm install
- to install dependancies- Install wrangler
pnpm install wrangler --save-dev
alias wrangler='./node_modules/.bin/wrangler'
and login
wrangler login
- Open
wrangler.toml
- 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 theSequenceConfig
scriptable object - Set the
CHAIN_HANDLE
- if you're not sure what this is, you can see theCHAIN_HANDLE
for each respective network on the Node Gateway page of the Builder Console.
- Give your server a name by changing the
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
enter0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6
- this is the Keccak-256 hash ofMINTER_ROLE
- Under
account
paste the minter's wallet address
- Find the contract under
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.