Skip to main content

Backend Configuration


💡Primary Sales Widget Enablement
The Primary Sales Widget is currently in its closed Beta release phase and we anticipate making it available publicly soon.

To gain access to the Primary Sales Widget, please complete the following form and our team will be in contact.

1. Set up your project in the Immutable Hub and create API keys

Copy the environment Id created since it will be used later on, it appears in the URL near the end (see image below).

2. Create a Signing key (KMS)

A Signing key needs to be created to sign the transactions the Multicaller will execute, a KMS key mimics an HSM and the actual keys cannot be retrieved by Immutable or other parties.

Call the endpoints documented below with a POST method, passing the API key obtained from the step above in an http header with the name x-immutable-api-key.

  • Testnet: https://api.sandbox.immutable.com/v1/primary-sales/key
  • Mainnet: https://api.immutable.com/v1/primary-sales/key

This is an example call for Testnet.

curl --location --request POST 'https://api.sandbox.immutable.com/v1/primary-sales/key' \
--header 'x-immutable-api-key: <API KEY HERE>'

Wait approximately 1 minute after the previous API call and then make this second call to get the KMS address.

curl --location --request GET 'https://api.sandbox.immutable.com/v1/primary-sales/key' \
--header 'x-immutable-api-key: <API KEY HERE>'

Note down this address, it will be used in a later step.

3. Set up your ERC721 collection

The easiest way to deploy your ERC721 collection is using the Immutable Hub, a guide on how to do it is available here

Once the ERC721 collection is deployed, make sure you copy the collection contract address.

4. The Guarded Multi-Caller

The guarded multicaller is what allows the game studio to perform multiple operations across different smart contracts such as transfer of ERC20 tokens and minting of ERC721/ERC1155 tokens in the same transaction, this needs to be deployed and owned by the game studio, follow these steps to deploy it.

  • 4.1.1 Clone the repo https://github.com/immutable/multicaller-contracts and install all the dependencies: Node, npm, yarn.

  • 4.1.2 Run command npx hardhat compile to create the necessary artifacts.

  • 4.1.3 Copy the .env.example file with command cp .env.example .env once copied, add the relevant values you need.

Make sure .env contains:

PRIVATE_KEY=<private_key_used_to_deploy_contract>
IMMUTABLE_ZKEVM_TESTNET_URL=https://rpc.testnet.immutable.com
  • 4.1.4 Run: yarn interact deploy --contractName=<contractName> --contractVersion=<contractVersion>

Make sure you remember the values used in contractName , contractVersion and the contract address after deployment, those will be required on a later step.

4.2 Multicaller Permissions to KMS

Permission to allow the address of the KMS key to use and execute in the multicaller contract.

Run: yarn interact grantMulticallSignerRole --contractAddress=<contractAddress> --signerAddress=<signerAddress>

  • contractAddress: Pass the contract address where the multicaller was deployed (Step 4.1.3).
  • signerAddress: Pass the address of the KMS key created in Step 2.

4.3 Multicaller Permissions to call Mint in the ERC721 collection

Permission to allow the multicaller to mint

yarn interact permitFunction --contractAddress=<contractAddress> --targetAddress=<targetAddress> --functionSignature=<functionSignature> --permitted=true

  • contractAddress: Pass the contract address where the multicaller was deployed
  • targetAddress: The contract address of the erc721 collection contract.
  • functionSignature: The function signature of the mint function selected, these are the function signatures we support:
    • mint(address,uint256) -> does NOT offer gas optimisations for multiple NFTs.
    • safeMint(address,uint256) -> does NOT offer gas optimisations for multiple NFTs.
    • mintBatch((address,uint256[])[]) -> offers gas optimisations for multiple NFTs.
    • safeMintBatch((address,uint256[])[]) -> offers gas optimisations for multiple NFTs.

Note: Methods with safe prefix perform validations to make sure the recipient address is prepared to receive the NFT.

4.4 Multicaller Permissions to call transfer of ERC20 tokens

yarn interact permitFunction --contractAddress=<contractAddress> --targetAddress=<targetAddress> --functionSignature=<functionSignature> --permitted=true

  • contractAddress: Pass the contract address where the multicaller was deployed
  • targetAddress: The contract address of the erc20 token.
  • functionSignature: The function signature of the transfer function (transferFrom(address,address,uint256))
📕Repeat
If you are using multiple ERC20 tokens, make sure you call it multiple times with the different function signatures needed.

4.5 ERC721 Permissions to Mint (Minter role)

The multicaller contract needs permissions to mint in the ERC721 collection (Minter role).

Run: yarn interact grantMinterRole --contractAddress=<contractAddress> --collectionAddress=<collectionAddress>

  • contractAddress: Pass the contract address where the multicaller was deployed.
  • collectionAddress: Pass the address of the ERC721 collection contract.

4.6 Verifying your Multicaller contract (Optional)

Verifying your multicaller contract helps debugging potential errors that may arise, it's not mandatory but it's recommended.

Run: npx hardhat verify --network <network> --contract contracts/GuardedMulticaller.sol:GuardedMulticaller <contractAddress> "<deployerAddress>" "<contractName>" "<contractVersion>"

  • network: Either immutableTestnet or immutableMainnet depending on the chain you want to verify on.
  • contractAddress: Pass the contract address where the multicaller was deployed.
  • deployerAddress: Pass the address of the wallet deploying the contract, it's the wallet for the key used in the PRIVATE_KEY env var.
  • contractName: Pass the contract name you defined when the contract was deployed.
  • contractVersion: Pass the contract version you defined when the contract was deployed.

Once the contract is verified, a green check mark (✅) appears next to the Contracts tab when inquiring the contract address on our Immutable explorer.

5. Setup your Game backend for stock management.

Most games have an inventory system of items available for sale, you can use your existing system with the Primary Sales widget (Bring Your Own) Or we offer an alternative to connect a store in WooCommerce (Wordpress Plugin) with the Primary Sales Widget.

6. Connecting your stock management system with the Primary Sales Widget

Once you have decided and setup your game backend for stock management, you are ready to make all the configurations in order for the Primary Sales Widget to work.

Let's review all configuration fields required to configure the Primary Sales widget:

PropertyDescription
payoutsThe list of wallets that will receive the revenue of the Primary Sale, if you only need one, add one value to the array with a percentage of 100, values needed are:
- The wallet address that will receive the payout percentage
- The percentage
expiryNumber of seconds configured for the orders to expire, signed orders need to be executed on-chain before this expiry. This value should encompass the time it takes for a user to review an order until it’s executed in the chain.
contract_idThe contract ID given by Immutable, this is used by Transak to know which game is using their widget, if you are not using Transak, set value to None.
currenciesArray of ERC20 currencies supported by the partner game to receive payouts. The information needed to configure a currency is:
- The contact address of the ERC20 contract
- The number of decimals
- The Symbol
- Base currency (true/false)
- Exchange ID (how the currency appears in coingecko, this is used to fetch conversion rates)
mint_typeThe type of mint method used to deliver the NFTs to the final user, the available methods are:
- mint: Standard method used to mint a single NFT, does not offer gas optimisations for multiple items or validation of the recipient wallet.
- safeMint: Standard method used to mint a single NFT but incorporates a validation to only allow the minting to happen if the recipient is prepared to receive an NFT.
- mintBatch: Gas optimised method to mint multiple NFTs to a recipient, it can consume ~40% less gas than standard mint.
- safeMintBatch: Gas optimised method to mint multiple NFTs to a recipient, it also incorporates a validation to only allow the minting to happen if the recipient is prepared to receive an NFT.
multicall_contract_address
multicall_contract_name
multicall_contract_version
Multicaller contract address, name and version, used in the task 4. The Guarded Multi-Caller. Name and version are used mostly as part of security checks.
quote_url
quote_api_key
The URL and API key used to get a quote for draft orders. These can be part of your own stock management system or WooCommerce depending on what was configured in the previous step.
authorization_url
authorization_api_key
The URL and API key used to authorize the sales. These can be part of your own stock management system or WooCommerce depending on what was configured in the previous step.
confirmation_url
confirmation_api_key
The URL and API key used to confirm the orders once executed on-chain. These can be part of your own stock management system or WooCommerce depending on what was configured in the previous step.
expiration_url
expiration_api_key
The URL and API key used to inform about expired orders. These can be part of your own stock management system or WooCommerce depending on what was configured in the previous step.

6.1 Supported Currencies

It is required to set one or more currencies in order to receive payouts. This is done in the configuration API endpoint by setting currencies as an array of ERC20 token details:

  • erc20_address <string>: The address of the ERC20 contract in zkEVM
  • decimals <number> The number of decimals of the ERC20
  • name <string>: Currency name
  • exchange_id <string>: "The ID of the ERC20 token as it appears in the currency conversion service (ie: Coingecko)"
  • base <boolean>: true if this is the base currency, false otherwise.
🪙Base currency
Base currency is the preferred token for payouts. Must ensure there is one base currency in the configuration.
📘Note
The primary sales widget prioritises payments be made in the base currency, before offering the option to pay with other currencies.

Wallets with insufficient funds in the base currency will be prompted to swap their tokens.

Setting up a configuration with two currencies in testnet would look like this:

{
"currencies": [
{
"base": true,
"decimals": 6,
"erc20_address": "0x3b2d8a1931736fc321c24864bceee981b11c3c57",
"exchange_id": "usd-coin",
"name": "USDC"
},
{
"base": true,
"decimals": 18,
"erc20_address": "0xe9e96d1aad82562b7588f03f49ad34186f996478",
"exchange_id": "ethereum",
"name": "ETH"
}
]
}
📗Base currency
In this example the configuration will default to payments in USDC, while also accepting payments in ETH.

Wallets with insufficient USDC or ETH, will be prompted to swap their tokens to USDC (if their tokens have liquidity pairs with USDC on QuickSwap).

6.2 Configuration API endpoint

Finally, must call the configuration API endpoint to set up the Primary Sales Widget with the configuration values from the previous steps.

Here is an example of a call to the config endpoint to create and update a the Primary Sales Widget config:

curl --location --request PUT 'https://api.sandbox.immutable.com/v1/primary-sales/config' \
--header 'x-immutable-api-key: <API KEY HERE>' \
--header 'Content-Type: application/json' \
--data-raw '{
"authorization_api_key": "<authorization_api_key>",
"authorization_url": "<authorization_url>",
"confirmation_api_key": "<confirmation_api_key>",
"confirmation_url": "<confirmation_url>",
"currencies": [
{
"erc20_address": "<erc20_address>",
"decimals": <decimals>,
"name": "<name>",
"base": <base>,
"exchange_id": "<exchange_id>"
}
],
"expiration_api_key": "<expiration_api_key>",
"expiration_url": "<expiration_url>",
"quote_api_key": "<quote_api_key>",
"quote_url": "<quote_url>",
"expiry": <expiry>,
"contract_id": "<contract_id>",
"mint_type": "<mint_type>",
"multicall_contract_address": "<multicall_contract_address>",
"multicall_contract_name": "<multicall_contract_name>",
"multicall_contract_version": "<multicall_contract_version>",
"payouts": [
{
"wallet_address": "<payout_address>",
"percentage": <payout_percentage>
}
]
}'
👀Note
Don't forget to replace the placeholders with the actual values.