-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Gateway: Interacting with Universal Apps (#433)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Loading branch information
1 parent
46a1da6
commit d303316
Showing
14 changed files
with
393 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"intro": { | ||
"title": "Universal App Basics", | ||
"description": "What is a universal app and what makes it different" | ||
"description": "Build universal apps that can be called from any blockchain" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"zetachain": { | ||
"title": "ZetaChain", | ||
"description": "Make calls from universal apps and withdraw tokens to connected chains" | ||
}, | ||
"evm": { | ||
"title": "EVM Blockchains", | ||
"description": "Make calls to universal apps and deposit tokens from Ethereum, BNB, Polygon, Base and more" | ||
}, | ||
"solana": { | ||
"title": "Solana", | ||
"description": "Make calls to universal apps and deposit SOL from Solana" | ||
}, | ||
"bitcoin": { | ||
"title": "Bitcoin", | ||
"description": "Make calls to universal apps and deposit BTC from Bitcoin" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
To interact with universal apps from EVM chains (like Ethereum, BNB, Polygon, | ||
etc.) use the EVM gateway. | ||
|
||
EVM gateway supports: | ||
|
||
- depositing gas tokens to a universal app or an account on ZetaChain | ||
- depositing supported ERC-20 tokens (including ZETA tokens) | ||
- depositing gas tokens and calling a universal app | ||
- depositing supported ERC-20 tokens and calling a universal app | ||
- calling a universal app | ||
|
||
## Deposit Gas Tokens | ||
|
||
To deposit tokens to an EOA or a universal contract call the `deposit` function | ||
of the Gateway contract. | ||
|
||
```solidity | ||
deposit(address receiver, RevertOptions calldata revertOptions) external payable; | ||
``` | ||
|
||
The `deposit` function is payable, which means it accepts native gas tokens (for | ||
example, ETH on Ethereum), which will then be sent to a `receiver` on ZetaChain. | ||
|
||
The `receiver` is either an externally-owned account (EOA) or a universal app | ||
address on ZetaChain. Even if the receiver is a universal app contract with the | ||
standard `receive` function, the `deposit` function will not trigger a contract | ||
call. If you want to deposit and call a universal app, please, use the | ||
`depositAndCall` function, instead. | ||
|
||
After the deposit is processed, the receiver gets [ZRC-20 | ||
version](/developers/tokens/zrc20) of the deposited token, for example (ZRC-20 | ||
ETH). | ||
|
||
## Deposit ERC-20 Tokens | ||
|
||
The `deposit` function can also be used to send supported ERC-20 tokens to EOAs | ||
and universal apps on ZetaChain. | ||
|
||
```solidity | ||
deposit(address receiver, uint256 amount, address asset, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
Only [supported ERC-20 assets](/developers/tokens/zrc20) can be deposited. The | ||
receiver gets ZRC-20 version of the deposited token (for example, ZRC-20 | ||
USDC.ETH). | ||
|
||
The `amount` is the amount and `asset` is the token address of the ERC-20 that | ||
is being deposited. | ||
|
||
## Deposit Gas Tokens and Call a Universal App | ||
|
||
To deposit tokens and call a universal app contract use the `depositAndCall` | ||
function. | ||
|
||
```solidity | ||
depositAndCall(address receiver, bytes calldata payload, RevertOptions calldata revertOptions) external payable; | ||
``` | ||
|
||
After the cross-chain transaction is processed, the `onCrossChainCall` function | ||
of a universal app contract is executed. | ||
|
||
The `receiver` must be a universal app contract address. | ||
|
||
```solidity | ||
pragma solidity 0.8.7; | ||
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol"; | ||
contract UniversalApp is UniversalContract { | ||
function onCrossChainCall( | ||
zContext calldata context, | ||
address zrc20, | ||
uint256 amount, | ||
bytes calldata message | ||
) external virtual override { | ||
// ... | ||
} | ||
} | ||
``` | ||
|
||
`onCrossChainCall` receives: | ||
|
||
- `message`: value of the `payload` | ||
- `amount`: amount of deposited tokens | ||
- `zrc20`: ZRC-20 address of a the deposited tokens (for example, contract | ||
address of ZRC-20 ETH) | ||
- `context`: | ||
- `context.origin`: the original sender address on a connected chain (the EOA | ||
or contract that called the Gateway) | ||
- `context.chainID`: chain ID of the connected chain from which the call was | ||
made | ||
|
||
When calling a universal app, the payload contains bytes passed to | ||
`onCrossChainCall` as `message`. You don't need to pass a function selector in | ||
the payload as the only function that can be called from a connected chain is | ||
`onCrossChainCall`. | ||
|
||
## Deposit ERC-20 Tokens and Call a Universal App | ||
|
||
`depositAndCall` can also be used to call a universal app contract and send | ||
ERC-20 tokens. | ||
|
||
```solidity | ||
depositAndCall(address receiver, uint256 amount, address asset, bytes calldata payload, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
The `amount` is the amount and `asset` is the token address of the ERC-20 that | ||
is being deposited. | ||
|
||
In the current version of the protocol only one ERC-20 asset can be deposited at | ||
a time. | ||
|
||
## Call a Universal App | ||
|
||
To call a universal app (without depositing tokens), use the `call` function. | ||
|
||
```solidity | ||
call(address receiver, bytes calldata payload, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
## Revert Transactions | ||
|
||
For information on `RevertOptions` refer to the [ZetaChain "Revert Transactions" | ||
doc](/developers/chains/zetachain#revert-transactions). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
On Solana the gateway is implemented as a Solana program. | ||
|
||
Solana gateway supports: | ||
|
||
- depositing SOL to a universal app or an account on ZetaChain | ||
- depositing SOL and calling a universal app | ||
- depositing SPL tokens (coming soon) | ||
|
||
https://github.com/zeta-chain/protocol-contracts-solana/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
To make a call from a universal app to a contract on a connected chain or to | ||
withdraw tokens, use the ZetaChain gateway. | ||
|
||
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 to 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, call | ||
the `withdraw` function of the gateway contract. | ||
|
||
```solidity | ||
withdraw(bytes memory receiver, uint256 amount, address zrc20, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
The `receiver` is either an externally-owned account (EOA) or a contract on a | ||
connected chain. Even if the receiver is a smart contract with the standard | ||
`receive` function, the `withdraw` function will not trigger a contract call. If | ||
you want to withdraw and call a contract on a connected chain, please, use the | ||
`withdrawAndCall` function, instead. | ||
|
||
The `receiver` is of type `bytes`, because the receiver may be on a chain that | ||
uses a different address type, for example, bech32 on Bitcoin. `bytes` allow the | ||
receiver address to be chain agnostic. When withdrawing to a receiver on an EVM | ||
chain make sure that you convert `address` to `bytes`. | ||
|
||
The `amount` is the amount and `zrc20` is the ZRC-20 address of the token that | ||
is being withdrawn. | ||
|
||
You don't need to specify which chain to withdraw to, because each ZRC-20 has an | ||
associated chain from which it was deposited. A ZRC-20 token can be withdrawn | ||
only to the chain from which it was originally deposited. This means that if you | ||
want to withdraw ZRC-20 USDC.ETH to the BNB chain, you first have to swap it to | ||
ZRC-20 USDC.BNB. | ||
|
||
## Withdraw ZETA Tokens | ||
|
||
The `withdraw` function can also be used to withdraw ZETA tokens to a connected | ||
chain. | ||
|
||
``` | ||
withdraw(bytes memory receiver, uint256 amount, uint256 chainId, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
## Withdraw ZRC-20 Tokens and Call a Contract on Connected Chain | ||
|
||
To withdraw ZRC-20 tokens and make a call from a universal app to a contract on | ||
a connected chain use the `withdrawAndCall` function of the gateway contract. | ||
|
||
```solidity | ||
function withdrawAndCall(bytes memory receiver, uint256 amount, address zrc20, bytes calldata message, uint256 gasLimit, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
The tokens are withdrawn and a call is made to a contract on the connected chain | ||
identified by the `zrc20` address. For example, if ZRC-20 ETH is being | ||
withdrawn, then the call is made to a contract on Ethereum. | ||
|
||
## Withdraw ZETA Tokens and Call a Contract on Connected Chain | ||
|
||
The `withdrawAndCall` function can also be used to withdraw ZETA tokens and make | ||
a call from a universal app to a contract on a connected chain. | ||
|
||
```solidity | ||
withdrawAndCall(bytes memory receiver, uint256 amount, uint256 chainId, bytes calldata message, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
## Call a Contract on a Connected Chain | ||
|
||
To call a contract on a connected chain (without withdrawing tokens), use the | ||
`call` function. | ||
|
||
```solidity | ||
function call(bytes memory receiver, address zrc20, bytes calldata message, uint256 gasLimit, RevertOptions calldata revertOptions) external; | ||
``` | ||
|
||
`zrc20` represents the ZRC-20 token address of the gas token of the destination | ||
chain. In the context of this function `zrc20` address acts as an identifier for | ||
the chain to which the call is made. For example, to make a call to Ethereum, | ||
use ZRC-20 ETH token address. | ||
|
||
## Format of the `message` when Calling Contracts | ||
|
||
The `withdrawAndCall` and `call` functions have a `bytes calldata message` | ||
parameter. This parameter contains the function selector and the encoded | ||
arguments necessary to call a specific function in the target contract. | ||
|
||
The message parameter should contain: | ||
|
||
- Function selector: the first 8 bytes represent the function selector, which is | ||
the first 4 bytes of the Keccak-256 hash of the function signature. | ||
- Arguments: the remaining bytes in the message correspond to the arguments | ||
passed to the function, encoded according to Ethereum's ABI encoding rules. | ||
These arguments can vary in length depending on the data types. | ||
|
||
For example, consider the following message: | ||
|
||
``` | ||
0xa777d0dc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000 | ||
``` | ||
|
||
- Function Selector: `0xa777d0dc`. This corresponds to the function | ||
`hello(string)`. | ||
- Arguments: The remaining data | ||
(`0000000000000000000000000000000000000000000000000000000000000020...`) is the | ||
ABI-encoded argument passed to the `hello(string)` function. Specifically: | ||
`616c696365` represents the string `alice` in hexadecimal. | ||
|
||
## Revert Transactions | ||
|
||
The `RevertOptions` struct defines how assets should be handled in the event of | ||
a cross-chain transaction (CCTX) reverting: | ||
|
||
```solidity | ||
struct RevertOptions { | ||
address revertAddress; | ||
bool callOnRevert; | ||
address abortAddress; | ||
bytes revertMessage; | ||
uint256 onRevertGasLimit; | ||
} | ||
``` | ||
|
||
`revertAddress`: the address that should get assets back if the CCTX reverts. | ||
For example, if a smart contract using ZetaChain wants to send assets back to | ||
the sender upon a revert, `revertAddress` should be set to `msg.sender`. | ||
|
||
`callOnRevert`: a boolean flag indicating whether the `onRevert` function should | ||
be called on the `revertAddress`. For example, a smart contract may want to | ||
execute custom logic when a revert occurs, such as unlocking tokens. In this | ||
case, the contract would set `callOnRevert` to true and assign `revertAddress` | ||
to `address(this)`. | ||
|
||
`abortAddress`: the address that will receive the funds on ZetaChain if the CCTX | ||
aborts. This feature is not currently used. | ||
|
||
`revertMessage`: message sent back to the `onRevert` function. This allows | ||
additional context to be provided for handling the revert. | ||
|
||
`onRevertGasLimit`: the gas limit to be used when executing the `onRevert` | ||
function. | ||
|
||
Contracts that implement the `onRevert` functionality are referred to as | ||
`Revertable` contracts. These contracts should conform to the following | ||
interface: | ||
|
||
```solidity | ||
struct RevertContext { | ||
address asset; | ||
uint64 amount; | ||
bytes revertMessage; | ||
} | ||
interface Revertable { | ||
function onRevert(RevertContext calldata revertContext) external; | ||
} | ||
``` | ||
|
||
This interface allows the contract to handle reverts in a customized way, based | ||
on the context provided through the `RevertContext` struct. |
Oops, something went wrong.