The Orderbook supports multiple fee types—protocol fees, royalties, and marketplace fees—that are automatically distributed when trades execute.
Fee Types
| Fee | Recipient | Set By |
|---|
| Protocol Fee | Immutable | Fixed by protocol |
| Royalty Fee | NFT Creator | Set on NFT contract |
| Maker Fee | Listing marketplace | Order creator |
| Taker Fee | Filling marketplace | Order filler |
How Fees Work
When a trade executes, fees are deducted from the payment. All fees are paid by the buyer, and the seller receives the sale price minus the deducted fees.
Fee Units: Fees are specified in the smallest unit of the currency (wei for native tokens, smallest decimal unit for ERC-20s). For example:
- 1 IMX = 1,000,000,000,000,000,000 wei (18 decimals)
- Fee of “10000000000000000” = 0.01 IMX
Fees are notional amounts, not percentages. If an order is partially filled, fees are automatically pro-rated by the orderbook.
Protocol Fee
The protocol fee is a small percentage that supports the Immutable ecosystem.
| Network | Protocol Fee |
|---|
| Mainnet | 2% |
| Testnet | 2% |
The protocol fee is non-negotiable and applies to all trades on the Orderbook.
Royalties
Royalties ensure creators earn from secondary sales. They’re set on the NFT contract and enforced by the Orderbook.
Setting Royalties
Royalties are configured when deploying your NFT contract. For complete setup instructions, see Deploying Contracts with Royalties and Royalty Configuration.
// In your ERC-721 contract
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount)
{
// 5% royalty to the creator
return (creatorAddress, (salePrice * 500) / 10000);
}
Typical Royalty Rates
| Game Type | Typical Royalty |
|---|
| Gaming items | 2-5% |
| Collectibles | 5-10% |
| Art | 5-15% |
Royalty Enforcement:
- Royalties must be implemented via the Operator Allowlist to be enforced
- The orderbook automatically queries royalty information using the ERC-2981 interface when creating orders
- Royalty amounts are re-validated during order fulfillment
- zkEVM limitation: Royalties can only be paid to a single wallet address. If you need to split royalties among multiple wallets, contact your Immutable account manager about fee splitter contracts.
Marketplace Fees
Marketplaces can add their own fees on top of protocol fees and royalties.
Maker Fees
Set by the marketplace where the order is created:
const { result } = await orderbookClient.createListing({
orderComponents: prepareListing.orderComponents,
orderHash: prepareListing.orderHash,
orderSignature: signature,
makerFees: [
{
recipientAddress: MARKETPLACE_FEE_WALLET,
amount: '10000000000000000', // 0.01 IMX flat fee
},
],
});
Taker Fees
Set by the marketplace where the order is filled:
const { actions } = await orderbookClient.fulfillOrder(
orderId,
buyerAddress,
[
{
recipientAddress: MARKETPLACE_FEE_WALLET,
amount: '10000000000000000', // 0.01 IMX flat fee
},
]
);
Maker vs Taker Fee Flexibility
| Fee Type | When Set | Can Change? |
|---|
| Maker Fee | At listing creation | ❌ Immutable - To change, must cancel and recreate listing |
| Taker Fee | At order fulfillment | ✅ Flexible - Can be different for each fulfillment |
Maker = Liquidity provider (creates order, adds to orderbook)
Taker = Liquidity consumer (fills order, removes from orderbook)Marketplaces typically charge makers lower fees to incentivize listing creation.
ERC-1155 Partial Fill Fee Rules
For ERC-1155 tokens that support partial fills, taker fees must reflect the full order amount, not the partial fill amount:
// ❌ WRONG: Scaling fee for partial fill
const listing = { sell: { amount: '10' }, buy: { amount: '1000000000000000000' } }; // 10 items at 0.1 IMX each
const amountToFill = '5'; // Buying 5 of 10
const takerFee = '5000000000000000'; // 0.005 IMX (scaled) - INCORRECT
// ✅ CORRECT: Fee for full order amount
const takerFee = '10000000000000000'; // 0.01 IMX (1% of full order) - CORRECT
// The orderbook will automatically pro-rate this to 0.005 IMX for the partial fill
For ERC-1155 orders, always provide taker fees for the complete order, even when partially filling. The orderbook automatically pro-rates the fee based on the quantity executed. Setting a scaled-down fee will result in incorrect marketplace compensation.
Fee Validation and Expiration
When fulfilling an order, the orderbook provides up-to-date fee information and validates all fees server-side:
const { actions, order, expiration } = await orderbookClient.fulfillOrder(
orderId,
buyerAddress,
[] // taker fees array
);
console.log({
order: order, // Order with CURRENT fees (may differ from listing query)
expiration: expiration // Transaction must be submitted within 3 minutes
});
// User must complete transaction before expiration
// After 3 minutes, request new fulfillment data
Important Fee Timing Rules:
- Fee changes: Fees at fulfillment time may differ from when the order was queried (e.g., promotional periods with reduced protocol fees)
- 3-minute expiration: Transaction data expires 3 minutes after generation. After expiration, request new fulfillment data with updated fees.
- Display to users: Always show users the final fee breakdown from the
fulfillOrder response before they sign, not from the listing query.
Percentage-Based Fees
Calculate fees as a percentage of the order value:
function calculateFee(orderAmount: string, percentageBps: number): string {
// BPS = basis points (100 bps = 1%)
const amount = BigInt(orderAmount);
const fee = (amount * BigInt(percentageBps)) / BigInt(10000);
return fee.toString();
}
// 2.5% marketplace fee
const fee = calculateFee(listing.buy.amount, 250);
const { actions } = await orderbookClient.fulfillOrder(
orderId,
buyerAddress,
[{ recipientAddress: MARKETPLACE_WALLET, amount: fee }]
);
Fee Splitting
Distribute fees to multiple recipients:
const makerFees = [
{
recipientAddress: PLATFORM_WALLET,
amount: calculateFee(price, 100), // 1% to platform
},
{
recipientAddress: AFFILIATE_WALLET,
amount: calculateFee(price, 50), // 0.5% to affiliate
},
];
await orderbookClient.createListing({
// ...
makerFees,
});
Displaying Fees to Users
Show users the fee breakdown before they trade:
interface FeeBreakdown {
protocolFee: bigint;
royalty: bigint;
makerFee: bigint;
takerFee: bigint;
sellerReceives: bigint;
}
function calculateFeeBreakdown(
salePrice: bigint,
royaltyBps: number,
makerFeeBps: number,
takerFeeBps: number
): FeeBreakdown {
const protocolFee = (salePrice * 200n) / 10000n; // 2%
const royalty = (salePrice * BigInt(royaltyBps)) / 10000n;
const makerFee = (salePrice * BigInt(makerFeeBps)) / 10000n;
const takerFee = (salePrice * BigInt(takerFeeBps)) / 10000n;
const sellerReceives = salePrice - protocolFee - royalty - makerFee;
return { protocolFee, royalty, makerFee, takerFee, sellerReceives };
}
Example UI
You're selling: Sword of Power #123
Price: 1.00 IMX
Fee Breakdown:
Protocol Fee (2%): -0.02 IMX
Creator Royalty (5%): -0.05 IMX
Marketplace Fee (1%): -0.01 IMX
─────────────────────────────────
You'll receive: 0.92 IMX
Fee Limits
| Fee Type | Maximum |
|---|
| Royalty | 10% recommended, contract-defined |
| Maker Fee | No protocol limit |
| Taker Fee | No protocol limit |
| Total Fees | Should not exceed sale price |
Keep total fees reasonable (under 15%) to maintain a healthy marketplace. High fees discourage trading.
Next Steps