From cc57caa123dc1b379ed1aef8a4a0cbaa56afb68c Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 3 Oct 2024 12:13:07 +0300 Subject: [PATCH 01/15] Call from EVM --- examples/hello/README.md | 46 ++++++-- .../hello/contracts/{Revert.sol => Echo.sol} | 17 ++- examples/hello/hardhat.config.ts | 4 +- examples/hello/package.json | 4 +- examples/hello/tasks/callFromEVM.ts | 103 ++++++++++++++++++ .../{gatewayCall.ts => callFromZetachain.ts} | 7 +- examples/hello/tasks/deploy.ts | 6 +- examples/hello/tasks/deployRevert.ts | 31 ------ examples/swap/package.json | 2 +- 9 files changed, 169 insertions(+), 51 deletions(-) rename examples/hello/contracts/{Revert.sol => Echo.sol} (55%) create mode 100644 examples/hello/tasks/callFromEVM.ts rename examples/hello/tasks/{gatewayCall.ts => callFromZetachain.ts} (93%) delete mode 100644 examples/hello/tasks/deployRevert.ts diff --git a/examples/hello/README.md b/examples/hello/README.md index 62730f9d..5cadb39d 100644 --- a/examples/hello/README.md +++ b/examples/hello/README.md @@ -1,15 +1,45 @@ -# ZetaChain Contracts Template +# Hello Example -## Getting Started +``` +yarn deploy +``` + +## EVM + +Successful call: + +``` +npx hardhat call-from-evm --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["string"]' hello +``` + +Failed call: + +``` +npx hardhat call-from-evm --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["uint256"]' 42 +``` -Install dependencies: +Failed call with handled revert: ``` -yarn +npx hardhat call-from-evm --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --revert-message 0x --call-on-revert --types '["uint256"]' 42 ``` -## Next Steps +## ZetaChain -Ready to dive in? Follow our [**🚀 smart contract -tutorials**](https://www.zetachain.com/docs/developers/tutorials/intro/) to -start building universal app contracts. +Successful call: + +``` +npx hardhat call-from-zetachain --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello +``` + +Failed call: + +``` +npx hardhat call-from-zetachain --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42 +``` + +Failed call with handled revert: + +``` +npx hardhat call-from-zetachain --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --revert-address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --revert-message 0x --call-on-revert --types '["uint256"]' 42 +``` diff --git a/examples/hello/contracts/Revert.sol b/examples/hello/contracts/Echo.sol similarity index 55% rename from examples/hello/contracts/Revert.sol rename to examples/hello/contracts/Echo.sol index aa0b821e..8cbe185a 100644 --- a/examples/hello/contracts/Revert.sol +++ b/examples/hello/contracts/Echo.sol @@ -2,11 +2,18 @@ pragma solidity 0.8.26; import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol"; +import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol"; + +contract Echo { + GatewayEVM public gateway; -contract Revert { event RevertEvent(string, RevertContext); event HelloEvent(string, string); + constructor(address payable gatewayAddress) { + gateway = GatewayEVM(gatewayAddress); + } + function hello(string memory message) external { emit HelloEvent("Hello on EVM", message); } @@ -15,6 +22,14 @@ contract Revert { emit RevertEvent("Revert on EVM", revertContext); } + function gatewayCall( + address receiver, + bytes calldata message, + RevertOptions memory revertOptions + ) external { + gateway.call(receiver, message, revertOptions); + } + receive() external payable {} fallback() external payable {} diff --git a/examples/hello/hardhat.config.ts b/examples/hello/hardhat.config.ts index 7b9bd47f..b4454dba 100644 --- a/examples/hello/hardhat.config.ts +++ b/examples/hello/hardhat.config.ts @@ -1,6 +1,6 @@ import "./tasks/deploy"; -import "./tasks/deployRevert"; -import "./tasks/gatewayCall"; +import "./tasks/callFromZetachain"; +import "./tasks/callFromEVM"; import "@zetachain/localnet/tasks"; import "@nomicfoundation/hardhat-toolbox"; import "@zetachain/toolkit/tasks"; diff --git a/examples/hello/package.json b/examples/hello/package.json index 2a8151fd..bb47d44b 100644 --- a/examples/hello/package.json +++ b/examples/hello/package.json @@ -7,7 +7,7 @@ "test": "echo \"Error: no test specified\" && exit 1", "lint:fix": "npx eslint . --ext .js,.ts --fix", "lint": "npx eslint . --ext .js,.ts", - "deploy": "npx hardhat compile --force && npx hardhat deploy --network localhost && npx hardhat deploy-revert --network localhost" + "deploy": "npx hardhat compile --force && npx hardhat deploy --network localhost && npx hardhat deploy --name Echo --network localhost --gateway 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" }, "keywords": [], "author": "", @@ -59,4 +59,4 @@ "@solana/web3.js": "^1.95.2", "@zetachain/protocol-contracts": "10.0.0-rc10" } -} +} \ No newline at end of file diff --git a/examples/hello/tasks/callFromEVM.ts b/examples/hello/tasks/callFromEVM.ts new file mode 100644 index 00000000..19977041 --- /dev/null +++ b/examples/hello/tasks/callFromEVM.ts @@ -0,0 +1,103 @@ +import { task, types } from "hardhat/config"; +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { ethers } = hre; + const [signer] = await ethers.getSigners(); + + const txOptions = { + gasPrice: args.txOptionsGasPrice, + gasLimit: args.txOptionsGasLimit, + }; + + const revertOptions = { + abortAddress: "0x0000000000000000000000000000000000000000", // not used + callOnRevert: args.callOnRevert, + onRevertGasLimit: args.onRevertGasLimit, + revertAddress: args.revertAddress, + revertMessage: ethers.utils.hexlify( + ethers.utils.toUtf8Bytes(args.revertMessage) + ), + }; + + const types = JSON.parse(args.types); + + const valuesArray = args.values.map((value: any, index: number) => { + const type = types[index]; + + if (type === "bool") { + try { + return JSON.parse(value.toLowerCase()); + } catch (e) { + throw new Error(`Invalid boolean value: ${value}`); + } + } else if (type.startsWith("uint") || type.startsWith("int")) { + return ethers.BigNumber.from(value); + } else { + return value; + } + }); + const encodedParameters = ethers.utils.defaultAbiCoder.encode( + types, + valuesArray + ); + + const gasLimit = hre.ethers.BigNumber.from(args.gasLimit); + + const factory = (await hre.ethers.getContractFactory(args.name)) as any; + const contract = factory.attach(args.contract); + + const tx = await contract.gatewayCall( + args.receiver, + encodedParameters, + revertOptions, + txOptions + ); + + console.log(`Transaction hash: ${tx.hash}`); + await tx.wait(); + console.log("gatewayCall executed successfully"); +}; + +task("call-from-evm", "Calls the gateway on a contract on EVM", main) + .addParam("contract", "The address of the deployed contract") + .addOptionalParam( + "gasLimit", + "Gas limit for for a cross-chain call", + 7000000, + types.int + ) + .addOptionalParam( + "txOptionsGasPrice", + "The gas price for the transaction", + 10000000000, + types.int + ) + .addOptionalParam( + "txOptionsGasLimit", + "The gas limit for the transaction", + 7000000, + types.int + ) + .addFlag("callOnRevert", "Whether to call on revert") + .addOptionalParam( + "revertAddress", + "Revert address", + "0x0000000000000000000000000000000000000000" + ) + .addOptionalParam("revertMessage", "Revert message", "0x") + .addParam( + "receiver", + "The address of the receiver contract on a connected chain" + ) + .addOptionalParam( + "onRevertGasLimit", + "The gas limit for the revert transaction", + 7000000, + types.int + ) + .addParam("name", "The name of the contract", "Echo") + .addParam("types", `The types of the parameters (example: '["string"]')`) + .addVariadicPositionalParam("values", "The values of the parameters"); + +module.exports = {}; diff --git a/examples/hello/tasks/gatewayCall.ts b/examples/hello/tasks/callFromZetachain.ts similarity index 93% rename from examples/hello/tasks/gatewayCall.ts rename to examples/hello/tasks/callFromZetachain.ts index 35a34acd..ccf2325d 100644 --- a/examples/hello/tasks/gatewayCall.ts +++ b/examples/hello/tasks/callFromZetachain.ts @@ -60,7 +60,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { await zrc20TransferTx.wait(); - const factory = await hre.ethers.getContractFactory("Hello"); + const factory = (await hre.ethers.getContractFactory(args.name)) as any; const contract = factory.attach(args.contract); const tx = await contract.gatewayCall( @@ -78,8 +78,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { }; task( - "gateway-call", - "Calls the gatewayCall function on the Hello contract", + "call-from-zetachain", + "Calls the gatewayCall function on a contract on ZetaChain", main ) .addParam("contract", "The address of the deployed Hello contract") @@ -120,6 +120,7 @@ task( types.int ) .addParam("function", `Function to call (example: "hello(string)")`) + .addParam("name", "The name of the contract", "Hello") .addParam("types", `The types of the parameters (example: '["string"]')`) .addVariadicPositionalParam("values", "The values of the parameters"); diff --git a/examples/hello/tasks/deploy.ts b/examples/hello/tasks/deploy.ts index 647ea6bf..877d2b34 100644 --- a/examples/hello/tasks/deploy.ts +++ b/examples/hello/tasks/deploy.ts @@ -12,7 +12,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } const factory = await hre.ethers.getContractFactory(args.name); - const contract = await (factory as any).deploy(args.gatewayZetaChain); + const contract = await (factory as any).deploy(args.gateway); await contract.deployed(); if (args.json) { @@ -30,7 +30,7 @@ task("deploy", "Deploy the contract", main) .addFlag("json", "Output in JSON") .addOptionalParam("name", "Contract to deploy", "Hello") .addOptionalParam( - "gatewayZetaChain", - "Gateway address", + "gateway", + "Gateway address (default: ZetaChain Gateway)", "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" ); diff --git a/examples/hello/tasks/deployRevert.ts b/examples/hello/tasks/deployRevert.ts deleted file mode 100644 index 080808c7..00000000 --- a/examples/hello/tasks/deployRevert.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { task, types } from "hardhat/config"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; - -const main = async (args: any, hre: HardhatRuntimeEnvironment) => { - const network = hre.network.name; - - const [signer] = await hre.ethers.getSigners(); - if (signer === undefined) { - throw new Error( - `Wallet not found. Please, run "npx hardhat account --save" or set PRIVATE_KEY env variable (for example, in a .env file)` - ); - } - - const factory = await hre.ethers.getContractFactory(args.name); - const contract = await (factory as any).deploy(); - await contract.deployed(); - - if (args.json) { - console.log(JSON.stringify(contract)); - } else { - console.log(`🔑 Using account: ${signer.address} - -🚀 Successfully deployed "${args.name}" contract on ${network}. -📜 Contract address: ${contract.address} -`); - } -}; - -task("deploy-revert", "Deploy the contract", main) - .addFlag("json", "Output in JSON") - .addOptionalParam("name", "Contract to deploy", "Revert"); diff --git a/examples/swap/package.json b/examples/swap/package.json index 2d5c7eae..4c95cb25 100644 --- a/examples/swap/package.json +++ b/examples/swap/package.json @@ -59,4 +59,4 @@ "@zetachain/protocol-contracts": "10.0.0-rc10", "@zetachain/toolkit": "13.0.0-rc4" } -} +} \ No newline at end of file From 73379dd8226cbf9c867358c3e16ed5ea24c77dbc Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 3 Oct 2024 13:26:49 +0300 Subject: [PATCH 02/15] immutable --- examples/hello/contracts/Echo.sol | 2 +- examples/hello/contracts/Hello.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/hello/contracts/Echo.sol b/examples/hello/contracts/Echo.sol index 8cbe185a..ff30d66e 100644 --- a/examples/hello/contracts/Echo.sol +++ b/examples/hello/contracts/Echo.sol @@ -5,7 +5,7 @@ import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol" import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol"; contract Echo { - GatewayEVM public gateway; + GatewayEVM public immutable gateway; event RevertEvent(string, RevertContext); event HelloEvent(string, string); diff --git a/examples/hello/contracts/Hello.sol b/examples/hello/contracts/Hello.sol index da9310cb..075365e9 100644 --- a/examples/hello/contracts/Hello.sol +++ b/examples/hello/contracts/Hello.sol @@ -7,7 +7,7 @@ import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol import "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol"; contract Hello is UniversalContract { - GatewayZEVM public gateway; + GatewayZEVM public immutable gateway; event HelloEvent(string, string); event RevertEvent(string, RevertContext); From 581470461db2305ccd33a4990994b441e86f371d Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 3 Oct 2024 13:28:01 +0300 Subject: [PATCH 03/15] gateway param --- examples/swap/tasks/deploy.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/swap/tasks/deploy.ts b/examples/swap/tasks/deploy.ts index e5858fb9..c8c98ba2 100644 --- a/examples/swap/tasks/deploy.ts +++ b/examples/swap/tasks/deploy.ts @@ -14,7 +14,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const factory = await hre.ethers.getContractFactory(args.name); const contract = await (factory as any).deploy( args.systemContract, - args.gatewayZetaChain + args.gateway ); await contract.deployed(); @@ -38,7 +38,7 @@ task("deploy", "Deploy the contract", main) "0x610178dA211FEF7D417bC0e6FeD39F05609AD788" ) .addOptionalParam( - "gatewayZetaChain", - "Gateway address", + "gateway", + "Gateway address (default: ZetaChain Gateway)", "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" ); From 231e85621e37e9980a43366637e8109b15c43bc2 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 3 Oct 2024 13:29:36 +0300 Subject: [PATCH 04/15] check types/values length --- examples/hello/tasks/callFromEVM.ts | 6 ++++++ examples/hello/tasks/callFromZetachain.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/examples/hello/tasks/callFromEVM.ts b/examples/hello/tasks/callFromEVM.ts index 19977041..f4cb53be 100644 --- a/examples/hello/tasks/callFromEVM.ts +++ b/examples/hello/tasks/callFromEVM.ts @@ -22,6 +22,12 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const types = JSON.parse(args.types); + if (types.length !== args.values.length) { + throw new Error( + `The number of types (${types.length}) does not match the number of values (${args.values.length}).` + ); + } + const valuesArray = args.values.map((value: any, index: number) => { const type = types[index]; diff --git a/examples/hello/tasks/callFromZetachain.ts b/examples/hello/tasks/callFromZetachain.ts index ccf2325d..7110fbc2 100644 --- a/examples/hello/tasks/callFromZetachain.ts +++ b/examples/hello/tasks/callFromZetachain.ts @@ -25,6 +25,12 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const types = JSON.parse(args.types); + if (types.length !== args.values.length) { + throw new Error( + `The number of types (${types.length}) does not match the number of values (${args.values.length}).` + ); + } + const valuesArray = args.values.map((value: any, index: number) => { const type = types[index]; From 6e40182991bc1b933bbfc2711dabdc41d355f066 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 3 Oct 2024 13:31:32 +0300 Subject: [PATCH 05/15] removed gas limit param --- examples/hello/tasks/callFromEVM.ts | 8 -------- examples/hello/tasks/callFromZetachain.ts | 8 +------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/examples/hello/tasks/callFromEVM.ts b/examples/hello/tasks/callFromEVM.ts index f4cb53be..04cf689c 100644 --- a/examples/hello/tasks/callFromEVM.ts +++ b/examples/hello/tasks/callFromEVM.ts @@ -48,8 +48,6 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { valuesArray ); - const gasLimit = hre.ethers.BigNumber.from(args.gasLimit); - const factory = (await hre.ethers.getContractFactory(args.name)) as any; const contract = factory.attach(args.contract); @@ -67,12 +65,6 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { task("call-from-evm", "Calls the gateway on a contract on EVM", main) .addParam("contract", "The address of the deployed contract") - .addOptionalParam( - "gasLimit", - "Gas limit for for a cross-chain call", - 7000000, - types.int - ) .addOptionalParam( "txOptionsGasPrice", "The gas price for the transaction", diff --git a/examples/hello/tasks/callFromZetachain.ts b/examples/hello/tasks/callFromZetachain.ts index 7110fbc2..fe707321 100644 --- a/examples/hello/tasks/callFromZetachain.ts +++ b/examples/hello/tasks/callFromZetachain.ts @@ -55,7 +55,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ethers.utils.concat([functionSignature, encodedParameters]) ); - const gasLimit = hre.ethers.BigNumber.from(args.gasLimit); + const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit); const zrc20 = new ethers.Contract(args.zrc20, ZRC20ABI.abi, signer); const [, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(gasLimit); const zrc20TransferTx = await zrc20.transfer( @@ -90,12 +90,6 @@ task( ) .addParam("contract", "The address of the deployed Hello contract") .addParam("zrc20", "The address of ZRC-20 to pay fees") - .addOptionalParam( - "gasLimit", - "Gas limit for for a cross-chain call", - 7000000, - types.int - ) .addOptionalParam( "txOptionsGasPrice", "The gas price for the transaction", From e2238613f04d342e1790c496c110bb0470c7006c Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 3 Oct 2024 13:32:26 +0300 Subject: [PATCH 06/15] connect signer --- examples/hello/tasks/callFromEVM.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hello/tasks/callFromEVM.ts b/examples/hello/tasks/callFromEVM.ts index 04cf689c..c19f9917 100644 --- a/examples/hello/tasks/callFromEVM.ts +++ b/examples/hello/tasks/callFromEVM.ts @@ -49,7 +49,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); const factory = (await hre.ethers.getContractFactory(args.name)) as any; - const contract = factory.attach(args.contract); + const contract = factory.attach(args.contract).connect(signer); const tx = await contract.gatewayCall( args.receiver, From 923f04136b5c094fb614a3726d88013bb4dcd487 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Fri, 4 Oct 2024 11:40:30 +0300 Subject: [PATCH 07/15] update localnet --- examples/hello/package.json | 4 ++-- examples/hello/yarn.lock | 8 ++++---- examples/swap/package.json | 4 ++-- examples/swap/yarn.lock | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/hello/package.json b/examples/hello/package.json index bb47d44b..e2dd01aa 100644 --- a/examples/hello/package.json +++ b/examples/hello/package.json @@ -28,7 +28,7 @@ "@types/node": ">=12.0.0", "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", - "@zetachain/localnet": "^3.0.4", + "@zetachain/localnet": "^3.2.0", "@zetachain/toolkit": "13.0.0-rc2", "axios": "^1.3.6", "chai": "^4.2.0", @@ -59,4 +59,4 @@ "@solana/web3.js": "^1.95.2", "@zetachain/protocol-contracts": "10.0.0-rc10" } -} \ No newline at end of file +} diff --git a/examples/hello/yarn.lock b/examples/hello/yarn.lock index 246fb4e9..ddb129d5 100644 --- a/examples/hello/yarn.lock +++ b/examples/hello/yarn.lock @@ -2407,10 +2407,10 @@ typescript "5.5.4" zod "3.22.4" -"@zetachain/localnet@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-3.0.4.tgz#ff457f732f9ea52f491c16dc4cc5ac77d9561a9b" - integrity sha512-biZhhonyUrtXSZCPzunT6x6pKK3GANtFtwkXHoEnDfQsjICRgfBMMrC76IsfM8XgEdRF15dp845QeDHMa19GkA== +"@zetachain/localnet@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-3.2.0.tgz#66c09120397dbaf4f0c461ba6671f249c3379f6b" + integrity sha512-oqyxrxuSraj1A6/CAkeEBa9VfIvp+QxBIivTu/L9jK1zUa5MQw+rLqTL/rD1LR/k9om6x/zJHzhzZKU9Vpk3Bw== dependencies: "@inquirer/prompts" "^5.5.0" "@uniswap/v2-core" "^1.0.1" diff --git a/examples/swap/package.json b/examples/swap/package.json index 4c95cb25..d3398027 100644 --- a/examples/swap/package.json +++ b/examples/swap/package.json @@ -28,7 +28,7 @@ "@types/node": ">=12.0.0", "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", - "@zetachain/localnet": "^3.0.4", + "@zetachain/localnet": "^3.2.0", "axios": "^1.3.6", "chai": "^4.2.0", "dotenv": "^16.0.3", @@ -59,4 +59,4 @@ "@zetachain/protocol-contracts": "10.0.0-rc10", "@zetachain/toolkit": "13.0.0-rc4" } -} \ No newline at end of file +} diff --git a/examples/swap/yarn.lock b/examples/swap/yarn.lock index a991d4d3..7f6c175e 100644 --- a/examples/swap/yarn.lock +++ b/examples/swap/yarn.lock @@ -2140,10 +2140,10 @@ typescript "5.5.4" zod "3.22.4" -"@zetachain/localnet@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-3.0.4.tgz#ff457f732f9ea52f491c16dc4cc5ac77d9561a9b" - integrity sha512-biZhhonyUrtXSZCPzunT6x6pKK3GANtFtwkXHoEnDfQsjICRgfBMMrC76IsfM8XgEdRF15dp845QeDHMa19GkA== +"@zetachain/localnet@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-3.2.0.tgz#66c09120397dbaf4f0c461ba6671f249c3379f6b" + integrity sha512-oqyxrxuSraj1A6/CAkeEBa9VfIvp+QxBIivTu/L9jK1zUa5MQw+rLqTL/rD1LR/k9om6x/zJHzhzZKU9Vpk3Bw== dependencies: "@inquirer/prompts" "^5.5.0" "@uniswap/v2-core" "^1.0.1" From f64ec1dba68926aa4cb4db00d5ffda187018ca19 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Fri, 4 Oct 2024 20:37:25 +0300 Subject: [PATCH 08/15] withdraw and call --- examples/hello/README.md | 12 +- examples/hello/contracts/Echo.sol | 4 +- examples/hello/contracts/Hello.sol | 28 +++- examples/hello/hardhat.config.ts | 5 +- examples/hello/package.json | 2 +- .../tasks/{callFromEVM.ts => echoCall.ts} | 6 +- .../{callFromZetachain.ts => helloCall.ts} | 6 +- examples/hello/tasks/helloWithdrawAndCall.ts | 139 ++++++++++++++++++ examples/hello/yarn.lock | 16 +- 9 files changed, 188 insertions(+), 30 deletions(-) rename examples/hello/tasks/{callFromEVM.ts => echoCall.ts} (95%) rename examples/hello/tasks/{callFromZetachain.ts => helloCall.ts} (97%) create mode 100644 examples/hello/tasks/helloWithdrawAndCall.ts diff --git a/examples/hello/README.md b/examples/hello/README.md index 5cadb39d..e666d957 100644 --- a/examples/hello/README.md +++ b/examples/hello/README.md @@ -9,19 +9,19 @@ yarn deploy Successful call: ``` -npx hardhat call-from-evm --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["string"]' hello +npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["string"]' hello ``` Failed call: ``` -npx hardhat call-from-evm --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["uint256"]' 42 +npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["uint256"]' 42 ``` Failed call with handled revert: ``` -npx hardhat call-from-evm --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --revert-message 0x --call-on-revert --types '["uint256"]' 42 +npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --revert-message 0x --call-on-revert --types '["uint256"]' 42 ``` ## ZetaChain @@ -29,17 +29,17 @@ npx hardhat call-from-evm --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E Successful call: ``` -npx hardhat call-from-zetachain --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello +npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello ``` Failed call: ``` -npx hardhat call-from-zetachain --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42 +npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42 ``` Failed call with handled revert: ``` -npx hardhat call-from-zetachain --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --revert-address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --revert-message 0x --call-on-revert --types '["uint256"]' 42 +npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --revert-address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --revert-message 0x --call-on-revert --types '["uint256"]' 42 ``` diff --git a/examples/hello/contracts/Echo.sol b/examples/hello/contracts/Echo.sol index ff30d66e..a5271205 100644 --- a/examples/hello/contracts/Echo.sol +++ b/examples/hello/contracts/Echo.sol @@ -14,7 +14,7 @@ contract Echo { gateway = GatewayEVM(gatewayAddress); } - function hello(string memory message) external { + function hello(string memory message) external payable { emit HelloEvent("Hello on EVM", message); } @@ -22,7 +22,7 @@ contract Echo { emit RevertEvent("Revert on EVM", revertContext); } - function gatewayCall( + function call( address receiver, bytes calldata message, RevertOptions memory revertOptions diff --git a/examples/hello/contracts/Hello.sol b/examples/hello/contracts/Hello.sol index 075365e9..5546f8f0 100644 --- a/examples/hello/contracts/Hello.sol +++ b/examples/hello/contracts/Hello.sol @@ -30,7 +30,7 @@ contract Hello is UniversalContract { emit RevertEvent("Revert on ZetaChain", revertContext); } - function gatewayCall( + function call( bytes memory receiver, address zrc20, bytes calldata message, @@ -41,4 +41,30 @@ contract Hello is UniversalContract { IZRC20(zrc20).approve(address(gateway), gasFee); gateway.call(receiver, zrc20, message, gasLimit, revertOptions); } + + function withdrawAndCall( + bytes memory receiver, + uint256 amount, + address zrc20, + bytes calldata message, + uint256 gasLimit, + RevertOptions memory revertOptions + ) external { + (address gasZRC20, uint256 gasFee) = IZRC20(zrc20) + .withdrawGasFeeWithGasLimit(gasLimit); + if (zrc20 == gasZRC20) { + IZRC20(zrc20).approve(address(gateway), amount + gasFee); + } else { + IZRC20(zrc20).approve(address(gateway), amount); + IZRC20(gasZRC20).approve(address(gateway), gasFee); + } + gateway.withdrawAndCall( + receiver, + amount, + zrc20, + message, + gasLimit, + revertOptions + ); + } } diff --git a/examples/hello/hardhat.config.ts b/examples/hello/hardhat.config.ts index b4454dba..c41f9d0b 100644 --- a/examples/hello/hardhat.config.ts +++ b/examples/hello/hardhat.config.ts @@ -1,6 +1,7 @@ import "./tasks/deploy"; -import "./tasks/callFromZetachain"; -import "./tasks/callFromEVM"; +import "./tasks/helloCall"; +import "./tasks/echoCall"; +import "./tasks/helloWithdrawAndCall"; import "@zetachain/localnet/tasks"; import "@nomicfoundation/hardhat-toolbox"; import "@zetachain/toolkit/tasks"; diff --git a/examples/hello/package.json b/examples/hello/package.json index e2dd01aa..ccdadd72 100644 --- a/examples/hello/package.json +++ b/examples/hello/package.json @@ -29,7 +29,7 @@ "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", "@zetachain/localnet": "^3.2.0", - "@zetachain/toolkit": "13.0.0-rc2", + "@zetachain/toolkit": "13.0.0-rc4", "axios": "^1.3.6", "chai": "^4.2.0", "dotenv": "^16.0.3", diff --git a/examples/hello/tasks/callFromEVM.ts b/examples/hello/tasks/echoCall.ts similarity index 95% rename from examples/hello/tasks/callFromEVM.ts rename to examples/hello/tasks/echoCall.ts index c19f9917..ee8c46f0 100644 --- a/examples/hello/tasks/callFromEVM.ts +++ b/examples/hello/tasks/echoCall.ts @@ -51,7 +51,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const factory = (await hre.ethers.getContractFactory(args.name)) as any; const contract = factory.attach(args.contract).connect(signer); - const tx = await contract.gatewayCall( + const tx = await contract.call( args.receiver, encodedParameters, revertOptions, @@ -63,7 +63,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { console.log("gatewayCall executed successfully"); }; -task("call-from-evm", "Calls the gateway on a contract on EVM", main) +task("echo-call", "Calls the gateway on a contract on EVM", main) .addParam("contract", "The address of the deployed contract") .addOptionalParam( "txOptionsGasPrice", @@ -97,5 +97,3 @@ task("call-from-evm", "Calls the gateway on a contract on EVM", main) .addParam("name", "The name of the contract", "Echo") .addParam("types", `The types of the parameters (example: '["string"]')`) .addVariadicPositionalParam("values", "The values of the parameters"); - -module.exports = {}; diff --git a/examples/hello/tasks/callFromZetachain.ts b/examples/hello/tasks/helloCall.ts similarity index 97% rename from examples/hello/tasks/callFromZetachain.ts rename to examples/hello/tasks/helloCall.ts index fe707321..92ca946a 100644 --- a/examples/hello/tasks/callFromZetachain.ts +++ b/examples/hello/tasks/helloCall.ts @@ -69,7 +69,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const factory = (await hre.ethers.getContractFactory(args.name)) as any; const contract = factory.attach(args.contract); - const tx = await contract.gatewayCall( + const tx = await contract.call( ethers.utils.hexlify(args.receiver), args.zrc20, message, @@ -84,7 +84,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { }; task( - "call-from-zetachain", + "hello-call", "Calls the gatewayCall function on a contract on ZetaChain", main ) @@ -123,5 +123,3 @@ task( .addParam("name", "The name of the contract", "Hello") .addParam("types", `The types of the parameters (example: '["string"]')`) .addVariadicPositionalParam("values", "The values of the parameters"); - -module.exports = {}; diff --git a/examples/hello/tasks/helloWithdrawAndCall.ts b/examples/hello/tasks/helloWithdrawAndCall.ts new file mode 100644 index 00000000..b2799483 --- /dev/null +++ b/examples/hello/tasks/helloWithdrawAndCall.ts @@ -0,0 +1,139 @@ +import { task, types } from "hardhat/config"; +import type { HardhatRuntimeEnvironment } from "hardhat/types"; +import ZRC20ABI from "@zetachain/protocol-contracts/abi/ZRC20.sol/ZRC20.json"; + +const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { ethers } = hre; + const [signer] = await ethers.getSigners(); + + const txOptions = { + gasPrice: args.txOptionsGasPrice, + gasLimit: args.txOptionsGasLimit, + }; + + const revertOptions = { + abortAddress: "0x0000000000000000000000000000000000000000", // not used + callOnRevert: args.callOnRevert, + onRevertGasLimit: args.onRevertGasLimit, + revertAddress: args.revertAddress, + revertMessage: ethers.utils.hexlify( + ethers.utils.toUtf8Bytes(args.revertMessage) + ), + }; + + const functionSignature = ethers.utils.id(args.function).slice(0, 10); + + const types = JSON.parse(args.types); + + if (types.length !== args.values.length) { + throw new Error( + `The number of types (${types.length}) does not match the number of values (${args.values.length}).` + ); + } + + const valuesArray = args.values.map((value: any, index: number) => { + const type = types[index]; + + if (type === "bool") { + try { + return JSON.parse(value.toLowerCase()); + } catch (e) { + throw new Error(`Invalid boolean value: ${value}`); + } + } else if (type.startsWith("uint") || type.startsWith("int")) { + return ethers.BigNumber.from(value); + } else { + return value; + } + }); + const encodedParameters = ethers.utils.defaultAbiCoder.encode( + types, + valuesArray + ); + + const message = ethers.utils.hexlify( + ethers.utils.concat([functionSignature, encodedParameters]) + ); + + const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit); + + const amount = hre.ethers.utils.parseUnits(args.amount, 18); + + const zrc20 = new ethers.Contract(args.zrc20, ZRC20ABI.abi, signer); + const [gasZRC20, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(gasLimit); + const gasZRC20Contract = new ethers.Contract(gasZRC20, ZRC20ABI.abi, signer); + const gasFeeTransfer = await gasZRC20Contract.transfer( + args.contract, + gasZRC20 == args.zrc20 ? gasFee.add(amount) : gasFee, + txOptions + ); + await gasFeeTransfer.wait(); + + if (gasZRC20 !== args.zrc20) { + const targetTokenTransfer = await zrc20.transfer( + args.contract, + gasFee.add(amount), + txOptions + ); + await targetTokenTransfer.wait(); + } + + const factory = (await hre.ethers.getContractFactory(args.name)) as any; + const contract = factory.attach(args.contract); + + const tx = await contract.withdrawAndCall( + ethers.utils.hexlify(args.receiver), + amount, + args.zrc20, + message, + gasLimit, + revertOptions, + txOptions + ); + + console.log(`Transaction hash: ${tx.hash}`); + await tx.wait(); + console.log("gatewayCall executed successfully"); +}; + +task( + "hello-withdraw-and-call", + "Calls the gatewayWithdrawAndCall function on a contract on ZetaChain", + main +) + .addParam("contract", "The address of the deployed Hello contract") + .addParam("zrc20", "The address of ZRC-20 to pay fees") + .addOptionalParam( + "txOptionsGasPrice", + "The gas price for the transaction", + 10000000000, + types.int + ) + .addOptionalParam( + "txOptionsGasLimit", + "The gas limit for the transaction", + 7000000, + types.int + ) + .addFlag("callOnRevert", "Whether to call on revert") + .addOptionalParam( + "revertAddress", + "Revert address", + "0x0000000000000000000000000000000000000000" + ) + .addOptionalParam("revertMessage", "Revert message", "0x") + .addParam( + "receiver", + "The address of the receiver contract on a connected chain" + ) + .addOptionalParam( + "onRevertGasLimit", + "The gas limit for the revert transaction", + 7000000, + types.int + ) + .addParam("function", `Function to call (example: "hello(string)")`) + .addParam("name", "The name of the contract", "Hello") + .addParam("amount", "Amount of ZRC-20 to withdraw") + .addParam("types", `The types of the parameters (example: '["string"]')`) + .addVariadicPositionalParam("values", "The values of the parameters"); diff --git a/examples/hello/yarn.lock b/examples/hello/yarn.lock index ddb129d5..7714ffa2 100644 --- a/examples/hello/yarn.lock +++ b/examples/hello/yarn.lock @@ -1669,11 +1669,6 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.0.2.tgz#3e5321a2ecdd0b206064356798c21225b6ec7105" integrity sha512-0MmkHSHiW2NRFiT9/r5Lu4eJq5UJ4/tzlOgYXNAIj/ONkQTVnz22pLxDvp4C4uZ9he7ZFvGn3Driptn1/iU7tQ== -"@openzeppelin/contracts@^4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.6.tgz#2a880a24eb19b4f8b25adc2a5095f2aa27f39677" - integrity sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA== - "@openzeppelin/contracts@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210" @@ -2443,16 +2438,17 @@ resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-9.0.0.tgz#c20ad5da43f6f3676f31556b303d1cb4ea17357e" integrity sha512-L4A8bddlyhjaBAsIv/x1Bvxc38RJz8U8rbbBtxK5oVyOAd5Zz04ZiT3HqzO4FuKq6RGGM1uiA8jvUfmRkKchXw== -"@zetachain/toolkit@13.0.0-rc2": - version "13.0.0-rc2" - resolved "https://registry.yarnpkg.com/@zetachain/toolkit/-/toolkit-13.0.0-rc2.tgz#8b85ecea407c572fa9f7c693367266ecf1a55540" - integrity sha512-0Nc0qjAfIZ0r7BjgAM2AcOxYaMtDLAxpU5Si6f814m/SPhbPYP/V91HgARj1Ia1IvH9g0NyqvQLnKlBrCh9r9w== +"@zetachain/toolkit@13.0.0-rc4": + version "13.0.0-rc4" + resolved "https://registry.yarnpkg.com/@zetachain/toolkit/-/toolkit-13.0.0-rc4.tgz#e137fc16043f1416469f709c48808cfa301d9299" + integrity sha512-4z4MKbQKjRIeNruUyDBjZDRO5oTLa1w/7wVn+PfMsXn++mFFGkiawkLcitnkH9dadBJiERzmo89MRJxsLQ3U6w== dependencies: "@coral-xyz/anchor" "^0.30.1" "@inquirer/prompts" "^2.1.1" "@inquirer/select" "1.1.3" "@nomiclabs/hardhat-ethers" "^2.2.3" - "@openzeppelin/contracts" "^4.9.6" + "@openzeppelin/contracts" "^5.0.2" + "@openzeppelin/contracts-upgradeable" "^5.0.2" "@solana/web3.js" "^1.95.3" "@uniswap/v2-periphery" "^1.1.0-beta.0" "@zetachain/faucet-cli" "^4.1.1" From 6e921bfdc34a6f284a1a328a7958c2a360a93cce Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Fri, 4 Oct 2024 20:40:29 +0300 Subject: [PATCH 09/15] update addresses --- examples/hello/README.md | 12 ++++++------ examples/hello/contracts/Echo.sol | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/examples/hello/README.md b/examples/hello/README.md index e666d957..91e91fc6 100644 --- a/examples/hello/README.md +++ b/examples/hello/README.md @@ -9,19 +9,19 @@ yarn deploy Successful call: ``` -npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["string"]' hello +npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --network localhost --types '["string"]' hello ``` Failed call: ``` -npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --types '["uint256"]' 42 +npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --network localhost --types '["uint256"]' 42 ``` Failed call with handled revert: ``` -npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --network localhost --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --revert-message 0x --call-on-revert --types '["uint256"]' 42 +npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --network localhost --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --revert-message 0x --call-on-revert --types '["uint256"]' 42 ``` ## ZetaChain @@ -29,17 +29,17 @@ npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --re Successful call: ``` -npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello +npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello ``` Failed call: ``` -npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42 +npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42 ``` Failed call with handled revert: ``` -npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --revert-address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --revert-message 0x --call-on-revert --types '["uint256"]' 42 +npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --revert-address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --revert-message 0x --call-on-revert --types '["uint256"]' 42 ``` diff --git a/examples/hello/contracts/Echo.sol b/examples/hello/contracts/Echo.sol index a5271205..da684de9 100644 --- a/examples/hello/contracts/Echo.sol +++ b/examples/hello/contracts/Echo.sol @@ -30,6 +30,20 @@ contract Echo { gateway.call(receiver, message, revertOptions); } + function pingPong(string memory message) external payable { + gateway.call( + 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E, + abi.encode("hello"), + RevertOptions({ + revertAddress: address(0), + callOnRevert: false, + abortAddress: address(0), + revertMessage: "", + onRevertGasLimit: 0 + }) + ); + } + receive() external payable {} fallback() external payable {} From 2331f3751ee85b50a9334c610814cdc22f28d095 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 7 Oct 2024 14:56:51 +0300 Subject: [PATCH 10/15] update readme --- examples/hello/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/hello/README.md b/examples/hello/README.md index 91e91fc6..52ea5607 100644 --- a/examples/hello/README.md +++ b/examples/hello/README.md @@ -9,19 +9,19 @@ yarn deploy Successful call: ``` -npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --network localhost --types '["string"]' hello +npx hardhat echo-call --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --network localhost --types '["string"]' hello ``` Failed call: ``` -npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --network localhost --types '["uint256"]' 42 +npx hardhat echo-call --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --network localhost --types '["uint256"]' 42 ``` Failed call with handled revert: ``` -npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --network localhost --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --revert-message 0x --call-on-revert --types '["uint256"]' 42 +npx hardhat echo-call --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --network localhost --revert-address 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --revert-message 0x --call-on-revert --types '["uint256"]' 42 ``` ## ZetaChain @@ -29,17 +29,17 @@ npx hardhat echo-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --re Successful call: ``` -npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello +npx hardhat hello-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello ``` Failed call: ``` -npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42 +npx hardhat hello-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42 ``` Failed call with handled revert: ``` -npx hardhat hell-call --contract 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --revert-address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 --revert-message 0x --call-on-revert --types '["uint256"]' 42 +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 ``` From ded9f4235fb6fa7ce54b7d7a464354cc828b8458 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 7 Oct 2024 14:57:45 +0300 Subject: [PATCH 11/15] remove pingpong --- examples/hello/contracts/Echo.sol | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/examples/hello/contracts/Echo.sol b/examples/hello/contracts/Echo.sol index da684de9..a5271205 100644 --- a/examples/hello/contracts/Echo.sol +++ b/examples/hello/contracts/Echo.sol @@ -30,20 +30,6 @@ contract Echo { gateway.call(receiver, message, revertOptions); } - function pingPong(string memory message) external payable { - gateway.call( - 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E, - abi.encode("hello"), - RevertOptions({ - revertAddress: address(0), - callOnRevert: false, - abortAddress: address(0), - revertMessage: "", - onRevertGasLimit: 0 - }) - ); - } - receive() external payable {} fallback() external payable {} From b6a8ca344955515874211097dee2cee63ff4aa03 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 7 Oct 2024 20:28:19 +0300 Subject: [PATCH 12/15] switch to approve --- examples/hello/contracts/Hello.sol | 10 ++++++---- examples/hello/tasks/helloCall.ts | 6 +----- examples/hello/tasks/helloWithdrawAndCall.ts | 8 ++++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/examples/hello/contracts/Hello.sol b/examples/hello/contracts/Hello.sol index 5546f8f0..afebf156 100644 --- a/examples/hello/contracts/Hello.sol +++ b/examples/hello/contracts/Hello.sol @@ -38,6 +38,7 @@ contract Hello is UniversalContract { RevertOptions memory revertOptions ) external { (, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit); + IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee); IZRC20(zrc20).approve(address(gateway), gasFee); gateway.call(receiver, zrc20, message, gasLimit, revertOptions); } @@ -52,10 +53,11 @@ contract Hello is UniversalContract { ) external { (address gasZRC20, uint256 gasFee) = IZRC20(zrc20) .withdrawGasFeeWithGasLimit(gasLimit); - if (zrc20 == gasZRC20) { - IZRC20(zrc20).approve(address(gateway), amount + gasFee); - } else { - IZRC20(zrc20).approve(address(gateway), amount); + uint256 total = zrc20 == gasZRC20 ? amount + gasFee : amount; + IZRC20(zrc20).transferFrom(msg.sender, address(this), total); + IZRC20(zrc20).approve(address(gateway), total); + if (zrc20 != gasZRC20) { + IZRC20(gasZRC20).transferFrom(msg.sender, address(this), gasFee); IZRC20(gasZRC20).approve(address(gateway), gasFee); } gateway.withdrawAndCall( diff --git a/examples/hello/tasks/helloCall.ts b/examples/hello/tasks/helloCall.ts index 92ca946a..ef977e98 100644 --- a/examples/hello/tasks/helloCall.ts +++ b/examples/hello/tasks/helloCall.ts @@ -58,11 +58,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit); const zrc20 = new ethers.Contract(args.zrc20, ZRC20ABI.abi, signer); const [, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(gasLimit); - const zrc20TransferTx = await zrc20.transfer( - args.contract, - gasFee, - txOptions - ); + const zrc20TransferTx = await zrc20.approve(args.contract, gasFee, txOptions); await zrc20TransferTx.wait(); diff --git a/examples/hello/tasks/helloWithdrawAndCall.ts b/examples/hello/tasks/helloWithdrawAndCall.ts index b2799483..43818bd5 100644 --- a/examples/hello/tasks/helloWithdrawAndCall.ts +++ b/examples/hello/tasks/helloWithdrawAndCall.ts @@ -62,20 +62,20 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const zrc20 = new ethers.Contract(args.zrc20, ZRC20ABI.abi, signer); const [gasZRC20, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(gasLimit); const gasZRC20Contract = new ethers.Contract(gasZRC20, ZRC20ABI.abi, signer); - const gasFeeTransfer = await gasZRC20Contract.transfer( + const gasFeeApprove = await gasZRC20Contract.approve( args.contract, gasZRC20 == args.zrc20 ? gasFee.add(amount) : gasFee, txOptions ); - await gasFeeTransfer.wait(); + await gasFeeApprove.wait(); if (gasZRC20 !== args.zrc20) { - const targetTokenTransfer = await zrc20.transfer( + const targetTokenApprove = await zrc20.approve( args.contract, gasFee.add(amount), txOptions ); - await targetTokenTransfer.wait(); + await targetTokenApprove.wait(); } const factory = (await hre.ethers.getContractFactory(args.name)) as any; From ce2bab4a6733c9878d45dbd6793339897fce90ab Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 7 Oct 2024 20:45:34 +0300 Subject: [PATCH 13/15] rename --- examples/hello/contracts/Hello.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/hello/contracts/Hello.sol b/examples/hello/contracts/Hello.sol index afebf156..249c800d 100644 --- a/examples/hello/contracts/Hello.sol +++ b/examples/hello/contracts/Hello.sol @@ -53,9 +53,9 @@ contract Hello is UniversalContract { ) external { (address gasZRC20, uint256 gasFee) = IZRC20(zrc20) .withdrawGasFeeWithGasLimit(gasLimit); - uint256 total = zrc20 == gasZRC20 ? amount + gasFee : amount; - IZRC20(zrc20).transferFrom(msg.sender, address(this), total); - IZRC20(zrc20).approve(address(gateway), total); + uint256 targetAmount = zrc20 == gasZRC20 ? amount + gasFee : amount; + IZRC20(zrc20).transferFrom(msg.sender, address(this), targetAmount); + IZRC20(zrc20).approve(address(gateway), targetAmount); if (zrc20 != gasZRC20) { IZRC20(gasZRC20).transferFrom(msg.sender, address(this), gasFee); IZRC20(gasZRC20).approve(address(gateway), gasFee); From 87c868bf4175ead842605b71b2a5af7876d05388 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 8 Oct 2024 11:29:01 +0300 Subject: [PATCH 14/15] fix --- examples/hello/contracts/Hello.sol | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/examples/hello/contracts/Hello.sol b/examples/hello/contracts/Hello.sol index 249c800d..2f6fa158 100644 --- a/examples/hello/contracts/Hello.sol +++ b/examples/hello/contracts/Hello.sol @@ -11,6 +11,7 @@ contract Hello is UniversalContract { event HelloEvent(string, string); event RevertEvent(string, RevertContext); + error TransferFailed(); constructor(address payable gatewayAddress) { gateway = GatewayZEVM(gatewayAddress); @@ -38,7 +39,8 @@ contract Hello is UniversalContract { RevertOptions memory revertOptions ) external { (, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit); - 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); } @@ -53,11 +55,18 @@ contract Hello is UniversalContract { ) external { (address gasZRC20, uint256 gasFee) = IZRC20(zrc20) .withdrawGasFeeWithGasLimit(gasLimit); - uint256 targetAmount = zrc20 == gasZRC20 ? amount + gasFee : amount; - IZRC20(zrc20).transferFrom(msg.sender, address(this), targetAmount); - IZRC20(zrc20).approve(address(gateway), targetAmount); + uint256 target = zrc20 == gasZRC20 ? amount + gasFee : amount; + if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), target)) + revert TransferFailed(); + IZRC20(zrc20).approve(address(gateway), target); if (zrc20 != gasZRC20) { - IZRC20(gasZRC20).transferFrom(msg.sender, address(this), gasFee); + if ( + !IZRC20(gasZRC20).transferFrom( + msg.sender, + address(this), + gasFee + ) + ) revert TransferFailed(); IZRC20(gasZRC20).approve(address(gateway), gasFee); } gateway.withdrawAndCall( From 16391e66bfcb0d479da333e29ff598f45850a908 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 8 Oct 2024 17:25:54 +0300 Subject: [PATCH 15/15] update localnet --- examples/hello/package.json | 2 +- examples/hello/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/hello/package.json b/examples/hello/package.json index ccdadd72..658706bf 100644 --- a/examples/hello/package.json +++ b/examples/hello/package.json @@ -28,7 +28,7 @@ "@types/node": ">=12.0.0", "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", - "@zetachain/localnet": "^3.2.0", + "@zetachain/localnet": "^3.3.0", "@zetachain/toolkit": "13.0.0-rc4", "axios": "^1.3.6", "chai": "^4.2.0", diff --git a/examples/hello/yarn.lock b/examples/hello/yarn.lock index 7714ffa2..94afc56b 100644 --- a/examples/hello/yarn.lock +++ b/examples/hello/yarn.lock @@ -2402,10 +2402,10 @@ typescript "5.5.4" zod "3.22.4" -"@zetachain/localnet@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-3.2.0.tgz#66c09120397dbaf4f0c461ba6671f249c3379f6b" - integrity sha512-oqyxrxuSraj1A6/CAkeEBa9VfIvp+QxBIivTu/L9jK1zUa5MQw+rLqTL/rD1LR/k9om6x/zJHzhzZKU9Vpk3Bw== +"@zetachain/localnet@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@zetachain/localnet/-/localnet-3.3.0.tgz#eb026e1e56ef4ea78fd5efb15df2f931daeba884" + integrity sha512-8PbS6GQrROYicyEHk3QGhspwKnm3Nn8tmgISbtVw2ca4I+9lIAnuo4WstBPXhV3/kR9zPxgxErWnBWNSE78BuA== dependencies: "@inquirer/prompts" "^5.5.0" "@uniswap/v2-core" "^1.0.1"