Skip to main content

Interchain Gas Payment

To deliver a message, a transaction must be included on the destination chain that calls the Mailbox process function with the encoded message and ISM metadata.

For convenience, a relayer watches for dispatched messages and will submit process transactions on behalf of the message sender if they receive sufficient payment on the origin chain. We refer to this as interchain gas payment.

Because messages can trigger arbitrary code execution, the relayer must meter the handle call with a gasLimit to charge appropriately at message dispatch time.

txCost=gasPricegasLimitexchangeRate=originGasTokenPricedestinationGasTokenPriceoriginFee=exchangeRatetxCosttxCost = gasPrice * gasLimit \\[5pt] exchangeRate = \frac{originGasTokenPrice}{destinationGasTokenPrice} \\[5pt] originFee = exchangeRate * txCost

Destination Gas Config

For each remote domain, you can set the domain gas config.

struct DomainGasConfig {
IGasOracle gasOracle;
uint96 gasOverhead;
}

gasOracle

The gasOracle is a contract containing the exchange rates between supported origin and destination chains.

gasOverhead

The gasOverhead is the operational cost of processing a message on the destination chain. When returning a quote for the cost of dispatching a message, the IGP contract will add this gasOverhead to the gasLimit.

Post Dispatch

During the post-dispatch hook, the InterchainGasPaymaster contract will revert if payment is insufficient to cover the relayer's anticipated costs. The relayer will honor quotes from dispatch time.

Gas Limit

When none is specified, the gasLimit for metering the handle call uses a static default of 50_000.

tip

We recommend developers benchmark their handle implementations in unit tests to determine a reasonable gasLimit to use.

If you expect the handle function to consume more than this default, you should override the default gasLimit in metadata.

Metadata

This hook expects metadata in a packed encoding of StandardHookMetadata. See the Mailbox dispatch overloads for how to pass metadata overrides.

struct StandardHookMetadata {
uint16 variant;
uint256 msgValue;
uint256 gasLimit;
address refundAddress;
}

Examples

bytes memory metadata = abi.encodePacked(
StandardHookMetadata({
variant: 1, // only variant supported by this hook
msgValue: 0, // unused by this hook
gasLimit: 100000, // override default gas limit
refundAddress: msg.sender // override default refund address
})
);

Gas Oracles

The interchain gas payment requirement is calculated using oraclized gas price and exchange rates between supported origin and destination chains.

info

Exchange rates and gas prices are up to the relayer to decide. A spread may be charged to account for drift and operating costs.

function getExchangeRateAndGasPrice(
uint32 _destinationDomain
)
public
view
override
returns (uint128 tokenExchangeRate, uint128 gasPrice)
{
IGasOracle _gasOracle = destinationGasConfigs[_destinationDomain]
.gasOracle;

require(
address(_gasOracle) != address(0),
string.concat(
"Configured IGP doesn't support domain ",
Strings.toString(_destinationDomain)
)
);

return _gasOracle.getExchangeRateAndGasPrice(_destinationDomain);
}

Parameters

  • destinationDomain: The message's destination domain

Returns

  • tokenExchangeRate: The exchange rate between the origin and destination chain's gas tokens
  • gasPrice: The gas price for the destination chain

The quoteGasPayment function calculates fees for the relayer's anticipated costs.

function quoteGasPayment(
uint32 _destinationDomain,
uint256 _gasLimit
) public view virtual override returns (uint256) {
// Get the gas data for the destination domain.
(
uint128 _tokenExchangeRate,
uint128 _gasPrice
) = getExchangeRateAndGasPrice(_destinationDomain);

// The total cost quoted in destination chain's native token.
uint256 _destinationGasCost = _gasLimit * uint256(_gasPrice);

// Convert to the local native token.
return
(_destinationGasCost * _tokenExchangeRate) /
TOKEN_EXCHANGE_RATE_SCALE;
}

Parameters

  • destinationDomain: The message's destination domain
  • gasLimit: The gas limit to meter the handle call with

Returns

  • fee: The payment required for the postDispatch to succeed

Retrying

If the handle call consumes more gas than quoted, the relayer will not submit a process transaction. In this case, additional gas can be paid for with the payForGas function.

function payForGas(
bytes32 _messageId,
uint32 _destinationDomain,
uint256 _gasAmount,
address _refundAddress
) external payable;

Parameters

  • messageId: The message identifier returned from dispatch call
  • destinationDomain: The message's destination domain
  • gasAmount: The additional gas amount to pay for
  • refundAddress: The address to refund excess payment to