From bc7bafb4fad6daeb919ff15e1147b72076b63464 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 10:30:01 +0300 Subject: [PATCH 01/13] update hello --- src/pages/developers/tutorials/_meta.json | 17 +- src/pages/developers/tutorials/hello.mdx | 134 +------ src/pages/developers/tutorials/swap-any.mdx | 10 +- src/pages/developers/tutorials/swap-tss.mdx | 381 -------------------- src/pages/developers/tutorials/swap.mdx | 11 +- 5 files changed, 26 insertions(+), 527 deletions(-) delete mode 100644 src/pages/developers/tutorials/swap-tss.mdx diff --git a/src/pages/developers/tutorials/_meta.json b/src/pages/developers/tutorials/_meta.json index 7b03b164..fc29798a 100644 --- a/src/pages/developers/tutorials/_meta.json +++ b/src/pages/developers/tutorials/_meta.json @@ -5,24 +5,19 @@ "description": "Learn how to set up a smart contract template, create an account, and use faucet" }, "hello": { - "title": "First Universal App on Localnet", + "title": "Message Passing", "readTime": "30 min", - "description": "Learn how to create, deploy and interact with a universal app" - }, - "swap-tss": { - "title": "Swap on Testnet", - "readTime": "30 min", - "description": "Implement an omnichain swap app compatible with chains like Ethereum, BNB and Bitcoin" + "description": "Learn the fundamentals of message passing and cross-chain contract calls" }, "swap": { - "title": "Swap on Localnet", + "title": "Swap", "readTime": "30 min", - "description": "Implement an omnichain swap app compatible with chains like Ethereum, BNB and Bitcoin" + "description": "Implement a universal swap app compatible with chains like Ethereum, Solana and Bitcoin" }, "swap-any": { - "title": "Swap Any Token on Localnet", + "title": "Swap Any Token", "readTime": "60 min", - "description": "Enhance the omnichain swap app with the ability to swap to any token" + "description": "Enhance the universal swap app with the ability to swap to any token" }, "localnet": { "title": "Localnet", diff --git a/src/pages/developers/tutorials/hello.mdx b/src/pages/developers/tutorials/hello.mdx index 48f09197..4e8726c2 100644 --- a/src/pages/developers/tutorials/hello.mdx +++ b/src/pages/developers/tutorials/hello.mdx @@ -1,5 +1,5 @@ --- -title: Your First Universal App +title: Message Passing --- import { Alert } from "~/components/shared"; @@ -17,11 +17,7 @@ By the end of this tutorial, you will have learned how to: blockchain in localnet. - Gracefully handle reverts by implementing revert logic. - - {" "} - This tutorial relies on the gateway, which is currently available only on localnet. It will support testnet once the gateway - is deployed there. Therefore, deploying this tutorial on testnet is not possible at this time. - +This tutorial relies on the Gateway, which is currently available only on localnet and testnet. ## Prerequisites @@ -69,8 +65,8 @@ contract Hello is UniversalContract { gateway = GatewayZEVM(gatewayAddress); } - function onCrossChainCall( - zContext calldata context, + function onCall( + MessageContext calldata context, address zrc20, uint256 amount, bytes calldata message @@ -91,9 +87,8 @@ contract Hello is UniversalContract { RevertOptions memory revertOptions ) external { (, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit); - if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee)) { + if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee)) revert TransferFailed(); - } IZRC20(zrc20).approve(address(gateway), gasFee); gateway.call(receiver, zrc20, message, gasLimit, revertOptions); } @@ -277,7 +272,7 @@ With localnet running, open a new terminal window to compile and deploy the `Hello` and `Echo` contracts: ```bash -yarn deploy +yarn deploy:localnet ``` You should see output indicating the successful deployment of the contracts: @@ -286,12 +281,12 @@ You should see output indicating the successful deployment of the contracts: ๐Ÿ”‘ Using account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ๐Ÿš€ Successfully deployed "Hello" contract on localhost. -๐Ÿ“œ Contract address: 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E +๐Ÿ“œ Contract address: 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB ๐Ÿ”‘ Using account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ๐Ÿš€ Successfully deployed "Echo" contract on localhost. -๐Ÿ“œ Contract address: 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 +๐Ÿ“œ Contract address: 0x9E545E3C0baAB3E08CdfD552C960A1050f373042 ``` **Note**: The deployed contract addresses may differ in your environment. @@ -304,8 +299,8 @@ command, replacing the contract addresses with those from your deployment: ```bash npx hardhat echo-call \ - --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ - --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ + --contract 0x9E545E3C0baAB3E08CdfD552C960A1050f373042 \ + --receiver 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB \ --network localhost \ --types '["string"]' alice ``` @@ -328,55 +323,6 @@ npx hardhat echo-call \ - **ZetaChain**: The `Hello` contract decodes the message and emits a `HelloEvent`. -## Simulating a Revert - -To demonstrate how reverts are handled, let's intentionally send incorrect data. -Instead of a `string`, we'll send a `uint256`: - -```bash -npx hardhat echo-call \ - --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ - --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ - --network localhost \ - --types '["uint256"]' 42 -``` - -**What Happens:** - -- The `Hello` contract's `onCrossChainCall` attempts to decode a `uint256` as a - `string`, causing `abi.decode` to fail and revert the transaction. -- The EVM chain detects the revert, and the transaction does not execute the - intended logic. - -## Handling a Revert - -To handle reverts gracefully, configure the gateway to call the `Echo` contract -on the source chain upon a revert: - -```bash -npx hardhat echo-call \ - --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ - --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ - --network localhost \ - --revert-address 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ - --revert-message 0x \ - --call-on-revert \ - --types '["uint256"]' 42 -``` - -**Parameters:** - -- `--revert-address`: Address of the `Echo` contract on the source EVM chain. -- `--revert-message`: Data to pass to the `Echo` contract's `onRevert` function. -- `--call-on-revert`: Flag indicating that the gateway should invoke a contract - upon revert. - -**What Happens:** - -- When the revert occurs, the gateway invokes the `Echo` contract's `onRevert` - function on the EVM chain. -- This allows you to handle the error gracefully within your application logic. - ## Calling an EVM Contract from a Universal App Now, let's perform the reverse operation: calling a contract on a connected EVM @@ -386,8 +332,8 @@ from your deployment: ```bash npx hardhat hello-call \ - --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ - --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ + --contract 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB \ + --receiver 0x9E545E3C0baAB3E08CdfD552C960A1050f373042 \ --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe \ --function "hello(string)" \ --network localhost \ @@ -406,58 +352,6 @@ npx hardhat hello-call \ - `--types`: ABI types of the message parameters. - `alice`: The message to send. -## Simulating a Revert - -To simulate a revert when calling an EVM contract from ZetaChain, send incorrect -data types: - -```bash -npx hardhat hello-call \ - --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ - --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ - --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe \ - --function "hello(string)" \ - --network localhost \ - --types '["uint256"]' 42 -``` - -**What Happens:** - -- The `Echo` contract expects a `string` but receives a `uint256`, causing the - function to fail and revert the transaction. - -## Handling a Revert - -To handle reverts gracefully when calling an EVM contract from ZetaChain, -include revert parameters: - -```bash -npx hardhat hello-call \ - --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ - --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ - --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe \ - --function "hello(string)" \ - --network localhost \ - --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ - --revert-message 0x \ - --call-on-revert \ - --types '["uint256"]' 42 -``` - -**Parameters:** - -- `--revert-address`: Address of the `Hello` contract on ZetaChain. -- `--revert-message`: Data to pass to the `Hello` contract's `onRevert` - function. -- `--call-on-revert`: Flag indicating that the gateway should invoke a contract - upon revert. - -**What Happens:** - -- Upon revert, the gateway calls the `onRevert` function of the `Hello` contract - on ZetaChain. -- This allows you to handle the error within your ZetaChain application. - ## Withdrawing and Calling an EVM Contract from a Universal App To withdraw tokens and call a contract on a connected chain from a universal @@ -465,8 +359,8 @@ app, run the following command: ```bash npx hardhat hello-withdraw-and-call \ - --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E \ - --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 \ + --contract 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB \ + --receiver 0x9E545E3C0baAB3E08CdfD552C960A1050f373042 \ --zrc20 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c \ --function "hello(string)" \ --amount 1 \ diff --git a/src/pages/developers/tutorials/swap-any.mdx b/src/pages/developers/tutorials/swap-any.mdx index 2952016b..083cdf01 100644 --- a/src/pages/developers/tutorials/swap-any.mdx +++ b/src/pages/developers/tutorials/swap-any.mdx @@ -22,11 +22,7 @@ In this enhanced version, you will modify the original swap contract to support this additional functionality. You will also deploy the modified contract to localnet and interact with it by swapping tokens from a connected EVM chain. - - {" "} - This tutorial depends on the gateway, which is available on localnet but not yet deployed on testnet. It will be compatible - with testnet after the gateway is deployed. In other words, you cannot deploy this tutorial on testnet yet.{" "} - +This tutorial relies on the Gateway, which is currently available only on localnet and testnet. ## Setting Up Your Environment @@ -80,8 +76,8 @@ contract SwapToAnyToken is UniversalContract { bool withdraw; } - function onCrossChainCall( - zContext calldata context, + function onCall( + MessageContext calldata context, address zrc20, uint256 amount, bytes calldata message diff --git a/src/pages/developers/tutorials/swap-tss.mdx b/src/pages/developers/tutorials/swap-tss.mdx deleted file mode 100644 index e932358c..00000000 --- a/src/pages/developers/tutorials/swap-tss.mdx +++ /dev/null @@ -1,381 +0,0 @@ ---- -title: Swap on Testnet ---- - -import { Alert } from "~/components/shared"; - -In this tutorial you will create a cross-chain swap contract. This contract will -enable users to exchange a native gas token or a supported ERC-20 token from one -connected blockchain for a token on another blockchain. For example, a user will -be able to swap USDC from Ethereum to BTC on Bitcoin in a single transaction. - - - {" "} - This tutorial features architecture that is compatible with the current ZetaChain testnet, but will be phased out once - the [gateway](/developers/evm/gateway) is released. For a gateway compatible localnet-only example check out [Swap on Localnet](/developers/tutorials/swap) - - -You will learn how to: - -- Decode incoming messages from both EVM chains and Bitcoin. -- Work with the ZRC-20 representation of tokens transferred from connected - chains. -- Use the swap helper function to swap tokens using Uniswap v2 pools. -- Withdraw ZRC-20 tokens to a connected chain, accounting for cross-chain gas - fees. - -The swap contract will be implemented as a universal app and deployed on -ZetaChain. - -Universal apps can accept token transfers and contract calls from connected -chains. Tokens transferred from connected chains to a universal app contract are -represented as [ZRC-20](/developers/tokens/zrc20). For example, ETH transferred -from Ethereum is represented as ZRC-20 ETH. ZRC-20 tokens have the unique -property of being able to be withdrawn back to their original chain as native -assets. - -The swap contract will: - -- Accept a contract call from a connected chain containing native gas or - supported ERC-20 tokens and a message. -- Decode the message, which should include: - - Target token address (represented as ZRC-20) - - Recipient address on the destination chain -- Query withdraw gas fee of the target token. -- Swap a fraction of the input token for a ZRC-20 gas tokens to cover the - withdrawal fee using the Uniswap v2 liquidity pools. -- Swap the remaining input token amount for the target token ZRC-20. -- Withdraw ZRC-20 tokens to the destination chain - - - -## Set Up Your Environment - -Clone the Hardhat contract template: - -``` -git clone https://github.com/zeta-chain/template - -cd template/contracts - -yarn -``` - -Make sure that you've followed the [Getting -Started](/developers/tutorials/intro) tutorial to set up your development -environment, create an account and request testnet tokens. - -## Create the contract - -Run the following command to create a new universal omnichain contract called -`Swap` with two values in the message: target token address and recipient. - -``` -npx hardhat omnichain Swap targetToken:address recipient -``` - -## Universal App Contract - -```solidity filename="contracts/Swap.sol" {6-7,12,18-21,29-45,48-78} -// SPDX-License-Identifier: MIT -pragma solidity 0.8.7; - -import "@zetachain/protocol-contracts/contracts/zevm/SystemContract.sol"; -import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol"; -import "@zetachain/toolkit/contracts/SwapHelperLib.sol"; -import "@zetachain/toolkit/contracts/BytesHelperLib.sol"; -import "@zetachain/toolkit/contracts/OnlySystem.sol"; - -contract Swap is zContract, OnlySystem { - SystemContract public systemContract; - uint256 constant BITCOIN = 18332; - - constructor(address systemContractAddress) { - systemContract = SystemContract(systemContractAddress); - } - - struct Params { - address target; - bytes to; - } - - function onCrossChainCall( - zContext calldata context, - address zrc20, - uint256 amount, - bytes calldata message - ) external virtual override onlySystem(systemContract) { - Params memory params = Params({target: address(0), to: bytes("")}); - - if (context.chainID == BITCOIN) { - params.target = BytesHelperLib.bytesToAddress(message, 0); - params.to = abi.encodePacked( - BytesHelperLib.bytesToAddress(message, 20) - ); - } else { - (address targetToken, bytes memory recipient) = abi.decode( - message, - (address, bytes) - ); - params.target = targetToken; - params.to = recipient; - } - - swapAndWithdraw(zrc20, amount, params.target, params.to); - } - - function swapAndWithdraw( - address inputToken, - uint256 amount, - address targetToken, - bytes memory recipient - ) internal { - uint256 inputForGas; - address gasZRC20; - uint256 gasFee; - - (gasZRC20, gasFee) = IZRC20(targetToken).withdrawGasFee(); - - inputForGas = SwapHelperLib.swapTokensForExactTokens( - systemContract, - inputToken, - gasFee, - gasZRC20, - amount - ); - - uint256 outputAmount = SwapHelperLib.swapExactTokensForTokens( - systemContract, - inputToken, - amount - inputForGas, - targetToken, - 0 - ); - - IZRC20(gasZRC20).approve(targetToken, gasFee); - IZRC20(targetToken).withdraw(recipient, outputAmount); - } -} -``` - -### Decoding the Message - -Create a `Params` struct, which will hold two values: - -- `address target`: target token ZRC-20 address. -- `bytes to`: recipient address on the destination chain. We're using `bytes`, - because the recipient can be either on EVM (like Ethereum or BNB) or on - Bitcoin. - -First, decode the incoming `message` to get the parameter values. The message -might be encoded differently depending on the source chain. For example, on -Bitcoin there is a upper limit of 80 bytes, so you might want to encode the -message in the most efficient way possible. On EVM don't have this limit, so -it's fine to use `abi.encode` to encode the message. - -Use `context.chainID` to determine the connected chain from which the contract -is called. - -If it's Bitcoin, the first 20 bytes of the `message` are the `params.target` -encoded as an `address`. Use `bytesToAddress` helper method to get the target -token address. To get the recipient address, use the same helper method with an -offset of 20 bytes and then use `abi.encodePacked` to convert the address to -`bytes`. - -If it's an EVM chain, use `abi.decode` to decode the `message` into the -`params.target` and `params.to`. - -### Swap and Withdraw Function - -#### Swapping for Gas Token - -Create a new function called `swapAndWithdraw`. Use the `withdrawGasFee` method -of the target token ZRC-20 to get the gas fee token address and the gas fee -amount. If the target token is the gas token of the destination chain (for -example, BNB), `gasZRC20` will be the same `params.target`. However, if the -target token is an ERC-20, like USDC on BNB, `gasZRC20` will tell you the -address of the ZRC-20 of the destination chain. - -Use the `swapTokensForExactTokens` helper method to swap the incoming token for -the gas coin using the internal liquidity pools. The method returns the amount -of the incoming token that was used to pay for the gas. - -#### Swapping for Target Token - -Next, swap the incoming amount minus the amount spent swapping for a gas fee for -the target token on the destination chain using the `swapExactTokensForTokens` -helper method. - -#### Withdraw Target Token to Connected Chain - -At this point the contract has the required `gasFee` amount of `gasZRC20` token -of the connected chain and an `outputAmount` amount of `params.target` token. - -To withdraw tokens to a connected chain you will be calling the `withdraw` -method of ZRC-20. The `withdraw` method expects the caller (in our case the -contract) to have the required amount of gas tokens ZRC-20. Approve the target -token ZRC-20 contract to spend the `gasFee` amount. Finally, call the `withdraw` -method of the target token ZRC-20 to send the tokens to the recipient on the -connected chain. - - - {" "} - Note that you don't have to tell which chain to withdraw to because each ZRC-20 contract knows which connected chain it - is associated with. For example, ZRC-20 Ethereum USDC can only be withdrawn to Ethereum. - - -## Update the Interact Task - -In the `interact` task generated for us by the contract template the recipient -is encoded as string. Our contract, however, expects the recipient to be encoded -as `bytes` to ensure that both EVM and Bitcoin addresses are supported. - -To support both EVM and Bitcoin addresses, we need to check if the recipient is -a valid Bitcoin address. If it is, we need to encode it as `bytes` using -`utils.solidityPack`. - -If itโ€™s not a valid bech32 address, then we assume it's an EVM address and use -`args.recipient` as the value for the recipient. - -Finally, update the `prepareData` function call to use the `bytes` type for the -recipient. - -```ts filename="tasks/interact.ts" {1,6-22} -import bech32 from "bech32"; - -const main = async (args: any, hre: HardhatRuntimeEnvironment) => { - const [signer] = await hre.ethers.getSigners(); - - let recipient; - try { - if (bech32.decode(args.recipient)) { - recipient = utils.solidityPack(["bytes"], [utils.toUtf8Bytes(args.recipient)]); - } - } catch (e) { - recipient = args.recipient; - } - - const data = prepareData(args.contract, ["address", "bytes"], [args.targetToken, recipient]); - //... -}; -``` - -## Create an Account and Request Tokens from the Faucet - -Before proceeding with the next steps, make sure you have [created an account -and requested ZETA tokens](/developers/tutorials/hello#create-an-account) from -the faucet. - -## Compile and Deploy the Contract - -``` -npx hardhat compile --force -``` - -``` -npx hardhat deploy --network zeta_testnet -``` - -``` -๐Ÿ”‘ Using account: 0x2cD3D070aE1BD365909dD859d29F387AA96911e1 - -๐Ÿš€ Successfully deployed contract on ZetaChain. -๐Ÿ“œ Contract address: 0xf6CDd83AB44E4d947FE52c2637ee4A04F330328E -๐ŸŒ Explorer: https://athens3.explorer.zetachain.com/address/0xf6CDd83AB44E4d947FE52c2637ee4A04F330328E -``` - -## Swap Native Gas Tokens Between EVM Chains - -Use the `interact` task to perform a cross-chain swap. In this example, we're -swapping native sETH from Sepolia for BNB on BNB chain. The contract will -deposit sETH to ZetaChain as ZRC-20, swap it for ZRC-20 BNB and then withdraw -native BNB to the BNB chain. To get the value of the `--target-token` find the -ZRC-20 contract address of the destination token in the [ZRC-20 section of the -docs](/developers/tokens/zrc20). - -``` -npx hardhat interact --contract 0x175DeE06ca605674e49F1FADfC6B399D6ab31726 --amount 0.3 --network sepolia_testnet --target-token 0xd97B1de3619ed2c6BEb3860147E30cA8A7dC9891 --recipient 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 -``` - -``` -๐Ÿ”‘ Using account: 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 - -๐Ÿš€ Successfully broadcasted a token transfer transaction on sepolia_testnet -network. ๐Ÿ“ Transaction hash: -0xc4b2bbd3b3090e14797463af1965a00318cc39a50fce53a5d5856d09fe67410d -``` - -Track your cross-chain transaction: - -``` -npx hardhat cctx -0xc4b2bbd3b3090e14797463af1965a00318cc39a50fce53a5d5856d09fe67410d -``` - -``` -โœ“ CCTXs on ZetaChain found. - -โœ“ 0xf6419c8d850314a436a3cfc7bc5cd487e29bad9c8fae0d8be9a913d622599980: 11155111 โ†’ 7001: OutboundMined (Remote omnich -ain contract call completed) -โ ง 0x5e533d781ddc9760784ba9c1887f77a80d3ca0d771ea41f02bc4d0a1c9412dc2: 7001 โ†’ 97: PendingOutbound (ZRC20 withdrawal -event setting to pending outbound directly) -``` - -## Swap ERC-20 Tokens Between EVM Chains - -Now let's swap USDC from Sepolia to BNB on BNB chain. To send USDC specify the -ERC-20 token contract address (on Sepolia) in the `--token` parameter. You can -find the address of the token in the [ZRC-20 section of the -docs](/developers/tokens/zrc20). - -``` -npx hardhat interact --contract 0xf6CDd83AB44E4d947FE52c2637ee4A04F330328E --amount 5 --token 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238 --network sepolia_testnet --target-token 0xd97B1de3619ed2c6BEb3860147E30cA8A7dC9891 --recipient 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 -``` - -``` -๐Ÿ”‘ Using account: 0x2cD3D070aE1BD365909dD859d29F387AA96911e1 - -๐Ÿš€ Successfully broadcasted a token transfer transaction on sepolia_testnet network. -๐Ÿ“ Transaction hash: 0xce8832232639d29d40078e14d0a5b20c055123d6df1e1d39f90cfd130c33466d -``` - -``` -npx hardhat cctx 0xce8832232639d29d40078e14d0a5b20c055123d6df1e1d39f90cfd130c33466d -``` - -``` -โœ“ CCTXs on ZetaChain found. - -โœ“ 0x1ae1436358ef755c1c782d0a249ae99e857b0aecb91dcd8da4a4e7171f5d9459: 11155111 โ†’ 7001: OutboundMined (Remote omnichain contract call completed) -โœ“ 0xbefe99d3e17d16fc88762f85b1becd1396b01956c04b5ec037abc2c63d821caa: 7001 โ†’ 97: OutboundMined (ZRC20 withdrawal event setting to pending outbound directly : Outbound succeeded, mined) -``` - -## Swap from Bitcoin - -Use the `send-btc` task to send Bitcoin to the TSS address with a memo. The memo -should contain the following: - -- Omnichain contract address on ZetaChain: - `175DeE06ca605674e49F1FADfC6B399D6ab31726` -- Target token address: `05BA149A7bd6dC1F937fA9046A9e05C05f3b18b0` -- Recipient address: `4955a3F38ff86ae92A914445099caa8eA2B9bA32` - -``` -npx hardhat send-btc --amount 0.001 --memo 175DeE06ca605674e49F1FADfC6B399D6ab3172605BA149A7bd6dC1F937fA9046A9e05C05f3b18b04955a3F38ff86ae92A914445099caa8eA2B9bA32 --recipient tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur -``` - -``` -npx hardhat cctx 29d6a0af11aa6164e83c17d9f129e4ec504d327fb94429732d95c16ddfcce999 -``` - -## Source Code - -You can find the source code for the example in this tutorial here: - -https://github.com/zeta-chain/example-contracts/tree/main/omnichain/swap diff --git a/src/pages/developers/tutorials/swap.mdx b/src/pages/developers/tutorials/swap.mdx index ae65fc76..4b56e8eb 100644 --- a/src/pages/developers/tutorials/swap.mdx +++ b/src/pages/developers/tutorials/swap.mdx @@ -40,12 +40,7 @@ The swap contract will: - Swap the remaining input token amount for the target token ZRC-20. - Withdraw ZRC-20 tokens to the destination chain. - - {" "} - This tutorial depends on the gateway, which is available on localnet but not yet deployed on testnet. It will be compatible - with testnet after the gateway is deployed. In other words, you can't deploy this tutorial on testnet yet. For a tutorial - that works with the current testnet, check out the [Swap on Testnet tutorial](/developers/tutorials/swap-tss).{" "} - +This tutorial relies on the Gateway, which is currently available only on localnet and testnet. ## Setting Up Your Environment @@ -97,8 +92,8 @@ contract Swap is UniversalContract { bytes to; } - function onCrossChainCall( - zContext calldata context, + function onCall( + MessageContext calldata context, address zrc20, uint256 amount, bytes calldata message From 92d7afb7f3f4a0f8c625d3a9d11bd670f17a4db6 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 10:35:05 +0300 Subject: [PATCH 02/13] update swap --- src/pages/developers/tutorials/swap.mdx | 39 ++++++++++++------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/pages/developers/tutorials/swap.mdx b/src/pages/developers/tutorials/swap.mdx index 4b56e8eb..e7aba616 100644 --- a/src/pages/developers/tutorials/swap.mdx +++ b/src/pages/developers/tutorials/swap.mdx @@ -256,14 +256,21 @@ their native chain, whether it's an EVM chain or Bitcoin. it is associated with. For example, ZRC-20 Ethereum USDC can only be withdrawn to Ethereum. +## Starting Localnet + +Start the local development environment to simulate ZetaChain's behavior by +running: + +``` +npx hardhat localnet +``` + ## Deploying the Contract Compile the contract and deploy it to localnet by running: ``` -npx hardhat compile --force - -npx hardhat deploy --network localhost +yarn deploy:localnet ``` You should see output similar to: @@ -272,16 +279,7 @@ You should see output similar to: ๐Ÿ”‘ Using account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ๐Ÿš€ Successfully deployed contract on localhost. -๐Ÿ“œ Contract address: 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E -``` - -## Starting Localnet - -Start the local development environment to simulate ZetaChain's behavior by -running: - -``` -npx hardhat localnet +๐Ÿ“œ Contract address: 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB ``` ## Swapping Gas Tokens for ERC-20 Tokens @@ -289,17 +287,16 @@ npx hardhat localnet To swap gas tokens for ERC-20 tokens, run the following command: ``` -npx hardhat swap-from-evm --network localhost --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --amount 1 --target 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +npx hardhat swap-from-evm --network localhost --receiver 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB --amount 1 --target 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ``` This script deposits tokens into the gateway on a connected EVM chain and sends a message to the Swap contract on ZetaChain to execute the swap logic. In this command, the `--receiver` parameter is the address of the Swap contract -on ZetaChain (`0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E`) that will handle the -swap. The `--amount 1` option indicates that you want to swap 1 ETH. `--target` -is the ZRC-20 address of the destination token (in this example, it's ZRC-20 -USDC). +on ZetaChain that will handle the swap. The `--amount 1` option indicates that +you want to swap 1 ETH. `--target` is the ZRC-20 address of the destination +token (in this example, it's ZRC-20 USDC). When you execute this command, the script calls the `gateway.depositAndCall` method on the connected EVM chain, depositing 1 ETH and sending a message to the @@ -320,12 +317,12 @@ To swap ERC-20 tokens for gas tokens, adjust the command by specifying the ERC-20 token you're swapping from using the `--erc20` parameter: ``` -npx hardhat swap-from-evm --network localhost --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --amount 1 --target 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --erc20 0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82 +npx hardhat swap-from-evm --network localhost --receiver 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB --amount 1 --target 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --erc20 0x0B306BF915C4d645ff596e518fAf3F9669b97016 ``` Here, the `--erc20` option specifies the ERC-20 token address you're swapping -from on the source chain (`0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82`). The -other parameters remain the same as in the previous command. +from on the source chain. The other parameters remain the same as in the +previous command. When you run the command, the script calls the `gateway.depositAndCall` method with the specified ERC-20 token and amount, sending a message to the Swap From bb065f6a99d28495146fe98e89e1e9c71fcd7756 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 10:39:03 +0300 Subject: [PATCH 03/13] update swap any --- src/pages/developers/tutorials/swap-any.mdx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/pages/developers/tutorials/swap-any.mdx b/src/pages/developers/tutorials/swap-any.mdx index 083cdf01..4515e663 100644 --- a/src/pages/developers/tutorials/swap-any.mdx +++ b/src/pages/developers/tutorials/swap-any.mdx @@ -259,9 +259,7 @@ Once your environment is set up, compile the contract and deploy it to localnet using the following command: ``` -npx hardhat compile --force - -npx hardhat deploy --network localhost --name SwapToAnyToken +yarn deploy-any:localnet ``` After deployment, you should see an output similar to this: @@ -270,19 +268,16 @@ After deployment, you should see an output similar to this: ๐Ÿ”‘ Using account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ๐Ÿš€ Successfully deployed contract on localhost. -๐Ÿ“œ Contract address: 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E +๐Ÿ“œ Contract address: 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB ``` -Ensure that you provide the `systemContractAddress` and `gatewayAddress` when -deploying the contract. For localnet, these addresses remain the same. - ## Swap and Withdraw Tokens to Connected Chain To swap tokens from a connected EVM chain and withdraw them to the destination chain, use the following command: ``` -npx hardhat swap-from-evm --network localhost --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --amount 1 --target 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --withdraw true +npx hardhat swap-from-evm --network localhost --receiver 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB --amount 1 --target 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --withdraw true ``` - EVM gateway is called with 1 native gas token (ETH) and a message that @@ -302,7 +297,7 @@ If you want to swap tokens and keep them on ZetaChain rather than withdrawing them, set the `withdraw` flag. ``` -npx hardhat swap-from-evm --network localhost --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --amount 1 --target 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --withdraw false +npx hardhat swap-from-evm --network localhost --receiver 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB --amount 1 --target 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --withdraw false ``` In the command above the `withdraw` is `false`, so the target ZRC-20 token will @@ -314,7 +309,7 @@ To swap a ZRC-20 token for another ZRC-20 on ZetaChain and withdraw to a connected chain, run: ``` -npx hardhat swap-from-zetachain --network localhost --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --amount 1 --target 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --zrc20 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --withdraw true +npx hardhat swap-from-zetachain --network localhost --contract 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB --amount 1 --target 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --zrc20 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --withdraw true ``` ## Swap on ZetaChain Without Withdrawing @@ -323,7 +318,7 @@ To swap a ZRC-20 token for another ZRC-20 on ZetaChain and transfer it to a recipient on ZetaChain, run: ``` -npx hardhat swap-from-zetachain --network localhost --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --amount 1 --target 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --zrc20 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --withdraw false +npx hardhat swap-from-zetachain --network localhost --contract 0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB --amount 1 --target 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --recipient 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --zrc20 0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c --withdraw false ``` ## Conclusion From 3532f5c0dcbb8debfa413aee196cf995857b8606 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 10:41:34 +0300 Subject: [PATCH 04/13] localnet --- src/pages/developers/tutorials/localnet.mdx | 41 +++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/pages/developers/tutorials/localnet.mdx b/src/pages/developers/tutorials/localnet.mdx index b762cd45..7766e479 100644 --- a/src/pages/developers/tutorials/localnet.mdx +++ b/src/pages/developers/tutorials/localnet.mdx @@ -42,7 +42,7 @@ dependencies: ``` git clone https://github.com/zeta-chain/example-contracts -cd example-contracts/universal/hello +cd example-contracts/examples/hello yarn ``` @@ -120,28 +120,29 @@ contract addresses: ``` EVM Contract Addresses ======================= -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ (index) โ”‚ Values โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Gateway EVM โ”‚ '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0' โ”‚ -โ”‚ ERC-20 Custody โ”‚ '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9' โ”‚ -โ”‚ TSS โ”‚ '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' โ”‚ -โ”‚ ZETA โ”‚ '0x5FbDB2315678afecb367f032d93F642f64180aa3' โ”‚ -โ”‚ ERC-20 USDC.ETH โ”‚ '0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82' โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ (index) โ”‚ Values โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Gateway EVM โ”‚ '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0' โ”‚ +โ”‚ ERC-20 Custody โ”‚ '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9' โ”‚ +โ”‚ TSS โ”‚ '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' โ”‚ +โ”‚ ZETA โ”‚ '0x5FbDB2315678afecb367f032d93F642f64180aa3' โ”‚ +โ”‚ ERC-20 USDC.ETH โ”‚ '0x0B306BF915C4d645ff596e518fAf3F9669b97016' โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ZetaChain Contract Addresses ============================= -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ (index) โ”‚ Values โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Gateway ZetaChain โ”‚ '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0' โ”‚ -โ”‚ ZETA โ”‚ '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853' โ”‚ -โ”‚ Fungible Module โ”‚ '0x735b14BB79463307AAcBED86DAf3322B1e6226aB' โ”‚ -โ”‚ System Contract โ”‚ '0x610178dA211FEF7D417bC0e6FeD39F05609AD788' โ”‚ -โ”‚ ZRC-20 USDC.ETH โ”‚ '0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c' โ”‚ -โ”‚ ZRC-20 ETH.ETH โ”‚ '0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe' โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ (index) โ”‚ Values โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Gateway ZetaChain โ”‚ '0x9A676e781A523b5d0C0e43731313A708CB607508' โ”‚ +โ”‚ ZETA โ”‚ '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318' โ”‚ +โ”‚ Fungible Module โ”‚ '0x735b14BB79463307AAcBED86DAf3322B1e6226aB' โ”‚ +โ”‚ System Contract โ”‚ '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0' โ”‚ +โ”‚ Uniswap Router โ”‚ '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e' โ”‚ +โ”‚ ZRC-20 USDC.ETH โ”‚ '0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c' โ”‚ +โ”‚ ZRC-20 ETH.ETH โ”‚ '0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe' โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` These addresses correspond to the deployed contracts on your local blockchain. From 0c0bbf57fa6d8e0b14f272c263b85c1d511ea702 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 13:09:06 +0300 Subject: [PATCH 05/13] nft tutorial --- src/pages/developers/tutorials/_meta.json | 5 + src/pages/developers/tutorials/localnet.mdx | 7 +- src/pages/developers/tutorials/nft.mdx | 576 ++++++++++++++++++++ 3 files changed, 586 insertions(+), 2 deletions(-) create mode 100644 src/pages/developers/tutorials/nft.mdx diff --git a/src/pages/developers/tutorials/_meta.json b/src/pages/developers/tutorials/_meta.json index fc29798a..b83e3fe3 100644 --- a/src/pages/developers/tutorials/_meta.json +++ b/src/pages/developers/tutorials/_meta.json @@ -19,6 +19,11 @@ "readTime": "60 min", "description": "Enhance the universal swap app with the ability to swap to any token" }, + "nft": { + "title": "NFT", + "readTime": "60 min", + "description": "Mint a universal NFT, which can be transferred between connected chains" + }, "localnet": { "title": "Localnet", "readTime": "30 min", diff --git a/src/pages/developers/tutorials/localnet.mdx b/src/pages/developers/tutorials/localnet.mdx index 7766e479..23488260 100644 --- a/src/pages/developers/tutorials/localnet.mdx +++ b/src/pages/developers/tutorials/localnet.mdx @@ -145,8 +145,11 @@ ZetaChain Contract Addresses โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` -These addresses correspond to the deployed contracts on your local blockchain. -You can interact with these contracts using your preferred development tools. +These addresses correspond to the contracts deployed on your local blockchain. +You can interact with them using your preferred development tools. Note that +while these addresses remain persistent between restarts, they may vary on +different instances of localnet. For the latest list of addresses, please refer +to the table displayed in the terminal window where localnet is running. # Available Parameters diff --git a/src/pages/developers/tutorials/nft.mdx b/src/pages/developers/tutorials/nft.mdx new file mode 100644 index 00000000..dc0d96a3 --- /dev/null +++ b/src/pages/developers/tutorials/nft.mdx @@ -0,0 +1,576 @@ +import { Alert } from "~/components/shared"; + +In this tutorial you will learn how to create a universal ERC-721 NFT that can +be easily transferred between chains connected to ZetaChain. + +The project consists of two ERC-721 NFT contracts. + +**Universal** contract is deployed on ZetaChain. The contract is used to: + +- Mint NFTs on ZetaChain +- Transfer NFTs from ZetaChain to a connected chain +- Handle incoming NFT transfers from connected chain to ZetaChain +- Handle NFT transfers between connected chains + +**Connected** contract is deployed one or more connected EVM chains. The +contract is used to: + +- Mint an NFT on a connected chain +- Transfer NFT to another connected chain or ZetaChain +- Handling incoming NFT transfers from ZetaChain or another connected chain + +A universal NFT can be minted on any chain: ZetaChain or any connected EVM +chain. When an NFT is minted, it gets assigned a persistent token ID that is +unique across all chains. When an NFT is transferred between chains, the token +ID remains the same. + +An NFT can be transferred from ZetaChain to a connected chain, from a connected +chain to ZetaChain and between connected chains. ZetaChain acts as a hub for +cross-chain transactions, so all transfers go through ZetaChain. For example, +when you transfer an NFT from Ethereum to BNB, two cross-chain transactions are +initiated: Ethereum โ†’ ZetaChain โ†’ BNB. This doesn't impact the transfer time or +costs, but makes it easier to connect any number of chains. + +Cross-chain NFT transfers are capable of handling reverts. If the transfer fails +on the destination chain, an NFT will be returned to the original sender on the +source chain. + +NFT contracts only accept cross-chain calls from trusted "counterparty" +contracts. Each contract on a connected chain stores a "counterparty" address โ€” +an address of the Universal contract on ZetaChain. The Universal contract stores +a list of "counterparty" contracts on connected chains. This ensures that only +the contracts from the same NFT collection can participate in the cross-chain +transfer. + + + {" "} + This tutorial uses the authenticated calls feature of the Gateway, which is currently available only on a pre-release (v4.0.0-rc*) + version of localnet, which is installed by default in this example.{" "} + + +## Set Up Your Environment + +Start by cloning the example contracts repository and installing the necessary +dependencies: + +```bash +git clone https://github.com/zeta-chain/example-contracts +cd example-contracts/examples/nft +yarn +``` + +## Universal App Contract + +```solidity filename="contracts/Universal.sol" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import {RevertContext, RevertOptions} from "@zetachain/protocol-contracts/contracts/Revert.sol"; +import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol"; +import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol"; +import "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol"; +import {SwapHelperLib} from "@zetachain/toolkit/contracts/SwapHelperLib.sol"; +import {SystemContract} from "@zetachain/toolkit/contracts/SystemContract.sol"; + +contract Universal is + ERC721, + ERC721Enumerable, + ERC721URIStorage, + Ownable, + UniversalContract +{ + GatewayZEVM public immutable gateway; + SystemContract public immutable systemContract = + SystemContract(0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9); + uint256 private _nextTokenId; + bool public isUniversal = true; + uint256 public gasLimit = 700000; + + error TransferFailed(); + + mapping(address => bytes) public counterparty; + + event CounterpartySet(address indexed zrc20, bytes indexed contractAddress); + + constructor( + address payable gatewayAddress, + address initialOwner + ) ERC721("MyToken", "MTK") Ownable(initialOwner) { + gateway = GatewayZEVM(gatewayAddress); + } + + function setCounterparty( + address zrc20, + bytes memory contractAddress + ) external onlyOwner { + counterparty[zrc20] = contractAddress; + emit CounterpartySet(zrc20, contractAddress); + } + + function transferCrossChain( + uint256 tokenId, + bytes memory receiver, + address zrc20 + ) public { + string memory uri = tokenURI(tokenId); + _burn(tokenId); + + (, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit); + if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee)) + revert TransferFailed(); + IZRC20(zrc20).approve(address(gateway), gasFee); + bytes memory encodedData = abi.encode(tokenId, msg.sender, uri); + + CallOptions memory callOptions = CallOptions(gasLimit, false); + + RevertOptions memory revertOptions = RevertOptions( + address(this), + true, + address(0), + encodedData, + gasLimit + ); + + gateway.call(receiver, zrc20, encodedData, callOptions, revertOptions); + } + + function safeMint(address to, string memory uri) public onlyOwner { + uint256 hash = uint256( + keccak256( + abi.encodePacked(address(this), block.number, _nextTokenId++) + ) + ); + + uint256 tokenId = hash & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + } + + function onCall( + MessageContext calldata messageContext, + address zrc20, + uint256 amount, + bytes calldata message + ) external override { + if (keccak256(messageContext.origin) != keccak256(counterparty[zrc20])) + revert("Unauthorized"); + + ( + uint256 tokenId, + address sender, + string memory uri, + address destination + ) = abi.decode(message, (uint256, address, string, address)); + + if (destination == address(0)) { + _safeMint(sender, tokenId); + _setTokenURI(tokenId, uri); + } else { + (, uint256 gasFee) = IZRC20(destination).withdrawGasFeeWithGasLimit( + 700000 + ); + + SwapHelperLib.swapExactTokensForTokens( + systemContract, + zrc20, + amount, + destination, + 0 + ); + + IZRC20(destination).approve(address(gateway), gasFee); + gateway.call( + counterparty[destination], + destination, + abi.encode(tokenId, sender, uri), + CallOptions(700000, false), + RevertOptions(address(0), false, address(0), "", 0) + ); + } + } + + function onRevert(RevertContext calldata context) external { + (uint256 tokenId, address sender, string memory uri) = abi.decode( + context.revertMessage, + (uint256, address, string) + ); + + _safeMint(sender, tokenId); + _setTokenURI(tokenId, uri); + } + + // The following functions are overrides required by Solidity. + + function _update( + address to, + uint256 tokenId, + address auth + ) internal override(ERC721, ERC721Enumerable) returns (address) { + return super._update(to, tokenId, auth); + } + + function _increaseBalance( + address account, + uint128 value + ) internal override(ERC721, ERC721Enumerable) { + super._increaseBalance(account, value); + } + + function tokenURI( + uint256 tokenId + ) public view override(ERC721, ERC721URIStorage) returns (string memory) { + return super.tokenURI(tokenId); + } + + function supportsInterface( + bytes4 interfaceId + ) + public + view + override(ERC721, ERC721Enumerable, ERC721URIStorage) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +``` + +### Minting an NFT + +`safeMint` mint a new NFT. Token ID is generated from the contract address, +block time, and an incrementing integer. This ensures that the token ID is +unique across all chains. The only scenario where ID collision is possible is +when two contracts are deployed on the same address on two different chains, and +an NFT is minted on both exactly at the same time using the same integer. You +can supply your own logic for generating token IDs. + +### Transfer NFT from ZetaChain to a Connected Chain + +`transferCrossChain` transfers an NFT from ZetaChain to a connected chain. +Transferring an NFT to a connected chain creates a transaction on a connected +chain, which costs gas. To pay for gas, the NFT sender must provide the +universal app with tokens for gas in the form of ZRC-20 version of the gas token +of the connected chain. For example, when a user transfers an NFT from ZetaChain +to Ethereum, they need to allow the contract to spend a certain amount of ZRC-20 +ETH. + +The function transfers the ZRC-20 tokens to the gateway contract. + +Next, the function encodes the token ID, sender's address and the URI into a +message. + +`callOptions` are defined with the gas limit on the destination chain and +`isArbitraryCall` (the second parameter) is set to false. `isArbitraryCall` +determines if the call is arbitrary (a call to any contract on the destination +chain, but without providing address of the universal contract making the call) +or authenticated (the call is made to `onCall` function, the universal contract +address is passed as a parameter). Setting `isArbitraryCall` to false is +important, because the contract on a connected chain must know which universal +contract is making a call to prevent unauthorized calls. + +`revertOptions` contain the address of a contract on ZetaChain, which will be +called if the contract on the destination chain reverts (in our example we want +to call the same universal contract), as well as the message that will be passed +to the `onRevert` function of the revert contract. Pass the same encoded message +to ensure that the universal contract can successfully mint the token back to +the sender if the transfer fails. + +Finally, `gateway.call` is executed to initiate a cross-chain transfer of an NFT +from ZetaChain to a connected chain. The destination chain is determined by the +ZRC-20 contract address, which corresponds to the gas token of the connected +chain. For example, to transfer the NFT to Ethereum, pass address of ZRC-20 ETH. + +### Handling NFT Transfers from Connected Chains + +`onCall` is executed when an NFT transfer is received from a connected chain. + +First, `onCall` checks that the transfer originates from a trusted counterparty +contract. This prevents unauthorized minting by malicious contracts. + +Since all cross-chain transfers are processed by ZetaChain, there are two +scenarios when `onCall` is executed: when the destination is ZetaChain or when +the destination is another connected chain. + +If the destination is a zero address, then the destination chain is ZetaChain. +An NFT is minted and transferred to the recipient. + +If the destination is a non-zero address, the destination chain is another +connected chain identified by the ZRC-20 gas token address in the destination +field of the message. The contract initiates a transfer to the connected chain. +First, it queries the withdraw fee on the destination chain. Then, it swaps the +incoming ZRC-20 tokens into the ZRC-20 gas token of the destination chain. The +swap uses the built-in Uniswap v2 pools, but any other swap mechanism can be +used, instead. Finally, `gateway.call` is executed to initiate the transfer to +the destination chain. + +### Revert Handling + +If an NFT transfer from ZetaChain to a connected chain fails, `onRevert` is +called. `onRevert` mints the NFT and transfers it back to original sender. + +## Connected Chain Contract + +```solidity filename="contracts/Connected.sol" +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol"; +import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol"; + +contract Connected is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable { + GatewayEVM public immutable gateway; + uint256 private _nextTokenId; + address public counterparty; + + function setCounterparty(address contractAddress) external onlyOwner { + counterparty = contractAddress; + } + + constructor( + address payable gatewayAddress, + address initialOwner + ) ERC721("MyToken", "MTK") Ownable(initialOwner) { + gateway = GatewayEVM(gatewayAddress); + } + + function safeMint(address to, string memory uri) public onlyOwner { + uint256 hash = uint256( + keccak256( + abi.encodePacked(address(this), block.number, _nextTokenId++) + ) + ); + + uint256 tokenId = hash & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + } + + function transferCrossChain( + uint256 tokenId, + address receiver, + address destination + ) external payable { + string memory uri = tokenURI(tokenId); + _burn(tokenId); + bytes memory encodedData = abi.encode( + tokenId, + msg.sender, + uri, + destination + ); + + RevertOptions memory revertOptions = RevertOptions( + address(this), + true, + address(0), + encodedData, + 0 + ); + + if (destination == address(0)) { + gateway.call(receiver, encodedData, revertOptions); + } else { + gateway.depositAndCall{value: msg.value}( + receiver, + encodedData, + revertOptions + ); + } + } + + function onCall( + MessageContext calldata messageContext, + bytes calldata message + ) external payable returns (bytes4) { + if (messageContext.sender != counterparty) revert("Unauthorized"); + + (uint256 tokenId, address sender, string memory uri) = abi.decode( + message, + (uint256, address, string) + ); + _safeMint(sender, tokenId); + _setTokenURI(tokenId, uri); + return ""; + } + + function onRevert(RevertContext calldata context) external { + (uint256 tokenId, address sender, string memory uri) = abi.decode( + context.revertMessage, + (uint256, address, string) + ); + + _safeMint(sender, tokenId); + _setTokenURI(tokenId, uri); + } + + receive() external payable {} + + fallback() external payable {} + + // The following functions are overrides required by Solidity. + + function _update( + address to, + uint256 tokenId, + address auth + ) internal override(ERC721, ERC721Enumerable) returns (address) { + return super._update(to, tokenId, auth); + } + + function _increaseBalance( + address account, + uint128 value + ) internal override(ERC721, ERC721Enumerable) { + super._increaseBalance(account, value); + } + + function tokenURI( + uint256 tokenId + ) public view override(ERC721, ERC721URIStorage) returns (string memory) { + return super.tokenURI(tokenId); + } + + function supportsInterface( + bytes4 interfaceId + ) + public + view + override(ERC721, ERC721Enumerable, ERC721URIStorage) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} +``` + +``` +./scripts/test.sh +``` + +### Transfer NFT from a Connected Chain + +`transferCrossChain` initiates a transfer of an NFT to ZetaChain or to another +connected chain. + +To transfer an NFT to ZetaChain the destination address must be specified as a +zero address. + +To transfer an NFT to another connected chain the destination address must be +the ZRC-20 address of the gas token of the destination chain. For example, to +transfer to Ethereum, the destination is ZRC-20 ETH address. + +When transferring to ZetaChain a no asset `gateway.call` is executed, because +cross-chain calls to ZetaChain do not require the sender to cover gas costs. + +When transferring to another connected chain, `gateway.depositAndCall` is +executed with some gas tokens to cover the gas costs on the destination chain. + +### Handling NFT Transfers + +`onCall` is executed when an NFT transfer is received from a connected chain or +ZetaChain. + +Since all cross-chain transactions go through a universal contract on ZetaChain, +`onCall` checks that the call is made from a trusted counterparty universal +contract address to prevent unauthorized minting. + +### Revert Handling + +If an NFT transfer from ZetaChain to a connected chain fails, `onRevert` is +called. `onRevert` mints the NFT and transfers it back to original sender. + +## Start Localnet + +[Localnet](/developers/tutorials/localnet) provides a simulated environment for +developing and testing ZetaChain contracts locally. + +To start localnet, open a terminal window and run: + +```bash +npx hardhat localnet +``` + +This command initializes a local blockchain environment that simulates the +behavior of ZetaChain protocol contracts. + +## Demo + +Run the following script, which will deploy NFT contracts on localnet, set +counterparty addresses, mint an NFT and transfer it ZetaChain โ†’ Ethereum โ†’ BNB โ†’ +ZetaChain: + +``` +./scripts/test.sh +``` + +On localnet Ethereum, BNB, and ZetaChain are all running on the same Anvil +blockchain, but each has its own Gateway, which allows us to simulate +cross-chain transfers. + +``` +๐Ÿš€ Deployed NFT contract on ZetaChain: 0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2 +๐Ÿš€ Deployed NFT contract on EVM chain: 0xD8a5a9b31c3C0232E196d518E89Fd8bF83AcAd43 +๐Ÿš€ Deployed NFT contract on BNB chain: 0xDC11f7E700A4c898AE5CAddB1082cFfa76512aDD + +๐Ÿ“ฎ User Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + +๐Ÿ”— Setting counterparty contracts... + +๐Ÿ–ผ๏ธ NFT Balance +--------------------------------------------- +๐ŸŸข ZetaChain: 0 +๐Ÿ”ต EVM Chain: 0 +๐ŸŸก BNB Chain: 0 +--------------------------------------------- + +Minted NFT with ID: 360200380862174510501150413599333672688790691765 on ZetaChain. + +๐Ÿ–ผ๏ธ NFT Balance +--------------------------------------------- +๐ŸŸข ZetaChain: 1 +๐Ÿ”ต EVM Chain: 0 +๐ŸŸก BNB Chain: 0 +--------------------------------------------- + +Transferring NFT: ZetaChain โ†’ Ethereum... +{"contractAddress":"0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2","transferTransactionHash":"0x044ac700fe16a498d5474c383606efb996425d62323fcdd8b53eadeaa487cb3a","sender":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","tokenId":"360200380862174510501150413599333672688790691765"} + +๐Ÿ–ผ๏ธ NFT Balance +--------------------------------------------- +๐ŸŸข ZetaChain: 0 +๐Ÿ”ต EVM Chain: 1 +๐ŸŸก BNB Chain: 0 +--------------------------------------------- + +Transferring NFT: Ethereum โ†’ BNB... +{"contractAddress":"0xD8a5a9b31c3C0232E196d518E89Fd8bF83AcAd43","transferTransactionHash":"0xc95a1ca71406dbb2e4a1f01b32b62cfa1f72d3c0923d2ea1e2967f8d837899e2","sender":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","tokenId":"360200380862174510501150413599333672688790691765"} + +๐Ÿ–ผ๏ธ NFT Balance +--------------------------------------------- +๐ŸŸข ZetaChain: 0 +๐Ÿ”ต EVM Chain: 0 +๐ŸŸก BNB Chain: 1 +--------------------------------------------- + +Transferring NFT: BNB โ†’ ZetaChain... +{"contractAddress":"0xDC11f7E700A4c898AE5CAddB1082cFfa76512aDD","transferTransactionHash":"0xb139d188c59c347540dbdea26f30f149f8131ce10ebc6f50ed7253dfd04ff014","sender":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","tokenId":"360200380862174510501150413599333672688790691765"} + +๐Ÿ–ผ๏ธ NFT Balance +--------------------------------------------- +๐ŸŸข ZetaChain: 1 +๐Ÿ”ต EVM Chain: 0 +๐ŸŸก BNB Chain: 0 +--------------------------------------------- +``` From 0bf8c5ffd28ce04b39785b14d1556f7433a7faee Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 16:35:36 +0300 Subject: [PATCH 06/13] testnet examples in hello --- src/pages/developers/tutorials/hello.mdx | 67 ++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/pages/developers/tutorials/hello.mdx b/src/pages/developers/tutorials/hello.mdx index 4e8726c2..a4bfd4ea 100644 --- a/src/pages/developers/tutorials/hello.mdx +++ b/src/pages/developers/tutorials/hello.mdx @@ -252,6 +252,73 @@ contract Echo { } ``` +## Deploy on Testnet + +``` +npx hardhat compile --force +npx hardhat deploy --gateway 0x6c533f7fe93fae114d0954697069df33c9b74fd7 --network zeta_testnet +npx hardhat deploy --gateway 0x0c487a766110c85d301d96e33579c5b317fa4995 --network base_testnet --name Echo +``` + +``` +๐Ÿ”‘ Using account: 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 + +๐Ÿš€ Successfully deployed "Hello" contract on zeta_testnet. +๐Ÿ“œ Contract address: 0x496CD66950a1F1c5B02513809A2d37fFB942be1B + +๐Ÿ”‘ Using account: 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 + +๐Ÿš€ Successfully deployed "Echo" contract on base_sepolia. +๐Ÿ“œ Contract address: 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed +``` + +## Call from Base to ZetaChain + +``` +npx hardhat echo-call \ + --contract 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed \ + --receiver 0x496CD66950a1F1c5B02513809A2d37fFB942be1B \ + --network base_sepolia \ + --tx-options-gas-price 20000 --types '["string"]' alice +``` + +https://sepolia.basescan.org/tx/0x133cdf3a06195de0a6bb89dd4761ca98d1301534b3c4987f0ff93c95c3fff78c + +https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x133cdf3a06195de0a6bb89dd4761ca98d1301534b3c4987f0ff93c95c3fff78c + +## Call from ZetaChain to Base + +``` +npx hardhat hello-call \ + --contract 0x496CD66950a1F1c5B02513809A2d37fFB942be1B \ + --receiver 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed \ + --zrc20 0x236b0DE675cC8F46AE186897fCCeFe3370C9eDeD \ + --function "hello(string)" \ + --network zeta_testnet \ + --tx-options-gas-price 200000 --types '["string"]' alice +``` + +https://zetachain-testnet.blockscout.com/tx/0x19d476fa2c3d29ba41467ae7f2742541fd11e0b67d6548fe7655a3d40274323e + +https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x19d476fa2c3d29ba41467ae7f2742541fd11e0b67d6548fe7655a3d40274323e + +## Withdraw And Call from ZetaChain to Base + +``` +npx hardhat hello-withdraw-and-call \ + --contract 0x496CD66950a1F1c5B02513809A2d37fFB942be1B \ + --receiver 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed \ + --zrc20 0x236b0DE675cC8F46AE186897fCCeFe3370C9eDeD \ + --function "hello(string)" \ + --amount 0.005 \ + --network zeta_testnet \ + --types '["string"]' hello +``` + +https://zetachain-testnet.blockscout.com/tx/0x67099389ab6cb44ee03602d164320c615720b57762c5ddab042d65bdbe30c7a2 + +https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x67099389ab6cb44ee03602d164320c615720b57762c5ddab042d65bdbe30c7a2 + ## Start Localnet [Localnet](/developers/tutorials/localnet) provides a simulated environment for From 66d88d6bb90bf5ed52a5469e8f2604e63325d3f2 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 16:38:31 +0300 Subject: [PATCH 07/13] testnet examples in swap --- src/pages/developers/tutorials/hello.mdx | 4 ++-- src/pages/developers/tutorials/swap.mdx | 30 +++++++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/pages/developers/tutorials/hello.mdx b/src/pages/developers/tutorials/hello.mdx index a4bfd4ea..7df57ce5 100644 --- a/src/pages/developers/tutorials/hello.mdx +++ b/src/pages/developers/tutorials/hello.mdx @@ -252,7 +252,7 @@ contract Echo { } ``` -## Deploy on Testnet +## Option 1: Deploy on Testnet ``` npx hardhat compile --force @@ -319,7 +319,7 @@ https://zetachain-testnet.blockscout.com/tx/0x67099389ab6cb44ee03602d164320c6157 https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x67099389ab6cb44ee03602d164320c615720b57762c5ddab042d65bdbe30c7a2 -## Start Localnet +## Option 2: Start Localnet [Localnet](/developers/tutorials/localnet) provides a simulated environment for developing and testing ZetaChain contracts locally. diff --git a/src/pages/developers/tutorials/swap.mdx b/src/pages/developers/tutorials/swap.mdx index e7aba616..067adb80 100644 --- a/src/pages/developers/tutorials/swap.mdx +++ b/src/pages/developers/tutorials/swap.mdx @@ -256,7 +256,33 @@ their native chain, whether it's an EVM chain or Bitcoin. it is associated with. For example, ZRC-20 Ethereum USDC can only be withdrawn to Ethereum. -## Starting Localnet +## Option 1: Deploy on Testnet + +``` +npx hardhat compile --force +npx hardhat deploy --gateway 0x6c533f7fe93fae114d0954697069df33c9b74fd7 --network zeta_testnet +``` + +``` +๐Ÿ”‘ Using account: 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 + +๐Ÿš€ Successfully deployed contract on zeta_testnet. +๐Ÿ“œ Contract address: 0x162CefCe314726698ac1Ee5895a6c392ba8e20d3 +``` + +## Swap from Base Sepolia to Polygon Amoy + +``` +npx hardhat evm-deposit-and-call + --receiver 0x162CefCe314726698ac1Ee5895a6c392ba8e20d3 \ + --amount 0.001 \ + --network base_sepolia \ + --gas-price 20000 \ + --gateway-evm 0x0c487a766110c85d301d96e33579c5b317fa4995 \ + --types '["address", "bytes"]' 0x777915D031d1e8144c90D025C594b3b8Bf07a08d 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 +``` + +## Option 2: Deploy on Localnet Start the local development environment to simulate ZetaChain's behavior by running: @@ -265,8 +291,6 @@ running: npx hardhat localnet ``` -## Deploying the Contract - Compile the contract and deploy it to localnet by running: ``` From 93ff0f3f806958dae645a16df0f9c3de1c0b6cfd Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 16:41:23 +0300 Subject: [PATCH 08/13] solana in swap --- src/pages/developers/tutorials/hello.mdx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pages/developers/tutorials/hello.mdx b/src/pages/developers/tutorials/hello.mdx index 7df57ce5..0c03b035 100644 --- a/src/pages/developers/tutorials/hello.mdx +++ b/src/pages/developers/tutorials/hello.mdx @@ -319,6 +319,16 @@ https://zetachain-testnet.blockscout.com/tx/0x67099389ab6cb44ee03602d164320c6157 https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x67099389ab6cb44ee03602d164320c615720b57762c5ddab042d65bdbe30c7a2 +## Swap from Solana + +``` +npx hardhat interact-solana \ + --amount 0.1 \ + --contract 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed \ + --recipient 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 \ + --target-token 0x236b0DE675cC8F46AE186897fCCeFe3370C9eDeD +``` + ## Option 2: Start Localnet [Localnet](/developers/tutorials/localnet) provides a simulated environment for From 919e16ed7f48cecd1686f12c0ca2d2c7d67def69 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 16:43:24 +0300 Subject: [PATCH 09/13] solana in swap --- src/pages/developers/tutorials/hello.mdx | 10 ---------- src/pages/developers/tutorials/swap.mdx | 9 +++++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/pages/developers/tutorials/hello.mdx b/src/pages/developers/tutorials/hello.mdx index 0c03b035..7df57ce5 100644 --- a/src/pages/developers/tutorials/hello.mdx +++ b/src/pages/developers/tutorials/hello.mdx @@ -319,16 +319,6 @@ https://zetachain-testnet.blockscout.com/tx/0x67099389ab6cb44ee03602d164320c6157 https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x67099389ab6cb44ee03602d164320c615720b57762c5ddab042d65bdbe30c7a2 -## Swap from Solana - -``` -npx hardhat interact-solana \ - --amount 0.1 \ - --contract 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed \ - --recipient 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 \ - --target-token 0x236b0DE675cC8F46AE186897fCCeFe3370C9eDeD -``` - ## Option 2: Start Localnet [Localnet](/developers/tutorials/localnet) provides a simulated environment for diff --git a/src/pages/developers/tutorials/swap.mdx b/src/pages/developers/tutorials/swap.mdx index 067adb80..732ec57a 100644 --- a/src/pages/developers/tutorials/swap.mdx +++ b/src/pages/developers/tutorials/swap.mdx @@ -282,6 +282,15 @@ npx hardhat evm-deposit-and-call --types '["address", "bytes"]' 0x777915D031d1e8144c90D025C594b3b8Bf07a08d 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 ``` +## Swap from Solana + +``` +npx hardhat solana-deposit \ + --amount 0.1 \ + --recipient 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed \ + --types '["address", "bytes"]' 0x236b0DE675cC8F46AE186897fCCeFe3370C9eDeD 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 +``` + ## Option 2: Deploy on Localnet Start the local development environment to simulate ZetaChain's behavior by From a2eb994c3be0a57abbdc36fc55282517ac57ac02 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 16:49:38 +0300 Subject: [PATCH 10/13] remove solana --- src/pages/developers/tutorials/swap.mdx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/pages/developers/tutorials/swap.mdx b/src/pages/developers/tutorials/swap.mdx index 732ec57a..067adb80 100644 --- a/src/pages/developers/tutorials/swap.mdx +++ b/src/pages/developers/tutorials/swap.mdx @@ -282,15 +282,6 @@ npx hardhat evm-deposit-and-call --types '["address", "bytes"]' 0x777915D031d1e8144c90D025C594b3b8Bf07a08d 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 ``` -## Swap from Solana - -``` -npx hardhat solana-deposit \ - --amount 0.1 \ - --recipient 0x775329c70A8d09AEb5e5ca92C369FF3155C5f1Ed \ - --types '["address", "bytes"]' 0x236b0DE675cC8F46AE186897fCCeFe3370C9eDeD 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 -``` - ## Option 2: Deploy on Localnet Start the local development environment to simulate ZetaChain's behavior by From 2bf4d7b6decdbdf73843f5f525b7effb7c99d8f3 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 30 Oct 2024 18:11:03 +0300 Subject: [PATCH 11/13] update protocol contract addresses --- src/components/Docs/components/ContractAddresses.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Docs/components/ContractAddresses.tsx b/src/components/Docs/components/ContractAddresses.tsx index e467acf8..ae73e531 100644 --- a/src/components/Docs/components/ContractAddresses.tsx +++ b/src/components/Docs/components/ContractAddresses.tsx @@ -15,8 +15,8 @@ type ContractAddressData = { type ContractAddressesByChain = Record; const addressesUrl: Record = { - testnet: "https://raw.githubusercontent.com/zeta-chain/protocol-contracts/main/v1/data/addresses.testnet.json", - mainnet: "https://raw.githubusercontent.com/zeta-chain/protocol-contracts/main/v1/data/addresses.mainnet.json", + testnet: "https://raw.githubusercontent.com/zeta-chain/protocol-contracts/main/v2/data/addresses.testnet.json", + mainnet: "https://raw.githubusercontent.com/zeta-chain/protocol-contracts/main/v2/data/addresses.mainnet.json", }; const groupDataByChain = (data: ContractAddressData[]) => From 591556c2d13b624bb47d3f7ffadf922c5bf580ae Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 31 Oct 2024 13:03:11 +0300 Subject: [PATCH 12/13] refactor --- src/pages/developers/tutorials/nft.mdx | 39 ++++++++++++++++---------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/pages/developers/tutorials/nft.mdx b/src/pages/developers/tutorials/nft.mdx index dc0d96a3..52464cdf 100644 --- a/src/pages/developers/tutorials/nft.mdx +++ b/src/pages/developers/tutorials/nft.mdx @@ -114,17 +114,20 @@ contract Universal is function transferCrossChain( uint256 tokenId, - bytes memory receiver, - address zrc20 + address receiver, + address destination ) public { string memory uri = tokenURI(tokenId); _burn(tokenId); - (, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit); - if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee)) - revert TransferFailed(); - IZRC20(zrc20).approve(address(gateway), gasFee); - bytes memory encodedData = abi.encode(tokenId, msg.sender, uri); + (, uint256 gasFee) = IZRC20(destination).withdrawGasFeeWithGasLimit( + gasLimit + ); + if ( + !IZRC20(destination).transferFrom(msg.sender, address(this), gasFee) + ) revert TransferFailed(); + IZRC20(destination).approve(address(gateway), gasFee); + bytes memory encodedData = abi.encode(tokenId, receiver, uri); CallOptions memory callOptions = CallOptions(gasLimit, false); @@ -136,7 +139,13 @@ contract Universal is gasLimit ); - gateway.call(receiver, zrc20, encodedData, callOptions, revertOptions); + gateway.call( + counterparty[destination], + destination, + encodedData, + callOptions, + revertOptions + ); } function safeMint(address to, string memory uri) public onlyOwner { @@ -153,12 +162,12 @@ contract Universal is } function onCall( - MessageContext calldata messageContext, + MessageContext calldata context, address zrc20, uint256 amount, bytes calldata message ) external override { - if (keccak256(messageContext.origin) != keccak256(counterparty[zrc20])) + if (keccak256(context.origin) != keccak256(counterparty[zrc20])) revert("Unauthorized"); ( @@ -366,7 +375,7 @@ contract Connected is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable { _burn(tokenId); bytes memory encodedData = abi.encode( tokenId, - msg.sender, + receiver, uri, destination ); @@ -380,10 +389,10 @@ contract Connected is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable { ); if (destination == address(0)) { - gateway.call(receiver, encodedData, revertOptions); + gateway.call(counterparty, encodedData, revertOptions); } else { gateway.depositAndCall{value: msg.value}( - receiver, + counterparty, encodedData, revertOptions ); @@ -396,11 +405,11 @@ contract Connected is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable { ) external payable returns (bytes4) { if (messageContext.sender != counterparty) revert("Unauthorized"); - (uint256 tokenId, address sender, string memory uri) = abi.decode( + (uint256 tokenId, address receiver, string memory uri) = abi.decode( message, (uint256, address, string) ); - _safeMint(sender, tokenId); + _safeMint(receiver, tokenId); _setTokenURI(tokenId, uri); return ""; } From 162dd8d7656ed6650fab157b0a70064340e3283c Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Fri, 1 Nov 2024 09:37:59 +0300 Subject: [PATCH 13/13] replace onCrossChainCall with onCall --- src/pages/developers/apps/intro.mdx | 10 +++++----- src/pages/developers/chains/evm.mdx | 17 ++++++++-------- src/pages/developers/tokens/zrc20.mdx | 21 ++++++++++---------- src/pages/developers/tutorials/hello.mdx | 22 ++++++++++----------- src/pages/developers/tutorials/swap-any.mdx | 19 +++++++++--------- src/pages/developers/tutorials/swap.mdx | 16 +++++++-------- 6 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/pages/developers/apps/intro.mdx b/src/pages/developers/apps/intro.mdx index 3a191411..6e79afef 100644 --- a/src/pages/developers/apps/intro.mdx +++ b/src/pages/developers/apps/intro.mdx @@ -32,8 +32,8 @@ pragma solidity 0.8.26; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol"; contract UniversalApp is UniversalContract { - function onCrossChainCall( - zContext calldata context, + function onCall( + MessageContext calldata context, address zrc20, uint256 amount, bytes calldata message @@ -67,7 +67,7 @@ universal app: allowfullscreen > -A call to a universal app triggers an `onCrossChainCall` method. +A call to a universal app triggers an `onCall` method. A universal app receives: @@ -81,8 +81,8 @@ corresponding ZRC-20 token on ZetaChain. ZRC-20 tokens are ERC-20-compatible and can be permissionlessly transferred back (withdrawn) to their original chain (ZRC-20 ETH on ZetaChain becomes ETH on Ethereum). -`onCrossChainCall` also has access to additional context information such as the -original sender address and chain ID. +`onCall` also has access to additional context information such as the original +sender address and chain ID. Universal apps can also initiate token transfers and contract calls to connected chains. diff --git a/src/pages/developers/chains/evm.mdx b/src/pages/developers/chains/evm.mdx index 42e1ec65..32e61675 100644 --- a/src/pages/developers/chains/evm.mdx +++ b/src/pages/developers/chains/evm.mdx @@ -56,8 +56,8 @@ function. 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. +After the cross-chain transaction is processed, the `onCall` function of a +universal app contract is executed. The `receiver` must be a universal app contract address. @@ -67,8 +67,8 @@ pragma solidity 0.8.7; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol"; contract UniversalApp is UniversalContract { - function onCrossChainCall( - zContext calldata context, + function onCall( + MessageContext calldata context, address zrc20, uint256 amount, bytes calldata message @@ -78,7 +78,7 @@ contract UniversalApp is UniversalContract { } ``` -`onCrossChainCall` receives: +`onCall` receives: - `message`: value of the `payload` - `amount`: amount of deposited tokens @@ -90,10 +90,9 @@ contract UniversalApp is UniversalContract { - `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`. +When calling a universal app, the payload contains bytes passed to `onCall` 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 `onCall`. ## Deposit ERC-20 Tokens and Call a Universal App diff --git a/src/pages/developers/tokens/zrc20.mdx b/src/pages/developers/tokens/zrc20.mdx index dd7233e0..1f6b1bcf 100644 --- a/src/pages/developers/tokens/zrc20.mdx +++ b/src/pages/developers/tokens/zrc20.mdx @@ -88,11 +88,11 @@ flowchart LR SystemContract("System Contract") subgraph contract ["Omnichain contract"] addr("Contract address") - subgraph onCrossChainCall + subgraph onCall msg("bytes calldata message") zrc20("address zrc20") amount("uint256 amount") - context("zContext calldata context") + context("MessageContext calldata context") end end end @@ -116,8 +116,8 @@ If the input data field is not empty, the protocol looks up the first 20 bytes of the input data field. If the first 20 bytes correspond to an EOA address on ZetaChain, the token will be deposited to that address. If the first 20 bytes correspond to a contract address on ZetaChain, the token will be deposited to -that contract and the `onCrossChainCall` function of that contract will be -called with the remaining input data as the `message`. +that contract and the `onCall` function of that contract will be called with the +remaining input data as the `message`. When depositing native gas tokens from EVM-based connected chains, there is no additional cross-chain fee. If you send 1 token to a TSS address, you will @@ -146,11 +146,11 @@ flowchart LR SystemContract("System Contract") subgraph contract ["Omnichain contract"] addr("Contract address") - subgraph onCrossChainCall + subgraph onCall msg("bytes calldata message") zrc20("address zrc20") amount("uint256 amount") - context("zContext calldata context") + context("MessageContext calldata context") end end end @@ -173,13 +173,12 @@ The `deposit` method accepts the following parameters: - `recipient`: the address on ZetaChain to deposit the tokens to. If the recipient is an EOA, the tokens will be deposited to the recipient's address. If the recipient is a contract, the tokens will be deposited to the contract - and the `onCrossChainCall` function of that contract will be called with the - `message` as an argument. + and the `onCall` function of that contract will be called with the `message` + as an argument. - `asset`: the address of the ERC-20 token to deposit. - `amount`: the amount of tokens to deposit. -- `message`: an arbitrary message to be passed to the `onCrossChainCall` - function of the recipient contract. If the recipient is an EOA, the message - should be empty. +- `message`: an arbitrary message to be passed to the `onCall` function of the + recipient contract. If the recipient is an EOA, the message should be empty. ## Withdrawing ZRC-20 Tokens from ZetaChain diff --git a/src/pages/developers/tutorials/hello.mdx b/src/pages/developers/tutorials/hello.mdx index 7df57ce5..8749923b 100644 --- a/src/pages/developers/tutorials/hello.mdx +++ b/src/pages/developers/tutorials/hello.mdx @@ -131,8 +131,8 @@ contract Hello is UniversalContract { Let's break down what this contract does. The `Hello` contract inherits from the [`UniversalContract`](https://github.com/zeta-chain/protocol-contracts/blob/main/v2/contracts/zevm/interfaces/UniversalContract.sol) -interface, which requires the implementation of `onCrossChainCall` and -`onRevert` functions for handling cross-chain interactions. +interface, which requires the implementation of `onCall` and `onRevert` +functions for handling cross-chain interactions. A state variable `gateway` of type `GatewayZEVM` holds the address of ZetaChain's gateway contract. This gateway facilitates communication between @@ -143,11 +143,11 @@ of the ZetaChain gateway contract. ### Handling Incoming Cross-Chain Calls -The `onCrossChainCall` function is a special handler that gets triggered when -the contract receives a call from a connected chain through the gateway. This -function processes the incoming data, which includes: +The `onCall` function is a special handler that gets triggered when the contract +receives a call from a connected chain through the gateway. This function +processes the incoming data, which includes: -- `context`: A `zContext` struct containing: +- `context`: A `MessageContext` struct containing: - `origin`: The address (EOA or contract) that initiated the gateway call on the connected chain. - `chainID`: The integer ID of the connected chain from which the cross-chain @@ -158,10 +158,10 @@ function processes the incoming data, which includes: - `amount`: The number of tokens transferred. - `message`: The encoded data payload. -Within `onCrossChainCall`, the contract decodes the `name` from the `message` -and emits a `HelloEvent` to signal successful reception and processing of the -message. It's important to note that `onCrossChainCall` can only be invoked by -the ZetaChain protocol, ensuring the integrity of cross-chain interactions. +Within `onCall`, the contract decodes the `name` from the `message` and emits a +`HelloEvent` to signal successful reception and processing of the message. It's +important to note that `onCall` can only be invoked by the ZetaChain protocol, +ensuring the integrity of cross-chain interactions. ### Making an Outgoing Contract Call @@ -386,7 +386,7 @@ npx hardhat echo-call \ - **EVM Chain**: The `call` function invokes `gateway.call`, emitting a `Called` event. - **ZetaChain**: The protocol detects the event and triggers the `Hello` - contract's `onCrossChainCall`. + contract's `onCall`. - **ZetaChain**: The `Hello` contract decodes the message and emits a `HelloEvent`. diff --git a/src/pages/developers/tutorials/swap-any.mdx b/src/pages/developers/tutorials/swap-any.mdx index 4515e663..19fca036 100644 --- a/src/pages/developers/tutorials/swap-any.mdx +++ b/src/pages/developers/tutorials/swap-any.mdx @@ -212,12 +212,11 @@ have been made to extend its functionality. First, the `Params` struct has been updated to include a `withdraw` flag. This allows users to specify whether they want the swapped tokens withdrawn to a -connected chain or kept on ZetaChain. The `onCrossChainCall` function now -decodes this additional flag from the incoming message. For EVM chains and -Solana, the contract decodes the `withdraw` flag alongside other parameters. For -Bitcoin, due to the smaller message size allowed by its OP_RETURN, the contract -checks if the message length is sufficient before extracting the `withdraw` -flag. +connected chain or kept on ZetaChain. The `onCall` function now decodes this +additional flag from the incoming message. For EVM chains and Solana, the +contract decodes the `withdraw` flag alongside other parameters. For Bitcoin, +due to the smaller message size allowed by its OP_RETURN, the contract checks if +the message length is sufficient before extracting the `withdraw` flag. The `swapAndWithdraw` function has also been modified to conditionally handle gas fees based on whether the tokens will be withdrawn. If the `withdraw` flag @@ -236,9 +235,9 @@ Additionally, a new public `swap` function has been introduced, which allows users to interact with the contract directly on ZetaChain. This function is particularly useful if you already have tokens on ZetaChain and want to swap them without making a cross-chain call. It takes in parameters similar to those -in `onCrossChainCall`, transfers the input tokens from the sender to the -contract, and then calls `swapAndWithdraw` to perform the swap and handle -withdrawal or direct transfer based on the `withdraw` flag. +in `onCall`, transfers the input tokens from the sender to the contract, and +then calls `swapAndWithdraw` to perform the swap and handle withdrawal or direct +transfer based on the `withdraw` flag. Finally, the contract now imports the `IWETH9` interface to handle direct token transfers when `withdraw` is `false`. This interface facilitates the transfer of @@ -283,7 +282,7 @@ npx hardhat swap-from-evm --network localhost --receiver 0x84eA74d481Ee0A5332c45 - EVM gateway is called with 1 native gas token (ETH) and a message that contains target ZRC-20 token address, receiver address and a boolean that indicates to withdraw a token to the destination chain or not. -- `onCrossChainCall` is called +- `onCall` is called - If `withdraw` is: - true, withdraw the ZRC-20 to the destination chain as a native token - false, send target ZRC-20 to the recipient diff --git a/src/pages/developers/tutorials/swap.mdx b/src/pages/developers/tutorials/swap.mdx index 067adb80..8d828797 100644 --- a/src/pages/developers/tutorials/swap.mdx +++ b/src/pages/developers/tutorials/swap.mdx @@ -185,10 +185,10 @@ information: `bytes` because the recipient could be on an EVM chain (like Ethereum or BNB) or on a non-EVM chain like Bitcoin. -When the `onCrossChainCall` function is invoked, it receives a `message` -parameter that needs to be decoded to extract the swap details. The encoding of -this message varies depending on the source chain due to different limitations -and requirements. +When the `onCall` function is invoked, it receives a `message` parameter that +needs to be decoded to extract the swap details. The encoding of this message +varies depending on the source chain due to different limitations and +requirements. - **For Bitcoin**: Since Bitcoin has an upper limit of 80 bytes for OP_RETURN messages, the contract uses a more efficient encoding. It extracts the @@ -326,8 +326,8 @@ When you execute this command, the script calls the `gateway.depositAndCall` method on the connected EVM chain, depositing 1 ETH and sending a message to the Swap contract on ZetaChain. -ZetaChain then picks up the event and executes the `onCrossChainCall` function -of the Swap contract with the provided message. +ZetaChain then picks up the event and executes the `onCall` function of the Swap +contract with the provided message. The Swap contract decodes the message, identifies the target ERC-20 token and recipient, and initiates the swap logic. @@ -352,8 +352,8 @@ When you run the command, the script calls the `gateway.depositAndCall` method with the specified ERC-20 token and amount, sending a message to the Swap contract on ZetaChain. -ZetaChain picks up the event and executes the `onCrossChainCall` function of the -Swap contract: +ZetaChain picks up the event and executes the `onCall` function of the Swap +contract: The Swap contract decodes the message, identifies the target gas token and recipient, and initiates the swap logic.