Transaction Hash:
Block:
19719290 at Apr-23-2024 04:29:35 PM +UTC
Transaction Fee:
0.000785545191430488 ETH
$1.68
Gas Used:
46,628 Gas / 16.847070246 Gwei
Emitted Events:
| 701 |
AxelarGasServiceProxy.0xd5df103822011013c8c940930e5180419111c65abadd6525ca7e740d56b4703f( 0xd5df103822011013c8c940930e5180419111c65abadd6525ca7e740d56b4703f, 0xc33916e63570c1180ff6856926992972aaf65c79d29f4a05263107c905dc1193, 0x0000000000000000000000000000000000000000000000000000000000000003, 000000000000000000000000ca74f404e0c7bfa35b13b511097df966d5a65597, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000005a1156f38f6af )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x15036ABA...c47F4B51F |
0.66015596643500583 Eth
Nonce: 311
|
0.659370421243575342 Eth
Nonce: 312
| 0.000785545191430488 | ||
| 0x2d5d7d31...09a082712 | (Axelar: Gas Service) | 0.301123321721392162 Eth | 0.299538833405449587 Eth | 0.001584488315942575 | |
|
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 13.177811476728499314 Eth | 13.177812987120627094 Eth | 0.00000151039212778 | |
| 0xcA74F404...6D5a65597 | 9.276516268529179642 Eth | 9.278100756845122217 Eth | 0.001584488315942575 |
Execution Trace
Operators.executeContract( target=0x2d5d7d31F671F86C782533cc367F14109a082712, callData=0x36504721C33916E63570C1180FF6856926992972AAF65C79D29F4A05263107C905DC11930000000000000000000000000000000000000000000000000000000000000003000000000000000000000000CA74F404E0C7BFA35B13B511097DF966D5A6559700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005A1156F38F6AF, nativeValue=0 ) => ( 0x )
AxelarGasServiceProxy.36504721( )AxelarGasService.refund( txHash=C33916E63570C1180FF6856926992972AAF65C79D29F4A05263107C905DC1193, logIndex=3, receiver=0xcA74F404E0C7bfA35B13B511097df966D5a65597, token=0x0000000000000000000000000000000000000000, amount=1584488315942575 )- ETH 0.001584488315942575
0xca74f404e0c7bfa35b13b511097df966d5a65597.CALL( )
- ETH 0.001584488315942575
executeContract[Operators (ln:173)]
call[Operators (ln:181)]ExecutionFailed[Operators (ln:183)]
File 1 of 3: Operators
File 2 of 3: AxelarGasServiceProxy
File 3 of 3: AxelarGasService
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IContractExecutor Interface
* @notice This interface defines the execute function used to interact with external contracts.
*/
interface IContractExecutor {
/**
* @notice Executes a call to an external contract.
* @dev Execution logic is left up to the implementation.
* @param target The address of the contract to be called
* @param callData The calldata to be sent
* @param nativeValue The amount of native token (e.g., Ether) to be sent along with the call
* @return bytes The data returned from the executed call
*/
function executeContract(
address target,
bytes calldata callData,
uint256 nativeValue
) external payable returns (bytes memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IOwnable } from './IOwnable.sol';
import { IContractExecutor } from './IContractExecutor.sol';
/**
* @title IOperators Interface
* @notice Interface for an access control mechanism where operators have exclusive
* permissions to execute functions.
*/
interface IOperators is IOwnable, IContractExecutor {
error NotOperator();
error InvalidOperator();
error OperatorAlreadyAdded();
error NotAnOperator();
error ExecutionFailed();
event OperatorAdded(address indexed operator);
event OperatorRemoved(address indexed operator);
/**
* @notice Check if an account is an operator.
* @param account Address of the account to check
* @return bool True if the account is an operator, false otherwise
*/
function isOperator(address account) external view returns (bool);
/**
* @notice Adds an operator.
* @param operator The address to add as an operator
*/
function addOperator(address operator) external;
/**
* @notice Removes an operator.
* @param operator The address of the operator to remove
*/
function removeOperator(address operator) external;
/**
* @notice Executes an external contract call.
* @dev Execution logic is left up to the implementation.
* @param target The contract to call
* @param callData The data to call the target contract with
* @param nativeValue The amount of native asset to send with the call
* @return bytes The data returned from the contract call
*/
function executeContract(
address target,
bytes calldata callData,
uint256 nativeValue
) external payable returns (bytes memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IOwnable Interface
* @notice IOwnable is an interface that abstracts the implementation of a
* contract with ownership control features. It's commonly used in upgradable
* contracts and includes the functionality to get current owner, transfer
* ownership, and propose and accept ownership.
*/
interface IOwnable {
error NotOwner();
error InvalidOwner();
error InvalidOwnerAddress();
event OwnershipTransferStarted(address indexed newOwner);
event OwnershipTransferred(address indexed newOwner);
/**
* @notice Returns the current owner of the contract.
* @return address The address of the current owner
*/
function owner() external view returns (address);
/**
* @notice Returns the address of the pending owner of the contract.
* @return address The address of the pending owner
*/
function pendingOwner() external view returns (address);
/**
* @notice Transfers ownership of the contract to a new address
* @param newOwner The address to transfer ownership to
*/
function transferOwnership(address newOwner) external;
/**
* @notice Proposes to transfer the contract's ownership to a new address.
* The new owner needs to accept the ownership explicitly.
* @param newOwner The address to transfer ownership to
*/
function proposeOwnership(address newOwner) external;
/**
* @notice Transfers ownership to the pending owner.
* @dev Can only be called by the pending owner
*/
function acceptOwnership() external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IOperators } from '../interfaces/IOperators.sol';
import { Ownable } from './Ownable.sol';
/**
* @title Operators
* @notice This contract provides an access control mechanism, where an owner can register
* operator accounts that can call arbitrary contracts on behalf of this contract.
* @dev The owner account is initially set as the deployer address.
*/
contract Operators is Ownable, IOperators {
mapping(address => bool) public operators;
/**
* @notice Sets the initial owner of the contract.
*/
constructor(address initialOwner) Ownable(initialOwner) {}
/**
* @notice Modifier that requires the `msg.sender` to be an operator.
* @dev Reverts with a NotOperator error if the condition is not met.
*/
modifier onlyOperator() {
if (!operators[msg.sender]) revert NotOperator();
_;
}
/**
* @notice Returns whether an address is an operator.
* @param account Address to check
* @return boolean whether the address is an operator
*/
function isOperator(address account) external view returns (bool) {
return operators[account];
}
/**
* @notice Adds an address as an operator.
* @dev Can only be called by the current owner.
* @param operator address to be added as operator
*/
function addOperator(address operator) external onlyOwner {
if (operator == address(0)) revert InvalidOperator();
if (operators[operator]) revert OperatorAlreadyAdded();
operators[operator] = true;
emit OperatorAdded(operator);
}
/**
* @notice Removes an address as an operator.
* @dev Can only be called by the current owner.
* @param operator address to be removed as operator
*/
function removeOperator(address operator) external onlyOwner {
if (operator == address(0)) revert InvalidOperator();
if (!operators[operator]) revert NotAnOperator();
operators[operator] = false;
emit OperatorRemoved(operator);
}
/**
* @notice Allows an operator to execute arbitrary functions on any smart contract.
* @dev Can only be called by an operator.
* @param target address of the contract to execute the function on. Existence is not checked.
* @param callData ABI encoded function call to execute on target
* @param nativeValue The amount of native asset to send with the call. If `nativeValue` is set to `0`, then `msg.value` is forwarded instead.
* @return data return data from executed function call
*/
function executeContract(
address target,
bytes calldata callData,
uint256 nativeValue
) external payable onlyOperator returns (bytes memory) {
if (nativeValue == 0) {
nativeValue = msg.value;
}
(bool success, bytes memory data) = target.call{ value: nativeValue }(callData);
if (!success) {
revert ExecutionFailed();
}
return data;
}
/**
* @notice This function enables the contract to accept native value transfers.
*/
receive() external payable {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IOwnable } from '../interfaces/IOwnable.sol';
/**
* @title Ownable
* @notice A contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The owner account is set through ownership transfer. This module makes
* it possible to transfer the ownership of the contract to a new account in one
* step, as well as to an interim pending owner. In the second flow the ownership does not
* change until the pending owner accepts the ownership transfer.
*/
abstract contract Ownable is IOwnable {
// keccak256('owner')
bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
// keccak256('ownership-transfer')
bytes32 internal constant _OWNERSHIP_TRANSFER_SLOT =
0x9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1;
/**
* @notice Initializes the contract by transferring ownership to the owner parameter.
* @param _owner Address to set as the initial owner of the contract
*/
constructor(address _owner) {
_transferOwnership(_owner);
}
/**
* @notice Modifier that throws an error if called by any account other than the owner.
*/
modifier onlyOwner() {
if (owner() != msg.sender) revert NotOwner();
_;
}
/**
* @notice Returns the current owner of the contract.
* @return owner_ The current owner of the contract
*/
function owner() public view returns (address owner_) {
assembly {
owner_ := sload(_OWNER_SLOT)
}
}
/**
* @notice Returns the pending owner of the contract.
* @return owner_ The pending owner of the contract
*/
function pendingOwner() public view returns (address owner_) {
assembly {
owner_ := sload(_OWNERSHIP_TRANSFER_SLOT)
}
}
/**
* @notice Transfers ownership of the contract to a new account `newOwner`.
* @dev Can only be called by the current owner.
* @param newOwner The address to transfer ownership to
*/
function transferOwnership(address newOwner) external virtual onlyOwner {
_transferOwnership(newOwner);
}
/**
* @notice Propose to transfer ownership of the contract to a new account `newOwner`.
* @dev Can only be called by the current owner. The ownership does not change
* until the new owner accepts the ownership transfer.
* @param newOwner The address to transfer ownership to
*/
function proposeOwnership(address newOwner) external virtual onlyOwner {
if (newOwner == address(0)) revert InvalidOwnerAddress();
emit OwnershipTransferStarted(newOwner);
assembly {
sstore(_OWNERSHIP_TRANSFER_SLOT, newOwner)
}
}
/**
* @notice Accepts ownership of the contract.
* @dev Can only be called by the pending owner
*/
function acceptOwnership() external virtual {
address newOwner = pendingOwner();
if (newOwner != msg.sender) revert InvalidOwner();
_transferOwnership(newOwner);
}
/**
* @notice Internal function to transfer ownership of the contract to a new account `newOwner`.
* @dev Called in the constructor to set the initial owner.
* @param newOwner The address to transfer ownership to
*/
function _transferOwnership(address newOwner) internal virtual {
if (newOwner == address(0)) revert InvalidOwnerAddress();
emit OwnershipTransferred(newOwner);
assembly {
sstore(_OWNER_SLOT, newOwner)
sstore(_OWNERSHIP_TRANSFER_SLOT, 0)
}
}
}
File 2 of 3: AxelarGasServiceProxy
// Sources flattened with hardhat v2.9.9 https://hardhat.org
// File contracts/interfaces/IUpgradable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
// General interface for upgradable contracts
interface IUpgradable {
error NotOwner();
error InvalidOwner();
error InvalidCodeHash();
error InvalidImplementation();
error SetupFailed();
error NotProxy();
event Upgraded(address indexed newImplementation);
event OwnershipTransferred(address indexed newOwner);
// Get current owner
function owner() external view returns (address);
function contractId() external pure returns (bytes32);
function implementation() external view returns (address);
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external;
function setup(bytes calldata data) external;
}
// File contracts/util/Proxy.sol
contract Proxy {
error InvalidImplementation();
error SetupFailed();
error EtherNotAccepted();
error NotOwner();
error AlreadyInitialized();
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
// keccak256('owner')
bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
constructor() {
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(_OWNER_SLOT, caller())
}
}
function init(
address implementationAddress,
address newOwner,
bytes memory params
) external {
address owner;
// solhint-disable-next-line no-inline-assembly
assembly {
owner := sload(_OWNER_SLOT)
}
if (msg.sender != owner) revert NotOwner();
if (implementation() != address(0)) revert AlreadyInitialized();
if (IUpgradable(implementationAddress).contractId() != contractId()) revert InvalidImplementation();
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(_IMPLEMENTATION_SLOT, implementationAddress)
sstore(_OWNER_SLOT, newOwner)
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = implementationAddress.delegatecall(
// keccak('setup(bytes)') selector
abi.encodeWithSelector(0x9ded06df, params)
);
if (!success) revert SetupFailed();
}
// solhint-disable-next-line no-empty-blocks
function contractId() internal pure virtual returns (bytes32) {}
function implementation() public view returns (address implementation_) {
// solhint-disable-next-line no-inline-assembly
assembly {
implementation_ := sload(_IMPLEMENTATION_SLOT)
}
}
// solhint-disable-next-line no-empty-blocks
function setup(bytes calldata data) public {}
// solhint-disable-next-line no-complex-fallback
fallback() external payable {
address implementaion_ = implementation();
// solhint-disable-next-line no-inline-assembly
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementaion_, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
receive() external payable virtual {
revert EtherNotAccepted();
}
}
// File contracts/gas-service/AxelarGasServiceProxy.sol
contract AxelarGasServiceProxy is Proxy {
function contractId() internal pure override returns (bytes32) {
return keccak256('axelar-gas-service');
}
}File 3 of 3: AxelarGasService
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// General interface for upgradable contracts
interface IContractIdentifier {
/**
* @notice Returns the contract ID. It can be used as a check during upgrades.
* @dev Meant to be overridden in derived contracts.
* @return bytes32 The contract ID
*/
function contractId() external pure returns (bytes32);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
error InvalidAccount();
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IContractIdentifier } from './IContractIdentifier.sol';
interface IImplementation is IContractIdentifier {
error NotProxy();
function setup(bytes calldata data) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IOwnable Interface
* @notice IOwnable is an interface that abstracts the implementation of a
* contract with ownership control features. It's commonly used in upgradable
* contracts and includes the functionality to get current owner, transfer
* ownership, and propose and accept ownership.
*/
interface IOwnable {
error NotOwner();
error InvalidOwner();
error InvalidOwnerAddress();
event OwnershipTransferStarted(address indexed newOwner);
event OwnershipTransferred(address indexed newOwner);
/**
* @notice Returns the current owner of the contract.
* @return address The address of the current owner
*/
function owner() external view returns (address);
/**
* @notice Returns the address of the pending owner of the contract.
* @return address The address of the pending owner
*/
function pendingOwner() external view returns (address);
/**
* @notice Transfers ownership of the contract to a new address
* @param newOwner The address to transfer ownership to
*/
function transferOwnership(address newOwner) external;
/**
* @notice Proposes to transfer the contract's ownership to a new address.
* The new owner needs to accept the ownership explicitly.
* @param newOwner The address to transfer ownership to
*/
function proposeOwnership(address newOwner) external;
/**
* @notice Transfers ownership to the pending owner.
* @dev Can only be called by the pending owner
*/
function acceptOwnership() external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IOwnable } from './IOwnable.sol';
import { IImplementation } from './IImplementation.sol';
// General interface for upgradable contracts
interface IUpgradable is IOwnable, IImplementation {
error InvalidCodeHash();
error InvalidImplementation();
error SetupFailed();
event Upgraded(address indexed newImplementation);
function implementation() external view returns (address);
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
error NativeTransferFailed();
/*
* @title SafeNativeTransfer
* @dev This library is used for performing safe native value transfers in Solidity by utilizing inline assembly.
*/
library SafeNativeTransfer {
/*
* @notice Perform a native transfer to a given address.
* @param receiver The recipient address to which the amount will be sent.
* @param amount The amount of native value to send.
* @throws NativeTransferFailed error if transfer is not successful.
*/
function safeNativeTransfer(address receiver, uint256 amount) internal {
bool success;
assembly {
success := call(gas(), receiver, amount, 0, 0, 0, 0)
}
if (!success) revert NativeTransferFailed();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC20 } from '../interfaces/IERC20.sol';
error TokenTransferFailed();
/*
* @title SafeTokenCall
* @dev This library is used for performing safe token transfers.
*/
library SafeTokenCall {
/*
* @notice Make a safe call to a token contract.
* @param token The token contract to interact with.
* @param callData The function call data.
* @throws TokenTransferFailed error if transfer of token is not successful.
*/
function safeCall(IERC20 token, bytes memory callData) internal {
(bool success, bytes memory returnData) = address(token).call(callData);
bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
if (!transferred || address(token).code.length == 0) revert TokenTransferFailed();
}
}
/*
* @title SafeTokenTransfer
* @dev This library safely transfers tokens from the contract to a recipient.
*/
library SafeTokenTransfer {
/*
* @notice Transfer tokens to a recipient.
* @param token The token contract.
* @param receiver The recipient of the tokens.
* @param amount The amount of tokens to transfer.
*/
function safeTransfer(
IERC20 token,
address receiver,
uint256 amount
) internal {
SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount));
}
}
/*
* @title SafeTokenTransferFrom
* @dev This library helps to safely transfer tokens on behalf of a token holder.
*/
library SafeTokenTransferFrom {
/*
* @notice Transfer tokens on behalf of a token holder.
* @param token The token contract.
* @param from The address of the token holder.
* @param to The address the tokens are to be sent to.
* @param amount The amount of tokens to be transferred.
*/
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount));
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IImplementation } from '../interfaces/IImplementation.sol';
/**
* @title Implementation
* @notice This contract serves as a base for other contracts and enforces a proxy-first access restriction.
* @dev Derived contracts must implement the setup function.
*/
abstract contract Implementation is IImplementation {
address private immutable implementationAddress;
/**
* @dev Contract constructor that sets the implementation address to the address of this contract.
*/
constructor() {
implementationAddress = address(this);
}
/**
* @dev Modifier to require the caller to be the proxy contract.
* Reverts if the caller is the current contract (i.e., the implementation contract itself).
*/
modifier onlyProxy() {
if (implementationAddress == address(this)) revert NotProxy();
_;
}
/**
* @notice Initializes contract parameters.
* This function is intended to be overridden by derived contracts.
* The overriding function must have the onlyProxy modifier.
* @param params The parameters to be used for initialization
*/
function setup(bytes calldata params) external virtual;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IImplementation } from '../interfaces/IImplementation.sol';
import { IUpgradable } from '../interfaces/IUpgradable.sol';
import { Ownable } from '../utils/Ownable.sol';
import { Implementation } from './Implementation.sol';
/**
* @title Upgradable Contract
* @notice This contract provides an interface for upgradable smart contracts and includes the functionality to perform upgrades.
*/
abstract contract Upgradable is Ownable, Implementation, IUpgradable {
// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @notice Constructor sets the implementation address to the address of the contract itself
* @dev This is used in the onlyProxy modifier to prevent certain functions from being called directly
* on the implementation contract itself.
* @dev The owner is initially set as address(1) because the actual owner is set within the proxy. It is not
* set as the zero address because Ownable is designed to throw an error for ownership transfers to the zero address.
*/
constructor() Ownable(address(1)) {}
/**
* @notice Returns the address of the current implementation
* @return implementation_ Address of the current implementation
*/
function implementation() public view returns (address implementation_) {
assembly {
implementation_ := sload(_IMPLEMENTATION_SLOT)
}
}
/**
* @notice Upgrades the contract to a new implementation
* @param newImplementation The address of the new implementation contract
* @param newImplementationCodeHash The codehash of the new implementation contract
* @param params Optional setup parameters for the new implementation contract
* @dev This function is only callable by the owner.
*/
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata params
) external override onlyOwner {
if (IUpgradable(newImplementation).contractId() != IUpgradable(implementation()).contractId())
revert InvalidImplementation();
if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
emit Upgraded(newImplementation);
if (params.length > 0) {
// slither-disable-next-line controlled-delegatecall
(bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(this.setup.selector, params));
if (!success) revert SetupFailed();
}
assembly {
sstore(_IMPLEMENTATION_SLOT, newImplementation)
}
}
/**
* @notice Sets up the contract with initial data
* @param data Initialization data for the contract
* @dev This function is only callable by the proxy contract.
*/
function setup(bytes calldata data) external override(IImplementation, Implementation) onlyProxy {
_setup(data);
}
/**
* @notice Internal function to set up the contract with initial data
* @param data Initialization data for the contract
* @dev This function should be implemented in derived contracts.
*/
function _setup(bytes calldata data) internal virtual {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IOwnable } from '../interfaces/IOwnable.sol';
/**
* @title Ownable
* @notice A contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The owner account is set through ownership transfer. This module makes
* it possible to transfer the ownership of the contract to a new account in one
* step, as well as to an interim pending owner. In the second flow the ownership does not
* change until the pending owner accepts the ownership transfer.
*/
abstract contract Ownable is IOwnable {
// keccak256('owner')
bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
// keccak256('ownership-transfer')
bytes32 internal constant _OWNERSHIP_TRANSFER_SLOT =
0x9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1;
/**
* @notice Initializes the contract by transferring ownership to the owner parameter.
* @param _owner Address to set as the initial owner of the contract
*/
constructor(address _owner) {
_transferOwnership(_owner);
}
/**
* @notice Modifier that throws an error if called by any account other than the owner.
*/
modifier onlyOwner() {
if (owner() != msg.sender) revert NotOwner();
_;
}
/**
* @notice Returns the current owner of the contract.
* @return owner_ The current owner of the contract
*/
function owner() public view returns (address owner_) {
assembly {
owner_ := sload(_OWNER_SLOT)
}
}
/**
* @notice Returns the pending owner of the contract.
* @return owner_ The pending owner of the contract
*/
function pendingOwner() public view returns (address owner_) {
assembly {
owner_ := sload(_OWNERSHIP_TRANSFER_SLOT)
}
}
/**
* @notice Transfers ownership of the contract to a new account `newOwner`.
* @dev Can only be called by the current owner.
* @param newOwner The address to transfer ownership to
*/
function transferOwnership(address newOwner) external virtual onlyOwner {
_transferOwnership(newOwner);
}
/**
* @notice Propose to transfer ownership of the contract to a new account `newOwner`.
* @dev Can only be called by the current owner. The ownership does not change
* until the new owner accepts the ownership transfer.
* @param newOwner The address to transfer ownership to
*/
function proposeOwnership(address newOwner) external virtual onlyOwner {
if (newOwner == address(0)) revert InvalidOwnerAddress();
emit OwnershipTransferStarted(newOwner);
assembly {
sstore(_OWNERSHIP_TRANSFER_SLOT, newOwner)
}
}
/**
* @notice Accepts ownership of the contract.
* @dev Can only be called by the pending owner
*/
function acceptOwnership() external virtual {
address newOwner = pendingOwner();
if (newOwner != msg.sender) revert InvalidOwner();
_transferOwnership(newOwner);
}
/**
* @notice Internal function to transfer ownership of the contract to a new account `newOwner`.
* @dev Called in the constructor to set the initial owner.
* @param newOwner The address to transfer ownership to
*/
function _transferOwnership(address newOwner) internal virtual {
if (newOwner == address(0)) revert InvalidOwnerAddress();
emit OwnershipTransferred(newOwner);
assembly {
sstore(_OWNER_SLOT, newOwner)
sstore(_OWNERSHIP_TRANSFER_SLOT, 0)
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
import { SafeTokenTransfer, SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
import { SafeNativeTransfer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeNativeTransfer.sol';
import { IAxelarGasService } from '../interfaces/IAxelarGasService.sol';
import { Upgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Upgradable.sol';
/**
* @title AxelarGasService
* @notice This contract manages gas payments and refunds for cross-chain communication on the Axelar network.
* @dev The owner address of this contract should be the microservice that pays for gas.
* @dev Users pay gas for cross-chain calls, and the gasCollector can collect accumulated fees and/or refund users if needed.
*/
contract AxelarGasService is Upgradable, IAxelarGasService {
using SafeTokenTransfer for IERC20;
using SafeTokenTransferFrom for IERC20;
using SafeNativeTransfer for address payable;
address public immutable gasCollector;
/**
* @notice Constructs the AxelarGasService contract.
* @param gasCollector_ The address of the gas collector
*/
constructor(address gasCollector_) {
gasCollector = gasCollector_;
}
/**
* @notice Modifier that ensures the caller is the designated gas collector.
*/
modifier onlyCollector() {
if (msg.sender != gasCollector) revert NotCollector();
_;
}
/**
* @notice Pay for gas using ERC20 tokens for a contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @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 gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
emit GasPaidForContractCall(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
gasToken,
gasFeeAmount,
refundAddress
);
IERC20(gasToken).safeTransferFrom(msg.sender, address(this), gasFeeAmount);
}
/**
* @notice Pay for gas using ERC20 tokens for a contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string memory symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
emit GasPaidForContractCallWithToken(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
symbol,
amount,
gasToken,
gasFeeAmount,
refundAddress
);
IERC20(gasToken).safeTransferFrom(msg.sender, address(this), gasFeeAmount);
}
/**
* @notice Pay for gas using native currency for a contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @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 refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable override {
emit NativeGasPaidForContractCall(sender, destinationChain, destinationAddress, keccak256(payload), msg.value, refundAddress);
}
/**
* @notice Pay for gas using native currency for a contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable override {
emit NativeGasPaidForContractCallWithToken(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
symbol,
amount,
msg.value,
refundAddress
);
}
/**
* @notice Pay for gas using ERC20 tokens for an express contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to express execute a remote contract.
* @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 gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForExpressCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
emit GasPaidForExpressCall(sender, destinationChain, destinationAddress, keccak256(payload), gasToken, gasFeeAmount, refundAddress);
IERC20(gasToken).safeTransferFrom(msg.sender, address(this), gasFeeAmount);
}
/**
* @notice Pay for gas using ERC20 tokens for an express contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to express execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string memory symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
emit GasPaidForExpressCallWithToken(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
symbol,
amount,
gasToken,
gasFeeAmount,
refundAddress
);
IERC20(gasToken).safeTransferFrom(msg.sender, address(this), gasFeeAmount);
}
/**
* @notice Pay for gas using native currency for an express contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @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 refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForExpressCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable override {
emit NativeGasPaidForExpressCall(sender, destinationChain, destinationAddress, keccak256(payload), msg.value, refundAddress);
}
/**
* @notice Pay for gas using native currency for an express contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable override {
emit NativeGasPaidForExpressCallWithToken(
sender,
destinationChain,
destinationAddress,
keccak256(payload),
symbol,
amount,
msg.value,
refundAddress
);
}
/**
* @notice Add additional gas payment using ERC20 tokens after initiating a cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param gasToken The ERC20 token address used to add gas
* @param gasFeeAmount The amount of tokens to add as gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function addGas(
bytes32 txHash,
uint256 logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
emit GasAdded(txHash, logIndex, gasToken, gasFeeAmount, refundAddress);
IERC20(gasToken).safeTransferFrom(msg.sender, address(this), gasFeeAmount);
}
/**
* @notice Add additional gas payment using native currency after initiating a cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param refundAddress The address where refunds, if any, should be sent
*/
function addNativeGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable override {
emit NativeGasAdded(txHash, logIndex, msg.value, refundAddress);
}
/**
* @notice Add additional gas payment using ERC20 tokens after initiating an express cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to express execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param gasToken The ERC20 token address used to add gas
* @param gasFeeAmount The amount of tokens to add as gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function addExpressGas(
bytes32 txHash,
uint256 logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external override {
emit ExpressGasAdded(txHash, logIndex, gasToken, gasFeeAmount, refundAddress);
IERC20(gasToken).safeTransferFrom(msg.sender, address(this), gasFeeAmount);
}
/**
* @notice Add additional gas payment using native currency after initiating an express cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to express execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param refundAddress The address where refunds, if any, should be sent
*/
function addNativeExpressGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable override {
emit NativeExpressGasAdded(txHash, logIndex, msg.value, refundAddress);
}
/**
* @notice Allows the gasCollector to collect accumulated fees from the contract.
* @dev Use address(0) as the token address for native currency.
* @param receiver The address to receive the collected fees
* @param tokens Array of token addresses to be collected
* @param amounts Array of amounts to be collected for each respective token address
*/
function collectFees(
address payable receiver,
address[] calldata tokens,
uint256[] calldata amounts
) external onlyCollector {
if (receiver == address(0)) revert InvalidAddress();
uint256 tokensLength = tokens.length;
if (tokensLength != amounts.length) revert InvalidAmounts();
for (uint256 i; i < tokensLength; i++) {
address token = tokens[i];
uint256 amount = amounts[i];
if (amount == 0) revert InvalidAmounts();
if (token == address(0)) {
if (amount <= address(this).balance) receiver.safeNativeTransfer(amount);
} else {
// slither-disable-next-line calls-loop
if (amount <= IERC20(token).balanceOf(address(this))) IERC20(token).safeTransfer(receiver, amount);
}
}
}
/**
* @dev Deprecated refund function, kept for backward compatibility.
*/
function refund(
address payable receiver,
address token,
uint256 amount
) external onlyCollector {
_refund(bytes32(0), 0, receiver, token, amount);
}
/**
* @notice Refunds gas payment to the receiver in relation to a specific cross-chain transaction.
* @dev Only callable by the gasCollector.
* @dev Use address(0) as the token address to refund native currency.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param receiver The address to receive the refund
* @param token The token address to be refunded
* @param amount The amount to refund
*/
function refund(
bytes32 txHash,
uint256 logIndex,
address payable receiver,
address token,
uint256 amount
) external onlyCollector {
_refund(txHash, logIndex, receiver, token, amount);
}
/**
* @dev Internal function to implement gas refund logic.
*/
function _refund(
bytes32 txHash,
uint256 logIndex,
address payable receiver,
address token,
uint256 amount
) private {
if (receiver == address(0)) revert InvalidAddress();
emit Refunded(txHash, logIndex, receiver, token, amount);
if (token == address(0)) {
receiver.safeNativeTransfer(amount);
} else {
IERC20(token).safeTransfer(receiver, amount);
}
}
/**
* @notice Returns a unique identifier for the contract.
* @return bytes32 Hash of the contract identifier
*/
function contractId() external pure returns (bytes32) {
return keccak256('axelar-gas-service');
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IUpgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IUpgradable.sol';
/**
* @title IAxelarGasService Interface
* @notice This is an interface for the AxelarGasService contract which manages gas payments
* and refunds for cross-chain communication on the Axelar network.
* @dev This interface inherits IUpgradable
*/
interface IAxelarGasService is IUpgradable {
error InvalidAddress();
error NotCollector();
error InvalidAmounts();
event GasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForExpressCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForExpressCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForExpressCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForExpressCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
uint256 gasFeeAmount,
address refundAddress
);
event GasAdded(bytes32 indexed txHash, uint256 indexed logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress);
event NativeGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress);
event ExpressGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress);
event NativeExpressGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress);
event Refunded(bytes32 indexed txHash, uint256 indexed logIndex, address payable receiver, address token, uint256 amount);
/**
* @notice Pay for gas using ERC20 tokens for a contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @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 gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using ERC20 tokens for a contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using native currency for a contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @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 refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable;
/**
* @notice Pay for gas using native currency for a contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable;
/**
* @notice Pay for gas using ERC20 tokens for an express contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to express execute a remote contract.
* @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 gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForExpressCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using ERC20 tokens for an express contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to express execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param gasToken The address of the ERC20 token used to pay for gas
* @param gasFeeAmount The amount of tokens to pay for gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function payGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Pay for gas using native currency for an express contract call on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @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 refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForExpressCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable;
/**
* @notice Pay for gas using native currency for an express contract call with tokens on a destination chain.
* @dev This function is called on the source chain before calling the gateway to execute a remote contract.
* @param sender The address making the payment
* @param destinationChain The target chain where the contract call with tokens will be made
* @param destinationAddress The target address on the destination chain
* @param payload Data payload for the contract call with tokens
* @param symbol The symbol of the token to be sent with the call
* @param amount The amount of tokens to be sent with the call
* @param refundAddress The address where refunds, if any, should be sent
*/
function payNativeGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable;
/**
* @notice Add additional gas payment using ERC20 tokens after initiating a cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param gasToken The ERC20 token address used to add gas
* @param gasFeeAmount The amount of tokens to add as gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function addGas(
bytes32 txHash,
uint256 logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Add additional gas payment using native currency after initiating a cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param refundAddress The address where refunds, if any, should be sent
*/
function addNativeGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable;
/**
* @notice Add additional gas payment using ERC20 tokens after initiating an express cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to express execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param gasToken The ERC20 token address used to add gas
* @param gasFeeAmount The amount of tokens to add as gas
* @param refundAddress The address where refunds, if any, should be sent
*/
function addExpressGas(
bytes32 txHash,
uint256 logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
/**
* @notice Add additional gas payment using native currency after initiating an express cross-chain call.
* @dev This function can be called on the source chain after calling the gateway to express execute a remote contract.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param refundAddress The address where refunds, if any, should be sent
*/
function addNativeExpressGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable;
/**
* @notice Allows the gasCollector to collect accumulated fees from the contract.
* @dev Use address(0) as the token address for native currency.
* @param receiver The address to receive the collected fees
* @param tokens Array of token addresses to be collected
* @param amounts Array of amounts to be collected for each respective token address
*/
function collectFees(
address payable receiver,
address[] calldata tokens,
uint256[] calldata amounts
) external;
/**
* @notice Refunds gas payment to the receiver in relation to a specific cross-chain transaction.
* @dev Only callable by the gasCollector.
* @dev Use address(0) as the token address to refund native currency.
* @param txHash The transaction hash of the cross-chain call
* @param logIndex The log index for the cross-chain call
* @param receiver The address to receive the refund
* @param token The token address to be refunded
* @param amount The amount to refund
*/
function refund(
bytes32 txHash,
uint256 logIndex,
address payable receiver,
address token,
uint256 amount
) external;
/**
* @notice Returns the address of the designated gas collector.
* @return address of the gas collector
*/
function gasCollector() external returns (address);
}