Skip to main content

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
Source Fee Diagram

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
Destination Fee Diagram
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 Strategies#

When 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 Funding#

The 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:

  1. Determine the expected message volume and fee requirements
  2. Transfer sufficient wrapped gas tokens and FEE_TOKEN to your contract address
  3. Monitor balances and replenish as needed

Option 2: Dynamic Fee Collection#

Alternatively, 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 Limits#

Protect 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 Tokens#

Implement 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#

  1. Monitor Balances: Regularly check your contract's token balances to ensure sufficient funds for message processing
  2. Implement Alerts: Set up notifications for low balance thresholds
  3. Fee Transparency: Clearly communicate fee structures to your users
  4. Emergency Recovery: Include mechanisms to recover funds in case of unexpected issues
  5. Test Thoroughly: Verify fee collection and message processing on testnets before mainnet deployment

Next Steps

Need Help? Join our Discord community for support and discussions.