From 1b8e3c72731dbe84201215231aec3eca05c19ed1 Mon Sep 17 00:00:00 2001 From: skosito Date: Wed, 7 Aug 2024 22:25:26 +0100 Subject: [PATCH] feat: v2 evm contracts deploy scripts (#293) --- .gitignore | 2 +- v2/.env.sample | 8 +++++ .../deterministic/DeployERC20Custody.s.sol | 29 ++++++++++++++++++ .../deterministic/DeployGatewayEVM.s.sol | 28 ++++++++--------- .../deterministic/DeployTestERC20.s.sol | 26 ++++++++++++++++ .../DeployZetaConnectorNonNative.s.sol | 30 +++++++++++++++++++ .../deterministic/UpgradeGatewayEVM.s.sol | 8 +---- v2/scripts/deploy/deterministic/readme.md | 13 ++++++-- 8 files changed, 118 insertions(+), 26 deletions(-) create mode 100644 v2/.env.sample create mode 100644 v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol create mode 100644 v2/scripts/deploy/deterministic/DeployTestERC20.s.sol create mode 100644 v2/scripts/deploy/deterministic/DeployZetaConnectorNonNative.s.sol diff --git a/.gitignore b/.gitignore index ce504686..3c2a1d95 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,4 @@ crytic-export out cache_forge -broadcast \ No newline at end of file +v2/broadcast/*/31337 \ No newline at end of file diff --git a/v2/.env.sample b/v2/.env.sample new file mode 100644 index 00000000..a9f55f71 --- /dev/null +++ b/v2/.env.sample @@ -0,0 +1,8 @@ +# This is sample on how .env should look like. Values given here are illustration and are expected if run with anvil locally and first private key. +# evm +TSS_ADDRESS=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 +GATEWAY_ADMIN_ADDRESS_EVM=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +ERC20_CUSTODY_ADMIN_ADDRESS_EVM=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +ZETA_CONNECTOR_ADMIN_ADDRESS_EVM=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +GATEWAY_PROXY_EVM=0x9f21B726FCb84D8e92cdC678772590dce5347D0B +ZETA_ERC20_EVM=0x42928581Ba60cD97B65D873151dc063F3D0619f8 diff --git a/v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol b/v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol new file mode 100644 index 00000000..bb8e933b --- /dev/null +++ b/v2/scripts/deploy/deterministic/DeployERC20Custody.s.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "forge-std/Script.sol"; +import "src/evm/ERC20Custody.sol"; + +contract DeployERC20Custody is Script { + function run() external { + address payable tss = payable(vm.envAddress("TSS_ADDRESS")); + address admin = vm.envAddress("ERC20_CUSTODY_ADMIN_ADDRESS_EVM"); + address gateway = vm.envAddress("GATEWAY_PROXY_EVM"); + + bytes32 salt = keccak256("ERC20Custody"); + + vm.startBroadcast(); + + ERC20Custody custody = new ERC20Custody{salt: salt}(gateway, tss, admin); + require(address(custody) != address(0), "deployment failed"); + + address expectedAddr = vm.computeCreate2Address( + salt, + hashInitCode(type(ERC20Custody).creationCode, abi.encode(gateway, tss, admin)) + ); + + require(expectedAddr == address(custody), "erc20 custody address doesn't match expected address"); + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol b/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol index 224bff43..effa25c9 100644 --- a/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol +++ b/v2/scripts/deploy/deterministic/DeployGatewayEVM.s.sol @@ -6,34 +6,28 @@ import "src/evm/GatewayEVM.sol"; import "test/utils/TestERC20.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -contract DeployGatewayEVMCreate2 is Script { +contract DeployGatewayEVM is Script { function run() external { - // TODO (https://github.com/zeta-chain/protocol-contracts/issues/251): should be passed as arg - string memory mnemonic = "test test test test test test test test test test test junk"; - uint256 privateKey = vm.deriveKey(mnemonic, 0); - address deployer = vm.rememberKey(privateKey); - - // TODO (https://github.com/zeta-chain/protocol-contracts/issues/251): should be passed as arg - address payable tss = payable(vm.envOr("TSS_ADDRESS", address(0x123))); - address admin = vm.envOr("ADMIN_ADDRESS", deployer); + address payable tss = payable(vm.envAddress("TSS_ADDRESS")); + address admin = vm.envAddress("GATEWAY_ADMIN_ADDRESS_EVM"); + address zeta = vm.envAddress("ZETA_ERC20_EVM"); address expectedImplAddress; address expectedProxyAddress; - bytes32 implSalt = bytes32(uint256(10)); - bytes32 proxySalt = bytes32(uint256(11)); - - vm.startBroadcast(deployer); + bytes32 implSalt = keccak256("GatewayEVM"); + bytes32 proxySalt = keccak256("GatewayEVMProxy"); - // TODO (https://github.com/zeta-chain/protocol-contracts/issues/251): should be passed as arg - TestERC20 zeta = new TestERC20("zeta", "ZETA"); + vm.startBroadcast(); - expectedImplAddress = computeCreate2Address( + expectedImplAddress = vm.computeCreate2Address( implSalt, hashInitCode(type(GatewayEVM).creationCode) ); GatewayEVM gatewayImpl = new GatewayEVM{salt: implSalt}(); + require(address(gatewayImpl) != address(0), "gatewayImpl deployment failed"); + require(expectedImplAddress == address(gatewayImpl), "impl address doesn't match expected address"); expectedProxyAddress = vm.computeCreate2Address( @@ -51,6 +45,8 @@ contract DeployGatewayEVMCreate2 is Script { address(gatewayImpl), abi.encodeWithSelector(GatewayEVM.initialize.selector, tss, address(zeta), admin) ); + require(address(gatewayProxy) != address(0), "gatewayProxy deployment failed"); + require(expectedProxyAddress == address(gatewayProxy), "proxy address doesn't match expected address"); diff --git a/v2/scripts/deploy/deterministic/DeployTestERC20.s.sol b/v2/scripts/deploy/deterministic/DeployTestERC20.s.sol new file mode 100644 index 00000000..ef6db83c --- /dev/null +++ b/v2/scripts/deploy/deterministic/DeployTestERC20.s.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "forge-std/Script.sol"; +import "test/utils/TestERC20.sol"; + +// This is just to deploy test erc20 tokens for testing deployments +contract DeployTestERC20 is Script { + function run() external { + bytes32 erc20Salt = keccak256("TestERC20"); + + vm.startBroadcast(); + + TestERC20 zeta = new TestERC20{salt: erc20Salt}("zeta", "ZETA"); + require(address(zeta) != address(0), "deployment failed"); + + address expectedAddr = vm.computeCreate2Address( + erc20Salt, + hashInitCode(type(TestERC20).creationCode, abi.encode("zeta", "ZETA")) + ); + + require(expectedAddr == address(zeta), "zeta address doesn't match expected address"); + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/v2/scripts/deploy/deterministic/DeployZetaConnectorNonNative.s.sol b/v2/scripts/deploy/deterministic/DeployZetaConnectorNonNative.s.sol new file mode 100644 index 00000000..c1f1c6d2 --- /dev/null +++ b/v2/scripts/deploy/deterministic/DeployZetaConnectorNonNative.s.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "forge-std/Script.sol"; +import "src/evm/ZetaConnectorNonNative.sol"; + +contract DeployZetaConnectorNonNative is Script { + function run() external { + address payable tss = payable(vm.envAddress("TSS_ADDRESS")); + address admin = vm.envAddress("ZETA_CONNECTOR_ADMIN_ADDRESS_EVM"); + address gateway = vm.envAddress("GATEWAY_PROXY_EVM"); + address zeta = vm.envAddress("ZETA_ERC20_EVM"); + + bytes32 salt = keccak256("ZetaConnectorNonNative"); + + vm.startBroadcast(); + + ZetaConnectorNonNative connector = new ZetaConnectorNonNative{salt: salt}(gateway, zeta, tss, admin); + require(address(connector) != address(0), "deployment failed"); + + address expectedAddr = vm.computeCreate2Address( + salt, + hashInitCode(type(ZetaConnectorNonNative).creationCode, abi.encode(gateway, zeta, tss, admin)) + ); + + require(expectedAddr == address(connector), "zeta connector non native address doesn't match expected address"); + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/v2/scripts/deploy/deterministic/UpgradeGatewayEVM.s.sol b/v2/scripts/deploy/deterministic/UpgradeGatewayEVM.s.sol index dfe6f383..ed2b84c8 100644 --- a/v2/scripts/deploy/deterministic/UpgradeGatewayEVM.s.sol +++ b/v2/scripts/deploy/deterministic/UpgradeGatewayEVM.s.sol @@ -10,13 +10,7 @@ import { Upgrades } from "openzeppelin-foundry-upgrades/Upgrades.sol"; contract UpgradeGatewayEVM is Script { function run() external { - // TODO (https://github.com/zeta-chain/protocol-contracts/issues/251): should be passed as arg - string memory mnemonic = "test test test test test test test test test test test junk"; - uint256 privateKey = vm.deriveKey(mnemonic, 0); - address deployer = vm.rememberKey(privateKey); - - // TODO (https://github.com/zeta-chain/protocol-contracts/issues/251): should be passed as arg - address proxy = vm.envOr("PROXY_ADDRESS", address(0xA7806c719bd377F15bA6CaDf2F94Afb7FfA66256)); + address proxy = vm.envAddress("GATEWAY_EVM_PROXY"); GatewayEVM prevImpl = GatewayEVM(proxy); diff --git a/v2/scripts/deploy/deterministic/readme.md b/v2/scripts/deploy/deterministic/readme.md index 2b851270..6c156687 100644 --- a/v2/scripts/deploy/deterministic/readme.md +++ b/v2/scripts/deploy/deterministic/readme.md @@ -1,6 +1,9 @@ -## Deterministic GatewayEVM deployments +## Deterministic deployments -`DeployGatewayEVMCreate2` script uses create2 with Foundry (https://book.getfoundry.sh/tutorials/create2-tutorial) to perform deterministic deployment of `GatewayEVM` contracts. +Note: `.env` file should be set up and updated during deployments according to expected env variables in scripts, check `.env.sample` for example on how it should look like. +Currently, `.env.sample` is set with test env variables that can be used to test scripts locally with `anvil` using first account private key. + +`DeployGatewayEVM` script uses create2 with Foundry (https://book.getfoundry.sh/tutorials/create2-tutorial) to perform deterministic deployment of `GatewayEVM` contracts. This ensures that on every EVM chain `GatewayEVM` contract will be on same address. Since UUPS proxy is used for `GatewayEVM` contract, both implementation and `ERC1967Proxy` are deployed using above technique: @@ -9,9 +12,15 @@ Since UUPS proxy is used for `GatewayEVM` contract, both implementation and `ERC - adding a salt to deployment - basic assertions to verify that deployed address is same as expected +Remaining deployment script work in similar way as `GatewayEVM` but much simpler because there is no proxy. + `UpgradeGatewayEVM` script uses OpenZeppelin's Foundry Upgrades plugin (https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades), to upgrade `GatewayEVM`: - deploy new implementation (doesn't need to be deterministic since proxy address doesn't change) - use plugin to upgrade proxy +To execute deployment script, following format is needed: +``` +forge script scripts/deploy/deterministic/