Fees and Gas Management
Source Fees on the Origin Chain
- Token Type: Paid in the chain's stablecoin (USDC or USDT), referred to as
FEE_TOKEN
- Requirement: Transactions will revert if your contract lacks sufficient
FEE_TOKEN
- Developer Action: Ensure
FEE_TOKEN
funds are available before message transmission - Testnet Note: We sponsor almost all fees on most testnets

Gas Fees on the Destination Chain
- Token Type: Paid in wrapped native gas tokens (WETH, WMATIC, WBNB, etc.)
- Responsibility: Your receiving contract needs available funds in the respective wrapped token
- Consequence: Messages won't be delivered without sufficient funds or approval
- Developer Decision: Choose whether to absorb fees or charge users directly
- Testnet Note: We sponsor almost all fees on most testnets

Message Delivery Guarantee
If a message wasn't processed due to insufficient gas in your receiving contract, it won't be lost. The message will be delivered and processed when funds are added and available.
#
Fee Management StrategiesWhen implementing cross-chain messaging, you have flexible options for managing fees. The key is ensuring your contracts have sufficient funds for both source fees and destination gas.
#
Option 1: Direct Contract FundingThe simplest approach is to directly fund your contract with the necessary tokens:
// No special code needed - just transfer tokens to your contract address// For example, send USDC (FEE_TOKEN) and WETH to your contract
Benefits:
- Simple implementation
- No additional code required
- Predictable fee management
How to implement:
- Determine the expected message volume and fee requirements
- Transfer sufficient wrapped gas tokens and FEE_TOKEN to your contract address
- Monitor balances and replenish as needed
#
Option 2: Dynamic Fee CollectionAlternatively, collect fees from users at transaction time:
// Example of collecting fees from usersfunction sendCrossChainMessage(uint256 destinationChainId, bytes memory data) external { // Calculate required fees uint256 sourceFee = calculateSourceFee(destinationChainId); uint256 destinationGas = calculateDestinationGas(destinationChainId); // Collect fees from user require(feeToken.transferFrom(msg.sender, address(this), sourceFee), "Fee transfer failed"); require(wrappedGasToken.transferFrom(msg.sender, address(this), destinationGas), "Gas transfer failed"); // Send the cross-chain message _sendMessage(destinationChainId, data);}
Benefits:
- Pay-as-you-go model
- Fees aligned with actual usage
- No need to pre-fund contracts
#
Fee Protection Mechanisms#
Setting Maximum Fee LimitsProtect your application from unexpected fee spikes:
// Set maximum gas limit for destination chainfunction setMaxGas(uint256 chainId, uint256 maxGasAmount) external onlyOwner { maxGasLimits[chainId] = maxGasAmount;}
// Set maximum fee limit for source chainfunction setMaxFee(uint256 chainId, uint256 maxFeeAmount) external onlyOwner { maxFeeLimits[chainId] = maxFeeAmount;}
// Use these limits in your message sending functionfunction sendProtectedMessage(uint256 destinationChainId, bytes memory data) external { uint256 gasCost = getGasCost(destinationChainId); uint256 feeCost = getFeeCost(destinationChainId); require(gasCost <= maxGasLimits[destinationChainId], "Gas cost exceeds maximum"); require(feeCost <= maxFeeLimits[destinationChainId], "Fee cost exceeds maximum"); // Proceed with message sending _sendMessage(destinationChainId, data);}
#
Recovering TokensImplement token recovery for emergency situations:
// Recover ERC20 tokens accidentally sent to the contractfunction recoverToken(address tokenAddress, uint256 amount) external onlyOwner { IERC20(tokenAddress).transfer(owner(), amount);}
// Recover native tokens (ETH, AVAX, etc.)function recoverNative(uint256 amount) external onlyOwner { payable(owner()).transfer(amount);}
caution
Consider overriding the default recoverToken
function if you need to restrict recovery capabilities or limit them to specific tokens.
#
Best Practices- Monitor Balances: Regularly check your contract's token balances to ensure sufficient funds for message processing
- Implement Alerts: Set up notifications for low balance thresholds
- Fee Transparency: Clearly communicate fee structures to your users
- Emergency Recovery: Include mechanisms to recover funds in case of unexpected issues
- Test Thoroughly: Verify fee collection and message processing on testnets before mainnet deployment
Next Steps
Create Cross-Chain Tokens
Build a token that can move between different blockchains with integrated fee handling.
Solidity Package
Learn how to use our Solidity package to implement cross-chain messaging with proper fee handling.
Troubleshooting
Find solutions to common fee-related issues and other cross-chain messaging problems.
Need Help? Join our Discord community for support and discussions.