-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: lumtis <[email protected]>
- Loading branch information
Showing
27 changed files
with
1,751 additions
and
335 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
362 changes: 181 additions & 181 deletions
362
...s/prototypes/evm/receiver.sol/receiver.go → ...otypes/evm/receiverevm.sol/receiverevm.go
Large diffs are not rendered by default.
Oops, something went wrong.
28 changes: 10 additions & 18 deletions
28
pkg/contracts/prototypes/zevm/gatewayzevm.sol/gatewayzevm.go
Large diffs are not rendered by default.
Oops, something went wrong.
190 changes: 95 additions & 95 deletions
190
...acts/prototypes/zevm/sender.sol/sender.go → ...totypes/zevm/senderzevm.sol/senderzevm.go
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
## Worker script | ||
|
||
To start localnet execute: | ||
|
||
``` | ||
yarn localnet | ||
``` | ||
|
||
This will run hardhat local node and worker script, which will deploy all contracts, and listen and react to events, facilitating communication between contracts. | ||
Tasks to interact with localnet are located in `tasks/localnet`. To make use of default contract addresses on localnet, start localnet from scratch, so contracts are deployed on same addresses. Otherwise, provide custom addresses as tasks parameters. | ||
|
||
To only show logs from worker and hide hardhat node logs: | ||
``` | ||
yarn localnet --hide="NODE" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
import { AddressZero } from "@ethersproject/constants"; | ||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; | ||
import { SystemContract, ZRC20 } from "@typechain-types"; | ||
import { parseEther } from "ethers/lib/utils"; | ||
import { ethers, upgrades } from "hardhat"; | ||
|
||
const hre = require("hardhat"); | ||
|
||
export const FUNGIBLE_MODULE_ADDRESS = "0x735b14BB79463307AAcBED86DAf3322B1e6226aB"; | ||
|
||
const deploySystemContracts = async (tss: SignerWithAddress) => { | ||
// Prepare EVM | ||
// Deploy system contracts (gateway and custody) | ||
const GatewayEVM = await ethers.getContractFactory("GatewayEVM"); | ||
const Custody = await ethers.getContractFactory("ERC20CustodyNew"); | ||
|
||
const gatewayEVM = await upgrades.deployProxy(GatewayEVM, [tss.address], { | ||
initializer: "initialize", | ||
kind: "uups", | ||
}); | ||
console.log("GatewayEVM:", gatewayEVM.address); | ||
|
||
const custody = await Custody.deploy(gatewayEVM.address); | ||
await gatewayEVM.setCustody(custody.address); | ||
|
||
// Prepare ZEVM | ||
// Deploy system contracts (gateway and system) | ||
const SystemContractFactory = await ethers.getContractFactory("SystemContractMock"); | ||
const systemContract = (await SystemContractFactory.deploy(AddressZero, AddressZero, AddressZero)) as SystemContract; | ||
|
||
const GatewayZEVM = await ethers.getContractFactory("GatewayZEVM"); | ||
const gatewayZEVM = await upgrades.deployProxy(GatewayZEVM, [], { | ||
initializer: "initialize", | ||
kind: "uups", | ||
}); | ||
console.log("GatewayZEVM:", gatewayZEVM.address); | ||
|
||
return { | ||
custody, | ||
gatewayEVM, | ||
gatewayZEVM, | ||
systemContract, | ||
}; | ||
}; | ||
|
||
const deployTestContracts = async ( | ||
systemContracts, | ||
ownerEVM: SignerWithAddress, | ||
ownerZEVM: SignerWithAddress, | ||
fungibleModuleSigner: SignerWithAddress | ||
) => { | ||
// Prepare EVM | ||
// Deploy test contracts (erc20, receiver) and mint funds to test accounts | ||
const TestERC20 = await ethers.getContractFactory("TestERC20"); | ||
const ReceiverEVM = await ethers.getContractFactory("ReceiverEVM"); | ||
|
||
const token = await TestERC20.deploy("Test Token", "TTK"); | ||
const receiverEVM = await ReceiverEVM.deploy(); | ||
await token.mint(ownerEVM.address, ethers.utils.parseEther("1000")); | ||
|
||
// Transfer some tokens to the custody contract | ||
await token.transfer(systemContracts.custody.address, ethers.utils.parseEther("500")); | ||
|
||
// Prepare ZEVM | ||
// Deploy test contracts (test zContract, zrc20, sender) and mint funds to test accounts | ||
const TestZContract = await ethers.getContractFactory("TestZContract"); | ||
const testZContract = await TestZContract.deploy(); | ||
|
||
const ZRC20Factory = await ethers.getContractFactory("ZRC20New"); | ||
const ZRC20Contract = (await ZRC20Factory.connect(fungibleModuleSigner).deploy( | ||
"TOKEN", | ||
"TKN", | ||
18, | ||
1, | ||
1, | ||
0, | ||
systemContracts.systemContract.address, | ||
systemContracts.gatewayZEVM.address | ||
)) as ZRC20; | ||
|
||
await systemContracts.systemContract.setGasCoinZRC20(1, ZRC20Contract.address); | ||
await systemContracts.systemContract.setGasPrice(1, ZRC20Contract.address); | ||
await ZRC20Contract.connect(fungibleModuleSigner).deposit(ownerZEVM.address, parseEther("100")); | ||
await ZRC20Contract.connect(ownerZEVM).approve(systemContracts.gatewayZEVM.address, parseEther("100")); | ||
|
||
// Include abi of gatewayZEVM events, so hardhat can decode them automatically | ||
const senderArtifact = await hre.artifacts.readArtifact("SenderZEVM"); | ||
const gatewayZEVMArtifact = await hre.artifacts.readArtifact("GatewayZEVM"); | ||
const senderABI = [ | ||
...senderArtifact.abi, | ||
...gatewayZEVMArtifact.abi.filter((f: ethers.utils.Fragment) => f.type === "event"), | ||
]; | ||
|
||
const SenderZEVM = new ethers.ContractFactory(senderABI, senderArtifact.bytecode, ownerZEVM); | ||
const senderZEVM = await SenderZEVM.deploy(systemContracts.gatewayZEVM.address); | ||
await ZRC20Contract.connect(fungibleModuleSigner).deposit(senderZEVM.address, parseEther("100")); | ||
|
||
return { | ||
ZRC20Contract, | ||
receiverEVM, | ||
senderZEVM, | ||
testZContract, | ||
}; | ||
}; | ||
|
||
export const startWorker = async () => { | ||
const [ownerEVM, ownerZEVM, tss] = await ethers.getSigners(); | ||
|
||
// Impersonate the fungible module account | ||
await hre.network.provider.request({ | ||
method: "hardhat_impersonateAccount", | ||
params: [FUNGIBLE_MODULE_ADDRESS], | ||
}); | ||
|
||
// Get a signer for the fungible module account | ||
const fungibleModuleSigner = await ethers.getSigner(FUNGIBLE_MODULE_ADDRESS); | ||
hre.network.provider.send("hardhat_setBalance", [FUNGIBLE_MODULE_ADDRESS, parseEther("1000000").toHexString()]); | ||
|
||
// Deploy system and test contracts | ||
const systemContracts = await deploySystemContracts(tss); | ||
const testContracts = await deployTestContracts(systemContracts, ownerEVM, ownerZEVM, fungibleModuleSigner); | ||
|
||
// Listen to contracts events | ||
// event Call(address indexed sender, bytes receiver, bytes message); | ||
systemContracts.gatewayZEVM.on("Call", async (...args: Array<any>) => { | ||
console.log("Worker: Call event on GatewayZEVM."); | ||
console.log("Worker: Calling ReceiverEVM through GatewayEVM..."); | ||
const receiver = args[1]; | ||
const message = args[2]; | ||
const executeTx = await systemContracts.gatewayEVM.execute(receiver, message, { value: 0 }); | ||
await executeTx.wait(); | ||
}); | ||
|
||
// event Withdrawal(address indexed from, bytes to, uint256 value, uint256 gasfee, uint256 protocolFlatFee, bytes message); | ||
systemContracts.gatewayZEVM.on("Withdrawal", async (...args: Array<any>) => { | ||
console.log("Worker: Withdrawal event on GatewayZEVM."); | ||
const receiver = args[1]; | ||
const message = args[5]; | ||
if (message != "0x") { | ||
console.log("Worker: Calling ReceiverEVM through GatewayEVM..."); | ||
const executeTx = await systemContracts.gatewayEVM.execute(receiver, message, { value: 0 }); | ||
await executeTx.wait(); | ||
} | ||
}); | ||
|
||
testContracts.receiverEVM.on("ReceivedPayable", () => { | ||
console.log("ReceiverEVM: receivePayable called!"); | ||
}); | ||
|
||
// event Call(address indexed sender, address indexed receiver, bytes payload); | ||
systemContracts.gatewayEVM.on("Call", async (...args: Array<any>) => { | ||
console.log("Worker: Call event on GatewayEVM."); | ||
console.log("Worker: Calling TestZContract through GatewayZEVM..."); | ||
const zContract = args[1]; | ||
const payload = args[2]; | ||
const executeTx = await systemContracts.gatewayZEVM.connect(fungibleModuleSigner).execute( | ||
[systemContracts.gatewayZEVM.address, fungibleModuleSigner.address, 1], | ||
// onCrosschainCall contains zrc20 and amount which is not available in Call event | ||
testContracts.ZRC20Contract.address, | ||
parseEther("0"), | ||
zContract, | ||
payload | ||
); | ||
await executeTx.wait(); | ||
}); | ||
|
||
// event Deposit(address indexed sender, address indexed receiver, uint256 amount, address asset, bytes payload); | ||
systemContracts.gatewayEVM.on("Deposit", async (...args: Array<any>) => { | ||
console.log("Worker: Deposit event on GatewayEVM."); | ||
const receiver = args[1]; | ||
const asset = args[3]; | ||
const payload = args[4]; | ||
if (payload != "0x") { | ||
console.log("Worker: Calling TestZContract through GatewayZEVM..."); | ||
const executeTx = await systemContracts.gatewayZEVM | ||
.connect(fungibleModuleSigner) | ||
.execute( | ||
[systemContracts.gatewayZEVM.address, fungibleModuleSigner.address, 1], | ||
asset, | ||
parseEther("0"), | ||
receiver, | ||
payload | ||
); | ||
await executeTx.wait(); | ||
} | ||
}); | ||
|
||
testContracts.testZContract.on("ContextData", async () => { | ||
console.log("TestZContract: onCrosschainCall called!"); | ||
}); | ||
|
||
process.stdin.resume(); | ||
}; | ||
|
||
startWorker() | ||
.then(() => { | ||
console.log("Setup complete, monitoring events. Press CTRL+C to exit."); | ||
}) | ||
.catch((error) => { | ||
console.error("Failed to deploy contracts or set up listeners:", error); | ||
process.exit(1); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { task } from "hardhat/config"; | ||
|
||
declare const hre: any; | ||
|
||
// Contains tasks to make it easier to interact with prototype contracts localnet. | ||
// To make use of default contract addresses on localnet, start localnet from scratch, so contracts are deployed on same addresses. | ||
// Otherwise, provide custom addresses as parameters. | ||
|
||
task("zevm-call", "calls evm contract from zevm account") | ||
.addOptionalParam("gatewayZEVM", "contract address of gateway on ZEVM", "0x413b1AfCa96a3df5A686d8BFBF93d30688a7f7D9") | ||
.addOptionalParam("receiverEVM", "contract address of receiver on EVM", "0x821f3361D454cc98b7555221A06Be563a7E2E0A6") | ||
.setAction(async (taskArgs) => { | ||
const gatewayZEVM = await hre.ethers.getContractAt("GatewayZEVM", taskArgs.gatewayZEVM); | ||
const receiverEVM = await hre.ethers.getContractAt("ReceiverEVM", taskArgs.receiverEVM); | ||
|
||
const str = "Hello!"; | ||
const num = 42; | ||
const flag = true; | ||
|
||
// Encode the function call data and call on zevm | ||
const message = receiverEVM.interface.encodeFunctionData("receivePayable", [str, num, flag]); | ||
try { | ||
const callTx = await gatewayZEVM.call(receiverEVM.address, message); | ||
await callTx.wait(); | ||
console.log("ReceiverEVM called from ZEVM"); | ||
} catch (e) { | ||
console.error("Error calling ReceiverEVM:", e); | ||
} | ||
}); | ||
|
||
task("zevm-withdraw-and-call", "withdraws zrc20 and calls evm contract from zevm account") | ||
.addOptionalParam("gatewayZEVM", "contract address of gateway on ZEVM", "0x413b1AfCa96a3df5A686d8BFBF93d30688a7f7D9") | ||
.addOptionalParam("receiverEVM", "contract address of receiver on EVM", "0x821f3361D454cc98b7555221A06Be563a7E2E0A6") | ||
.addOptionalParam("zrc20", "contract address of zrc20", "0x9fd96203f7b22bCF72d9DCb40ff98302376cE09c") | ||
.addOptionalParam("amount", "amount to withdraw", "1") | ||
.setAction(async (taskArgs) => { | ||
const gatewayZEVM = await hre.ethers.getContractAt("GatewayZEVM", taskArgs.gatewayZEVM); | ||
const receiverEVM = await hre.ethers.getContractAt("ReceiverEVM", taskArgs.receiverEVM); | ||
const zrc20 = await hre.ethers.getContractAt("ZRC20New", taskArgs.zrc20); | ||
const [, ownerZEVM] = await hre.ethers.getSigners(); | ||
|
||
const str = "Hello!"; | ||
const num = 42; | ||
const flag = true; | ||
|
||
// Encode the function call data and call on zevm | ||
const message = receiverEVM.interface.encodeFunctionData("receivePayable", [str, num, flag]); | ||
|
||
try { | ||
const callTx = await gatewayZEVM | ||
.connect(ownerZEVM) | ||
.withdrawAndCall(receiverEVM.address, hre.ethers.utils.parseEther(taskArgs.amount), zrc20.address, message); | ||
await callTx.wait(); | ||
console.log("ReceiverEVM called from ZEVM"); | ||
} catch (e) { | ||
console.error("Error calling ReciverEVM:", e); | ||
} | ||
}); | ||
|
||
task("evm-call", "calls zevm zcontract from evm account") | ||
.addOptionalParam("gatewayEVM", "contract address of gateway on EVM", "0xB06c856C8eaBd1d8321b687E188204C1018BC4E5") | ||
.addOptionalParam("zContract", "contract address of zContract on ZEVM", "0x71089Ba41e478702e1904692385Be3972B2cBf9e") | ||
.setAction(async (taskArgs) => { | ||
const gatewayEVM = await hre.ethers.getContractAt("GatewayEVM", taskArgs.gatewayEVM); | ||
const zContract = await hre.ethers.getContractAt("TestZContract", taskArgs.zContract); | ||
|
||
const message = hre.ethers.utils.defaultAbiCoder.encode(["string"], ["hello"]); | ||
|
||
try { | ||
const callTx = await gatewayEVM.call(zContract.address, message); | ||
await callTx.wait(); | ||
console.log("TestZContract called from EVM"); | ||
} catch (e) { | ||
console.error("Error calling TestZContract:", e); | ||
} | ||
}); | ||
|
||
task("evm-deposit-and-call", "deposits erc20 and calls zevm zcontract from evm account") | ||
.addOptionalParam("gatewayEVM", "contract address of gateway on EVM", "0xB06c856C8eaBd1d8321b687E188204C1018BC4E5") | ||
.addOptionalParam("zContract", "contract address of zContract on ZEVM", "0x71089Ba41e478702e1904692385Be3972B2cBf9e") | ||
.addOptionalParam("erc20", "contract address of erc20", "0x02df3a3F960393F5B349E40A599FEda91a7cc1A7") | ||
.addOptionalParam("amount", "amount to deposit", "1") | ||
.setAction(async (taskArgs) => { | ||
const gatewayEVM = await hre.ethers.getContractAt("GatewayEVM", taskArgs.gatewayEVM); | ||
const zContract = await hre.ethers.getContractAt("TestZContract", taskArgs.zContract); | ||
const erc20 = await hre.ethers.getContractAt("TestERC20", taskArgs.erc20); | ||
|
||
await erc20.approve(gatewayEVM.address, hre.ethers.utils.parseEther(taskArgs.amount)); | ||
|
||
const payload = hre.ethers.utils.defaultAbiCoder.encode(["string"], ["hello"]); | ||
|
||
try { | ||
const callTx = await gatewayEVM["depositAndCall(address,uint256,address,bytes)"]( | ||
zContract.address, | ||
hre.ethers.utils.parseEther(taskArgs.amount), | ||
erc20.address, | ||
payload | ||
); | ||
await callTx.wait(); | ||
console.log("TestZContract called from EVM"); | ||
} catch (e) { | ||
console.error("Error calling TestZContract:", e); | ||
} | ||
}); |
Oops, something went wrong.