diff --git a/src/pages/developers/_meta.json b/src/pages/developers/_meta.json index 693405bf..1e0b3094 100644 --- a/src/pages/developers/_meta.json +++ b/src/pages/developers/_meta.json @@ -11,6 +11,10 @@ "title": "Universal EVM", "description": "EVM enhanced with omnichain interoperability features, enabling the development of robust universal apps." }, + "chains": { + "title": "Connected Blockchains", + "description": "Use Gateway to make calls to and from universal apps, deposit and withdraw tokens." + }, "tutorials": { "title": "Tutorials", "description": "Step-by-step guides to help you master building on ZetaChain." diff --git a/src/pages/developers/apps/_meta.json b/src/pages/developers/apps/_meta.json index b856063f..c81fb694 100644 --- a/src/pages/developers/apps/_meta.json +++ b/src/pages/developers/apps/_meta.json @@ -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" } } \ No newline at end of file diff --git a/src/pages/developers/apps/intro.mdx b/src/pages/developers/apps/intro.mdx index 9b83b779..3a191411 100644 --- a/src/pages/developers/apps/intro.mdx +++ b/src/pages/developers/apps/intro.mdx @@ -27,11 +27,11 @@ gain powerful omnichain capabilities. Here's an example universal app: ```solidity -pragma solidity 0.8.7; +pragma solidity 0.8.26; -import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol"; +import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol"; -contract UniversalApp is zContract { +contract UniversalApp is UniversalContract { function onCrossChainCall( zContext calldata context, address zrc20, @@ -146,8 +146,8 @@ choosing), the gas fees will be covered. chains - can trigger contract calls and token transfers to connected chains - can automatically handle gas for cross-chain transactions - - are fully compatible with EVM chains (like Ethereum and BNB), Bitcoin. - Support for Polygon, Solana, Cosmos (through IBC) and other chains is coming - soon. + - are fully compatible with EVM chains (like Ethereum, BNB, and Polygon), + Bitcoin, Solana. Support for TON and Cosmos (through IBC) and other chains + is coming soon. - Native gas and supported ERC-20 tokens are represented as ZRC-20 tokens. A ZRC-20 token can be permissionlessly withdrawn back to its original chain. diff --git a/src/pages/developers/chains/_meta.json b/src/pages/developers/chains/_meta.json new file mode 100644 index 00000000..55852c4f --- /dev/null +++ b/src/pages/developers/chains/_meta.json @@ -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" + } +} \ No newline at end of file diff --git a/src/pages/developers/evm/bitcoin.mdx b/src/pages/developers/chains/bitcoin.mdx similarity index 91% rename from src/pages/developers/evm/bitcoin.mdx rename to src/pages/developers/chains/bitcoin.mdx index c3c4ff9e..ab45faa1 100644 --- a/src/pages/developers/evm/bitcoin.mdx +++ b/src/pages/developers/chains/bitcoin.mdx @@ -4,6 +4,15 @@ title: Call Universal Apps from Bitcoin import { Alert } from "~/components/shared"; +On Bitcoin the gateway is implemented as an TSS MPC account. The private key +securing the account is split into fragments and distributed among ZetaChain +observer-signer validators. + +Bitcoin gateway supports: + +- depositing BTC to a universal app or an account on ZetaChain +- depositing BTC and calling a universal app + ## Overview To deposit BTC into ZetaChain's Universal EVM (and optionally call a smart diff --git a/src/pages/developers/chains/evm.mdx b/src/pages/developers/chains/evm.mdx new file mode 100644 index 00000000..42e1ec65 --- /dev/null +++ b/src/pages/developers/chains/evm.mdx @@ -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). diff --git a/src/pages/developers/chains/solana.mdx b/src/pages/developers/chains/solana.mdx new file mode 100644 index 00000000..3c2b2ab5 --- /dev/null +++ b/src/pages/developers/chains/solana.mdx @@ -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/ diff --git a/src/pages/developers/chains/zetachain.mdx b/src/pages/developers/chains/zetachain.mdx new file mode 100644 index 00000000..72e7e8b6 --- /dev/null +++ b/src/pages/developers/chains/zetachain.mdx @@ -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. diff --git a/src/pages/developers/evm/_meta.json b/src/pages/developers/evm/_meta.json index a7299c57..2cb13a34 100644 --- a/src/pages/developers/evm/_meta.json +++ b/src/pages/developers/evm/_meta.json @@ -1,16 +1,12 @@ { - "system-contract": { - "title": "System Contract", - "description": "Stores useful values and functions used by universal apps" + "gateway": { + "title": "Gateway", + "description": "A single point of entry for interacting with universal apps" }, "connector": { "title": "Connector Contract", "description": "Enables message passing and ZETA transfer to and from universal apps" }, - "bitcoin": { - "title": "Bitcoin Interoperability", - "description": "Learn about how universal apps can be called from Bitcoin" - }, "gas": { "title": "Gas Fees", "description": "Learn about ZRC-20 withdraw fees, message passing fees" diff --git a/src/pages/developers/evm/gateway.mdx b/src/pages/developers/evm/gateway.mdx new file mode 100644 index 00000000..0e90a150 --- /dev/null +++ b/src/pages/developers/evm/gateway.mdx @@ -0,0 +1,52 @@ +Gateway is an interface that serves as a unified entry point for interactions +between contracts on connected chains and universal apps on ZetaChain. + +## Gateway on Connected Chains + +The gateway on connected chains (like Ethereum, Solana and Bitcoin) facilitates +incoming transactions: contract calls and token transfers from connected chains +to universal apps on ZetaChain. + +The implementation of the gateway depends on the connected chain: + +- EVM chains: a gateway smart contract +- Solana: a gateway program +- Bitcoin: a TSS MPC gateway address managed by a network of observer-signer + validators + +Each chain has only one gateway. The same gateway is used to interact with all +universal apps. + +Gateway supports the following features: + +- depositing native gas tokens to a universal app or an account on ZetaChain +- depositing supported ERC-20 tokens (including ZETA tokens) to a universal app + or an account on ZetaChain +- depositing native gas tokens and making a contract call (with arbitrary data + passing) to a universal app +- depositing supported ERC-20 tokens and making a contract call (with arbitrary + data passing) to a universal app +- making a contract call (with arbitrary data passing) to a universal app + +These features may vary depending on each specific connected chain. For example, +deposits from Bitcoin can only be made in native gas token (BTC). And deposits +from Solana can be made in SOL and (soon) SPL tokens. + +Currently, only one asset can be deposited at a time to a universal app. Support +for multi-asset deposits will be added in the future updates to the protocol. + +## Gateway on ZetaChain + +Gateway on ZetaChain facilitates outgoing transactions: calls and token +withdrawals from universal apps to contracts on connected chains. + +Gateway supports the following features: + +- withdrawing ZRC-20 tokens as native gas or ERC-20 tokens to connected chains +- withdrawing ZETA tokens to a connected chain +- withdrawing tokens to and making a contract call on a connected chain +- making a contract call on a connected chain + +Currently, only one asset can be withdrawn at a time from a universal app. +Support for multi-asset withdrawals will be added in the future updates to the +protocol. diff --git a/src/pages/developers/evm/system-contract.mdx b/src/pages/developers/evm/system-contract.mdx deleted file mode 100644 index 6bbe84a2..00000000 --- a/src/pages/developers/evm/system-contract.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: System Contract ---- - -The System Contract on ZetaChain serves as the caller for universal apps when -they are called from connected chains. - -| Network | System contract address | -| ------------ | ------------------------------------------ | -| Testnet | 0xEdf1c3275d13489aCdC6cD6eD246E72458B8795B | -| Mainnet Beta | 0x91d18e54DAf4F677cB28167158d6dd21F6aB3921 | - -The `onlySystem` modifier must be applied to the `onCrossChainCall` function to -ensure that only the system contract can call this function. - -Useful values and functions in the system contract: - -- `wZetaContractAddress`: wrapped ZETA address. -- `uniswapv2Router02Address`: address of the Uniswap v2 router, which powers the - internal liquidity pools. -- `uniswapv2FactoryAddress`: address of the Uniswap v2 factory. -- `gasZetaPoolByChainId`: returns a pool address of ZETA and a gas token of the - specified chain. -- `gasCoinZRC20ByChainId`: returns a ZRC-20 address of the gas token of the - specified chain. -- `gasPriceByChainId`: helper to estimate gas for transactions on connected - chains. -- `zetaConnectorZEVMAddress`: address of the connector contract. (please, note - that the connector contract will be deprecated in the future) - -The system contract is inherited from `ZetaChain`, making it easily accessible -from your universal app contract: - -```solidity -pragma solidity 0.8.7; - -import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IZRC20.sol"; -import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol"; - -contract YourContract is zContract { - function onCrossChainCall( - zContext calldata context, - address zrc20, - uint256 amount, - bytes calldata message - ) external virtual override { - // systemContract.gasCoinZRC20ByChainId(context.chainID) - } -} -``` - -To get the system contract address in a client-side application or script, use -the `getAddress` function: - -```ts -import { getAddress } from "@zetachain/protocol-contracts"; - -const SYSTEM_CONTRACT = getAddress("systemContract", "zeta_testnet"); -``` diff --git a/src/pages/developers/tutorials/bitcoin.mdx b/src/pages/developers/tutorials/bitcoin.mdx index f6c857a5..72c0fda5 100644 --- a/src/pages/developers/tutorials/bitcoin.mdx +++ b/src/pages/developers/tutorials/bitcoin.mdx @@ -13,7 +13,7 @@ description: In this tutorial you will learn how to build a simple frontend appl - [Node.js](https://nodejs.org/en/) installed on your machine with `npm` or `yarn` - Learn how to [Deposit and call ZetaChain's EVM contracts from - Bitcoin](/developers/evm/bitcoin/). + Bitcoin](/developers/chains/bitcoin/). ## Create a new project @@ -68,7 +68,7 @@ This HTML page contains a simple form with three inputs: To call an omnichain contract from Bitcoin you need to send a token transfer transaction to the ZetaChain's [TSS address](/reference/network/contracts) on Bitcoin with a memo that conforms to [the required -format](/developers/evm/bitcoin). +format](/developers/chains/bitcoin). The memo is composed of two parts: diff --git a/src/pages/developers/tutorials/hello.mdx b/src/pages/developers/tutorials/hello.mdx index de129c65..410b1dea 100644 --- a/src/pages/developers/tutorials/hello.mdx +++ b/src/pages/developers/tutorials/hello.mdx @@ -113,7 +113,7 @@ contract Greeting is zContract, OnlySystem { interface](https://github.com/zeta-chain/protocol-contracts/blob/main/contracts/zevm/interfaces/zContract.sol). The contract declares a state variable of type `SystemContract` that stores a -reference to the [system contract](/developers/evm/system-contract). +reference to the system contract. The constructor function accepts the address of the system contract and stores it in the `systemContract` state variable. diff --git a/src/pages/reference/apps/wallets.mdx b/src/pages/reference/apps/wallets.mdx index 1795f0de..c7c9aace 100644 --- a/src/pages/reference/apps/wallets.mdx +++ b/src/pages/reference/apps/wallets.mdx @@ -25,7 +25,7 @@ page](/reference/network/details). In order to interact with ZetaChain from Bitcoin, you'll need a wallet that meets certain criteria. You can learn more about it in the [Bitcoin -section](/developers/evm/bitcoin) of the docs. +section](/developers/chains/bitcoin) of the docs. Supported wallets: