Skip to main content

Setting royalties

By the end of this guide, you will know the process for setting royalty fees and how to view royalties for a collection. This page also provides examples of using Immutable's preset fee splitter contract to allocate royalty fees to multiple recipients


Single Royalty Recipients: Immutable's Preset ERC721 Contract

Immutable's preset ERC721 contract is designed to allocate royalty payments to a single recipient for each collection. Consequently, all assets minted under this collection will direct their royalty proceeds to the designated payee account at the specified percentage of the transaction price.

To configure the royalties payee address and percentage for your collection, refer to the royalty setup instructions in the deploy preset contract section of our "Create in-game assets" guide.

View a collection's royalty information

To view the royalty fee instructions on an existing collection follow these steps. Price has to be specified in the request as royalty may change based on price.

  1. Go to the root directory of your project
  2. Create a scripts directory
  3. Create get-royalties.ts file
  4. Insert the following code with the below variables:
  • CONTRACT_ADDRESS (The address of the collection)
  • TOKEN_ID (The ID of the NFT)
  • SALE_PRICE (The proposed sales price for the NFT)
  • COLLECTION_SYMBOL (The symbol of your collection - typically 2-3 characters long)
get-royalties.ts
import { getContract, http, createWalletClient, defineChain } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { ImmutableERC721Abi } from '@imtbl/contracts';

const PRIVATE_KEY = 'YOUR_PRIVATE_KEY'; // should be read from environment variable
const CONTRACT_ADDRESS = '0xYOUR_CONTRACT_ADDRESS'; // should be of type `0x${string}`
const TOKEN_ID = BigInt(1);
const SALE_PRICE = BigInt(1);

const immutableTestnet = defineChain({
id: 13473,
name: 'imtbl-zkevm-testnet',
nativeCurrency: { name: 'IMX', symbol: 'IMX', decimals: 18 },
rpcUrls: {
default: {
http: ['https://rpc.testnet.immutable.com'],
},
},
});

const walletClient = createWalletClient({
chain: immutableTestnet,
transport: http(),
account: privateKeyToAccount(`0x${PRIVATE_KEY}`),
});

const contract = getContract({
address: CONTRACT_ADDRESS,
abi: ImmutableERC721Abi,
client: walletClient,
});

const getRoyalty = async (): Promise<[string, BigInt]> => {
const [receiver, royaltyAmount] = await contract.read.royaltyInfo([
TOKEN_ID,
SALE_PRICE,
]);

return [receiver, royaltyAmount];
};

getRoyalty();
  1. Run the script:
./node_modules/.bin/ts-node get-royalties.ts

Update royalties

This feature is currently in development and will be available soon.

Multiple Royalty Recipients: Immutable's Preset Fee Splitting Contract

Immutable's fee splitting contract is crafted to manage the collection and distribution of ERC20 tokens for royalty fees in Web3 gaming. While Immutable's zkEVM ERC-721 assets are designed to support a single royalty recipient, the fee splitting contract accommodates more complex arrangements by enabling multiple recipients.

This contract is particularly useful in games with intricate royalty structures. It allows for each collection to set a default royalty address, typically the fee splitting contract's address. All NFTs minted from these collections will then automatically direct their royalties to this address.

For collections requiring varied royalty distributions among individual assets, the royalty address for each asset can be customized after minting. This ensures that royalty payments are allocated precisely as needed for each specific asset within a collection.

Fee Splitting Contract Splitting Fees

The diagram above highlights the need for multiple fee splitting contracts in scenarios such as:

  • Different Recipients: A unique fee splitter contract is needed for each distinct combination of royalty recipients. For example, if NFT X allocates royalties to wallets A and B, and NFT Y allocates royalties to wallets A and C, this necessitates two different fee splitter contracts.
  • Varied Distribution Percentages: A unique fee splitter contract are necessary for different percentage allocations to the same recipients. For example, if one asset requires a 50/50 royalty split and another a 70/30 split between the same recipients' wallets, this necessitates two different fee splitter contracts.
tip

Immutable’s fee splitting contract deployment is exclusive to clients in partnership with Immutable. If you wish to deploy Immutable's, or your own, fee splitting smart contract on zkEVM, please contact your Immutable account manager.

How to use Immutable's preset fee splitter contract for royalties

Creating a fee splitting contract

Immutable's preset fee splitting contract must be updated by the content creator (i.e. game studio) to specify the required fee allocation for the collection.

Each recipient's wallet can be specified in the contract as well as the % allocation that recipient is expected to receive.

See the below example

// Example script here

Setting a Fee Splitter Contract as the Default Royalty Recipient for a Collection

When deploying a collection using Immutable's standard ERC721 contract, it is possible to assign a royalty recipient at the outset.

When deploying a new collection, the address of a pre-deployed fee splitter contract should be designated as the recipient for all royalty fees. Once the royalties are collected by the fee splitter contract, they will be divided amongst the recipients the the fees are released via the releaseAll() function.

Deploying a collection with via Immutable's Hub (default royalty splitting allocation)

If you are deploying your collection with Immutable's hub, please read the following tutorial for a step by step guide.

Enter the contract address of your royalty fee splitting contract here, as well as the percentage of the transaction price that should be allocated for all royalties.

Adding fee splitter address to hub deployed contract
Customizing Royalty Allocations for Specific Assets

For instances where individual assets in a collection necessitate distinct royalty allocations diverging from the default setting, game studios need to specify these variations post-minting.

The process involves the following steps:

  1. Deploy a New Royalty Splitting Contract: Initiate and deploy a separate royalty splitting contract tailored to the unique royalty requirements of the group of assets. Ensure to record the contract address once deployed.

  2. Assign NFTs to the NeW Royalty Splitting Contract: Develop a script to assign the new royalty structure dictated by the new fee splitter contract. This script will be used to reassign the royalty fee allocation to the already minted NFTs, replacing the default collection royalty fee splitter contract address with the new contract address from step 1.

An example of such a script is below:

// Example script here

By following these steps, game studios can effectively manage and tailor royalty distributions for individual assets within the same collection.

Releasing Collected Fees to Recipients

To distribute the ERC20 tokens accumulated in a fee splitter smart contract, use the script provided to call the releaseAll() function. It is important to remember that the native token (IMX for zkEVM) is automatically released with this function and does not need explicit mention.

This distribution can be scheduled through a periodic script or initiated by a specific user. Notably, executing the releaseAll() function only affects the release of funds and does not alter the pre-established allocation. Therefore, broad access to this function does not pose a security risk, as the caller cannot modify the recipients or their shares.

note

The party that triggers the releaseAll() function is responsible for covering the gas fees associated with the transaction. This means if an individual content creator initiates this function, they will incur the gas costs not just for their own royalty distribution but also for all other recipients included in the transaction.

Granting access to the releaseAll() function

The grantReleaseFundsRole() function grants access to the releaseAll() function.

This can be given to all royalty recipients, or only an admin user, depending on the game studio's requirements.

Below is an example of granting access using the grantReleaseFundsRole() function.

// Example script here

Changing the Fee Allocation of a Previously Deployed Fee Splitter Contract

Over time, the royalty distribution associated with an asset may need modification. This can be achieved through the following different methods:

  • Amending the Collection's Default Royalty Recipient: Implement a new fee splitter contract with updated allocations and change the collection's default royalty configuration to be directed to this new contract. It's important to note that assets assigned a non-default fee splitting configuration will remain unaffected by this change and must be individually redirected to the new contract.
  • Amending a Fee Splitter Contract: The admin user can modify an existing fee splitter contract allocation. This modification could involve updating the number of recipients or adjusting the allocation percentages for each recipient.

Admin users should exclusively handle these changes, as opposed to the more accessible releaseAll() function.

Amending the Collection's Default Royalty Recipient

Below is an example script to change the default royalty recipient of a collection to a new fee splitting contract. Alternatively, an individual wallet can be used if the collection no longer requires multiple royalty recipients.

caution

Ensure that all fees accumulated in the old fee splitting contract are released to the respective recipients before making the change. This guarantees that royalties from past transactions are duly received.

// Example script here

Amending the Fee Splitter Contract

The overridePayees() function can be used to adjust the fee splitting allocation of a previously deployed smart contract. It can only be run by the admin user.

The script below illustrates how to alter the royalty allocation in an existing fee splitting contract using the overridePayees() function.

caution

After overriding a contract, all fees in the old fee splitting contract will be distributed according to the new allocation configuration. The contract does not retain memory of previous allocations for funds collected before the adjustment. Hence, it is advisable to execute the releaseAll() function before modifying the contract's allocation settings.

// Example script here