On-Chain Gas Estimation (Alpha)
💡
The on-chain gas estimation API is currently only available on testnet.
On-chain gas estimation allows you to estimate interchain transaction gas fees directly from a Solidity contract. You should only use this if you are unable to estimate gas off-chain — for example, if you have a dApp or service that does not have a UI for initiating transactions.
This on-chain API overestimates gas costs using a multiplier for volatility. For more accurate pricing, use the off-chain gas estimation API.
Usage
The on-chain API provided by the IInterchainGasEstimation
interface, which is implemented by the AxelarGasService
contract. Gas estimates will include a buffer, as they do not have access to real time off-chain gas pricing.
The primary method to invoke is estimateGasFee()
.
/** * @notice Estimates the gas fee for a cross-chain contract call. * @param destinationChain Axelar registered name of the destination chain * @param destinationAddress Destination contract address being called * @param executionGasLimit The gas limit to be used for the destination contract execution, * e.g. pass in 200k if your app consumes needs upto 200k for this contract call * @param params Additional parameters for the gas estimation * @return gasEstimate The cross-chain gas estimate, in terms of source chain's native gas token that should be forwarded to the gas service. */function estimateGasFee( string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, uint256 executionGasLimit, bytes calldata params) external view returns (uint256 gasEstimate);
When using on-chain gas estimation, you should pay gas based on the estimate from the new payGas()
function on the gas service instead of calling payNativeGasForContractCall()
.
/** * @notice Pay for gas for any type of contract execution on a destination chain. * @dev This function is called on the source chain before calling the gateway to execute a remote contract. * @dev If estimateOnChain is true, the function will estimate the gas cost and revert if the payment is insufficient. * @param sender The address making the payment * @param destinationChain The target chain where the contract call will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call * @param executionGasLimit The gas limit for the contract call * @param estimateOnChain Flag to enable on-chain gas estimation * @param refundAddress The address where refunds, if any, should be sent * @param params Additional parameters for gas payment. This can be left empty for normal contract call payments.*/function payGas( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, uint256 executionGasLimit, bool estimateOnChain, address refundAddress, bytes calldata params) external payable;
Full GMP Example
The following is an example GMP contract that can send and receive messages. This contract can be found in the axelar-examples
repository on GitHub.
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;
import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol';import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol';import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
/** * @title CallContractGasEstimation * @notice Send a message from chain A to chain B and stores gmp message */contract CallContractGasEstimation is AxelarExecutable { string public message; string public sourceChain; string public sourceAddress; IAxelarGasService public immutable gasService; uint256 public constant GAS_LIMIT = 200000;
event Executed(string _from, string _message);
/** * * @param _gateway address of axl gateway on deployed chain * @param _gasReceiver address of axl gas service on deployed chain */ constructor(address _gateway, address _gasReceiver) AxelarExecutable(_gateway) { gasService = IAxelarGasService(_gasReceiver); }
/** * @notice Estimate gas for a cross-chain contract call * @param destinationChain name of the dest chain * @param destinationAddress address on dest chain this tx is going to * @param _message message to be sent * @return gasEstimate The cross-chain gas estimate */ function estimateGasFee( string calldata destinationChain, string calldata destinationAddress, string calldata _message ) external view returns (uint256) { bytes memory payload = abi.encode(_message);
return gasService.estimateGasFee( destinationChain, destinationAddress, payload, GAS_LIMIT, new bytes(0) ); }
/** * @notice Send message from chain A to chain B * @dev message param is passed in as gmp message * @param destinationChain name of the dest chain (ex. "Fantom") * @param destinationAddress address on dest chain this tx is going to * @param _message message to be sent */ function setRemoteValue( string calldata destinationChain, string calldata destinationAddress, string calldata _message ) external payable { require(msg.value > 0, 'Gas payment is required');
bytes memory payload = abi.encode(_message); gasService.payGas{ value: msg.value }( address(this), destinationChain, destinationAddress, payload, GAS_LIMIT, true, msg.sender, new bytes(0) ); gateway.callContract(destinationChain, destinationAddress, payload); }
/** * @notice logic to be executed on dest chain * @dev this is triggered automatically by relayer * @param _sourceChain blockchain where tx is originating from * @param _sourceAddress address on src chain where tx is originating from * @param _payload encoded gmp message sent from src chain */ function _execute(string calldata _sourceChain, string calldata _sourceAddress, bytes calldata _payload) internal override { (message) = abi.decode(_payload, (string)); sourceChain = _sourceChain; sourceAddress = _sourceAddress;
emit Executed(sourceAddress, message); }}
Transaction execution
Transaction execution is not guaranteed with the on-chain gas estimation API. If you wish to guarantee that your transactions will be executed, please contact the Interop Labs team.