Skip to content

Commit

Permalink
refactor: export localnet and tasks in separate packages (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev authored Aug 12, 2024
1 parent 094f049 commit 252a27e
Show file tree
Hide file tree
Showing 8 changed files with 2,142 additions and 475 deletions.
9 changes: 9 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import "./packages/tasks/src/localnet";

import { HardhatUserConfig } from "hardhat/config";

const config: HardhatUserConfig = {
solidity: "0.8.7",
};

export default config;
16 changes: 12 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,39 @@
"version": "0.0.0-set-on-publish",
"description": "",
"scripts": {
"build": "tsc",
"build": "del-cli dist && tsc",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"files": [
"dist"
],
"exports": {
".": {
"import": "./dist/index.js"
"./tasks": "./dist/tasks/src/index.js",
"./localnet": {
"import": "./dist/localnet/src/index.js",
"require": "./dist/localnet/src/index.js",
"types": "./dist/localnet/src/index.d.ts"
}
},
"keywords": [],
"author": "ZetaChain",
"license": "MIT",
"packageManager": "[email protected]+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72",
"devDependencies": {
"@types/wait-on": "^5.3.4",
"@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.0.1",
"del-cli": "^5.1.0",
"eslint": "^9.8.0",
"ts-node": "^10.9.2",
"typescript": "^5.5.4"
},
"dependencies": {
"@zetachain/protocol-contracts": "10.0.0-rc5",
"ethers": "^6.13.2"
"concurrently": "^8.2.2",
"ethers": "^6.13.2",
"hardhat": "^2.22.8",
"wait-on": "^7.2.0"
}
}
211 changes: 211 additions & 0 deletions packages/localnet/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import { ethers, NonceManager, Signer } from "ethers";
import * as GatewayEVM from "@zetachain/protocol-contracts/abi/GatewayEVM.sol/GatewayEVM.json";
import * as Custody from "@zetachain/protocol-contracts/abi/ERC20Custody.sol/ERC20Custody.json";
import * as ERC1967Proxy from "@zetachain/protocol-contracts/abi/ERC1967Proxy.sol/ERC1967Proxy.json";
import * as TestERC20 from "@zetachain/protocol-contracts/abi/TestERC20.sol/TestERC20.json";
import * as SystemContract from "@zetachain/protocol-contracts/abi/SystemContractMock.sol/SystemContractMock.json";
import * as GatewayZEVM from "@zetachain/protocol-contracts/abi/GatewayZEVM.sol/GatewayZEVM.json";
import * as ZetaConnectorNonNative from "@zetachain/protocol-contracts/abi/ZetaConnectorNonNative.sol/ZetaConnectorNonNative.json";
import * as WETH9 from "@zetachain/protocol-contracts/abi/WZETA.sol/WETH9.json";

const FUNGIBLE_MODULE_ADDRESS = "0x735b14BB79463307AAcBED86DAf3322B1e6226aB";

let protocolContracts: any;
let testContracts: any;
let deployer: Signer;
const deployOpts = {
gasPrice: 10000000000,
gasLimit: 6721975,
};

const deployProtocolContracts = async (
deployer: Signer,
fungibleModuleSigner: Signer
) => {
// Prepare EVM
// Deploy protocol contracts (gateway and custody)
const testERC20Factory = new ethers.ContractFactory(
TestERC20.abi,
TestERC20.bytecode,
deployer
);
const testEVMZeta = await testERC20Factory.deploy("zeta", "ZETA", deployOpts);

const gatewayEVMFactory = new ethers.ContractFactory(
GatewayEVM.abi,
GatewayEVM.bytecode,
deployer
);
const gatewayEVMImpl = await gatewayEVMFactory.deploy(deployOpts);

const gatewayEVMInterface = new ethers.Interface(GatewayEVM.abi);
const gatewayEVMInitFragment = gatewayEVMInterface.getFunction("initialize");
const gatewayEVMInitdata = gatewayEVMInterface.encodeFunctionData(
gatewayEVMInitFragment as ethers.FunctionFragment,
[
await deployer.getAddress(),
testEVMZeta.target,
await deployer.getAddress(),
]
);

const proxyEVMFactory = new ethers.ContractFactory(
ERC1967Proxy.abi,
ERC1967Proxy.bytecode,
deployer
);
const proxyEVM = (await proxyEVMFactory.deploy(
gatewayEVMImpl.target,
gatewayEVMInitdata,
deployOpts
)) as any;

const gatewayEVM = new ethers.Contract(
proxyEVM.target,
GatewayEVM.abi,
deployer
);

const zetaConnectorFactory = new ethers.ContractFactory(
ZetaConnectorNonNative.abi,
ZetaConnectorNonNative.bytecode,
deployer
);
const zetaConnector = await zetaConnectorFactory.deploy(
gatewayEVM.target,
testEVMZeta.target,
await deployer.getAddress(),
await deployer.getAddress(),
deployOpts
);

const custodyFactory = new ethers.ContractFactory(
Custody.abi,
Custody.bytecode,
deployer
);
const custody = await custodyFactory.deploy(
gatewayEVM.target,
await deployer.getAddress(),
await deployer.getAddress(),
deployOpts
);

await (gatewayEVM as any)
.connect(deployer)
.setCustody(custody.target, deployOpts);
await (gatewayEVM as any)
.connect(deployer)
.setConnector(zetaConnector.target, deployOpts);

// Prepare ZEVM
// Deploy protocol contracts (gateway and system)
const weth9Factory = new ethers.ContractFactory(
WETH9.abi,
WETH9.bytecode,
deployer
);
const wzeta = await weth9Factory.deploy(deployOpts);

const systemContractFactory = new ethers.ContractFactory(
SystemContract.abi,
SystemContract.bytecode,
deployer
);
const systemContract = await systemContractFactory.deploy(
ethers.ZeroAddress,
ethers.ZeroAddress,
ethers.ZeroAddress,
deployOpts
);

const gatewayZEVMFactory = new ethers.ContractFactory(
GatewayZEVM.abi,
GatewayZEVM.bytecode,
deployer
);
const gatewayZEVMImpl = await gatewayZEVMFactory.deploy(deployOpts);

const gatewayZEVMInterface = new ethers.Interface(GatewayZEVM.abi);
const gatewayZEVMInitFragment =
gatewayZEVMInterface.getFunction("initialize");
const gatewayZEVMInitData = gatewayEVMInterface.encodeFunctionData(
gatewayZEVMInitFragment as ethers.FunctionFragment,
[wzeta.target, await deployer.getAddress()]
);

const proxyZEVMFactory = new ethers.ContractFactory(
ERC1967Proxy.abi,
ERC1967Proxy.bytecode,
deployer
);
const proxyZEVM = (await proxyZEVMFactory.deploy(
gatewayZEVMImpl.target,
gatewayZEVMInitData,
deployOpts
)) as any;

const gatewayZEVM = new ethers.Contract(
proxyZEVM.target,
GatewayZEVM.abi,
deployer
);

await (wzeta as any)
.connect(fungibleModuleSigner)
.deposit({ ...deployOpts, value: ethers.parseEther("10") });
await (wzeta as any)
.connect(fungibleModuleSigner)
.approve(gatewayZEVM.target, ethers.parseEther("10"), deployOpts);
await (wzeta as any)
.connect(deployer)
.deposit({ ...deployOpts, value: ethers.parseEther("10") });
await (wzeta as any)
.connect(deployer)
.approve(gatewayZEVM.target, ethers.parseEther("10"), deployOpts);

return {
custody,
zetaConnector,
gatewayEVM,
gatewayZEVM,
systemContract,
testEVMZeta,
wzeta,
};
};

export const initLocalnet = async (port: number) => {
const provider = new ethers.JsonRpcProvider(`http://127.0.0.1:${port}`);
provider.pollingInterval = 100;
// anvil test mnemonic
const mnemonic =
"test test test test test test test test test test test junk";

// impersonate and fund fungible module account
await provider.send("anvil_impersonateAccount", [FUNGIBLE_MODULE_ADDRESS]);
await provider.send("anvil_setBalance", [
FUNGIBLE_MODULE_ADDRESS,
ethers.parseEther("100000").toString(),
]);
const fungibleModuleSigner = await provider.getSigner(
FUNGIBLE_MODULE_ADDRESS
);

deployer = new NonceManager(ethers.Wallet.fromPhrase(mnemonic, provider));
deployer.connect(provider);

protocolContracts = await deployProtocolContracts(
deployer,
fungibleModuleSigner
);

await provider.send("evm_mine", []);

process.stdin.resume();

return {
gatewayEVM: protocolContracts.gatewayEVM.target,
gatewayZetaChain: protocolContracts.gatewayZEVM.target,
};
};
1 change: 1 addition & 0 deletions packages/tasks/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { localnetTask } from "./localnet";
44 changes: 44 additions & 0 deletions packages/tasks/src/localnet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { task, types } from "hardhat/config";
import { initLocalnet } from "../../localnet/src";
import { exec } from "child_process";
import waitOn from "wait-on";

const main = async (args: any) => {
const port = args.port || 8545;
const anvilArgs = args.anvil ? `${args.anvil}` : "";

console.log(`Starting anvil on port ${port} with args: ${anvilArgs}`);

const anvilProcess = exec(
`anvil --auto-impersonate --port ${port} ${anvilArgs}`
);

if (anvilProcess.stdout && anvilProcess.stderr) {
anvilProcess.stdout.pipe(process.stdout);
anvilProcess.stderr.pipe(process.stderr);
}

await waitOn({ resources: [`tcp:127.0.0.1:${port}`] });

const { gatewayEVM, gatewayZetaChain } = await initLocalnet(port);

console.log("Gateway EVM:", gatewayEVM);
console.log("Gateway ZetaChain:", gatewayZetaChain);

process.on("SIGINT", () => {
console.log("\nReceived Ctrl-C, shutting down anvil...");
anvilProcess.kill();
process.exit();
});

await new Promise(() => {});
};

export const localnetTask = task("localnet", "Start localnet", main)
.addOptionalParam("port", "Port to run anvil on", 8545, types.int)
.addOptionalParam(
"anvil",
"Additional arguments to pass to anvil",
"",
types.string
);
Loading

0 comments on commit 252a27e

Please sign in to comment.