Build
Connected Chains
ZetaChain

To make a call from a universal app to a contract on a connected chain or withdraw tokens, use the ZetaChain gateway.

The ZetaChain gateway supports:

  • Withdrawing ZRC-20 tokens as native gas or ERC-20 tokens to connected chains.
  • Withdrawing ZETA tokens to connected chains.
  • Withdrawing tokens and making a contract call on connected chains.
  • Calling contracts on connected chains.

To withdraw ZRC-20 tokens to an EOA or a contract on a connected chain, use the withdraw function of the gateway contract:

function withdraw(bytes memory receiver, uint256 amount, address zrc20, RevertOptions calldata revertOptions) external;

The receiver can be either an externally-owned account (EOA) or a contract on a connected chain. Even if the receiver is a smart contract with a standard receive function, the withdraw function will not trigger a contract call. If you need to withdraw and call a contract on a connected chain, use the withdrawAndCall function instead.

The receiver is of type bytes to accommodate different address formats used by various chains (e.g., Bech32 for Bitcoin). This type ensures the receiver address is chain-agnostic. When withdrawing to an EVM chain, ensure you convert address to bytes.

The amount specifies the quantity to withdraw, and zrc20 is the ZRC-20 address of the token being withdrawn.

You don’t need to specify the destination chain since each ZRC-20 token is tied to the chain from which it was deposited. A ZRC-20 token can only be withdrawn to its originating chain. For example, to withdraw ZRC-20 USDC.ETH to the BNB chain, you must first swap it to ZRC-20 USDC.BNB.

To withdraw ZRC-20 tokens and call a contract on a connected chain, use the withdrawAndCall function:

function withdrawAndCall(bytes memory receiver, uint256 amount, address zrc20, bytes calldata message, CallOptions calldata callOptions, RevertOptions calldata revertOptions) external;

This function withdraws tokens and makes a call to a contract on the connected chain identified by the zrc20 address. For instance, if ZRC-20 ETH is withdrawn, the call is made to a contract on Ethereum.

To call a contract on a connected chain without withdrawing tokens, use the call function:

function call(bytes memory receiver, address zrc20, bytes calldata message, CallOptions calldata callOptions, RevertOptions calldata revertOptions) external;

Here, zrc20 represents the ZRC-20 token address of the gas token for the destination chain. This address acts as an identifier for the target chain. For example, to call a contract on Ethereum, use the ZRC-20 ETH token address.

The CallOptions parameter specifies details for making calls to contracts on connected chains. It is used in both the call and withdrawAndCall functions:

struct CallOptions {
    uint256 gasLimit;
    bool isArbitraryCall;
}
  • gasLimit: The maximum gas the cross-chain contract call can consume. If the gas usage exceeds this limit, the transaction reverts.
  • isArbitraryCall: Determines whether the call is "arbitrary" (true) or "authenticated" (false).

An arbitrary call invokes any function on a connected chain but does not retain the original caller's identity—within the target contract, msg.sender is the Gateway address, not the originating universal contract. This is suitable for scenarios like token swaps, where the caller’s identity is unnecessary.

An authenticated call specifically targets the onCall function of a contract on the connected chain. Authentication is achieved because the onCall function receives the context.sender parameter, referencing the originating universal contract. This allows the target contract to verify and trust the initiating universal app, rejecting unauthorized calls.

The message parameter in the withdrawAndCall and call functions contains the encoded function selector and arguments for the target contract:

  • Function Selector: The first 4 bytes of the Keccak-256 hash of the function signature.
  • Arguments: The remaining bytes, ABI-encoded according to Ethereum’s rules.

For example:

0xa777d0dc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000
  • Function Selector: 0xa777d0dc corresponds to hello(string).
  • Arguments: The remaining data represents the argument alice, encoded in hexadecimal (616c696365).

The RevertOptions struct specifies how assets are handled in case of a cross-chain transaction (CCTX) revert:

struct RevertOptions {
    address revertAddress;
    bool callOnRevert;
    address abortAddress;
    bytes revertMessage;
    uint256 onRevertGasLimit;
}
  • revertAddress: The address to return assets to if the transaction reverts.
  • callOnRevert: A flag indicating whether to call the onRevert function on the revertAddress.
  • abortAddress: The address to receive funds on ZetaChain if the CCTX aborts (not currently used).
  • revertMessage: Context passed to the onRevert function.
  • onRevertGasLimit: Gas limit for executing the onRevert function.

Revertable Contracts

Contracts implementing the onRevert function must conform to this interface:

struct RevertContext {
    address asset;
    uint64 amount;
    bytes revertMessage;
}
 
interface Revertable {
    function onRevert(RevertContext calldata revertContext) external;
}

This interface allows contracts to handle reverts dynamically, using the information provided in the RevertContext.