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.
Withdraw ZRC-20 Tokens
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.
Withdraw ZRC-20 Tokens and Call a Contract on a Connected Chain
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.
Call a Contract on a Connected Chain
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.
Call Options
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.
Format of the message
Parameter
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 tohello(string)
. - Arguments: The remaining data represents the argument
alice
, encoded in hexadecimal (616c696365
).
Revert Transactions
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 theonRevert
function on therevertAddress
.abortAddress
: The address to receive funds on ZetaChain if the CCTX aborts (not currently used).revertMessage
: Context passed to theonRevert
function.onRevertGasLimit
: Gas limit for executing theonRevert
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
.