From c0244389916aa62355358ab978e93b94c51a5760 Mon Sep 17 00:00:00 2001 From: Benjamin Patch Date: Mon, 30 Oct 2023 12:06:15 +1100 Subject: [PATCH 1/8] initial changes --- .gitmodules | 6 +++--- deploy.sh | 3 +++ lib/openzeppelin-contracts | 2 +- script/DeployChildContracts.s.sol | 16 +++++++++++++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index 5fb58bd03..28c4c3deb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/openzeppelin-contracts"] - path = lib/openzeppelin-contracts - url = https://github.com/OpenZeppelin/openzeppelin-contracts [submodule "lib/openzeppelin-contracts-upgradeable"] path = lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable @@ -13,3 +10,6 @@ [submodule "lib/axelar-gmp-sdk-solidity"] path = lib/axelar-gmp-sdk-solidity url = https://github.com/axelarnetwork/axelar-gmp-sdk-solidity +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/deploy.sh b/deploy.sh index 8a106b185..ad429dbc7 100755 --- a/deploy.sh +++ b/deploy.sh @@ -31,9 +31,12 @@ function main() { fi child_erc20_bridge=$( get_deployed_contract "$child_filename" "ChildERC20Bridge" ) + proxies=$( get_deployed_contract "$child_filename" "TransparentUpgradeableProxy" ) child_bridge_adaptor=$( get_deployed_contract "$child_filename" "ChildAxelarBridgeAdaptor" ) child_chain_child_token_template=$( get_deployed_contract "$child_filename" "ChildERC20" ) + echo "Proxies: $proxies" + export ROOT_ERC20_BRIDGE=$root_erc20_bridge export ROOT_BRIDGE_ADAPTOR=$root_bridge_adaptor export ROOTCHAIN_CHILD_TOKEN_TEMPLATE=$root_chain_child_token_template diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index fd81a96f0..94697be8a 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit fd81a96f01cc42ef1c9a5399364968d0e07e9e90 +Subproject commit 94697be8a3f0dfcd95dfb13ffbd39b5973f5c65d diff --git a/script/DeployChildContracts.s.sol b/script/DeployChildContracts.s.sol index 45a0cae03..58a190f1a 100644 --- a/script/DeployChildContracts.s.sol +++ b/script/DeployChildContracts.s.sol @@ -3,6 +3,9 @@ pragma solidity ^0.8.21; import {Script, console2} from "forge-std/Script.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + import {ChildERC20Bridge} from "../src/child/ChildERC20Bridge.sol"; import {ChildAxelarBridgeAdaptor} from "../src/child/ChildAxelarBridgeAdaptor.sol"; import {ChildERC20} from "../src/child/ChildERC20.sol"; @@ -14,17 +17,28 @@ contract DeployChildContracts is Script { function run() public { uint256 deployerPrivateKey = vm.envUint("CHILD_PRIVATE_KEY"); address childGateway = vm.envAddress("CHILD_GATEWAY_ADDRESS"); - //address childGasService = vm.envAddress("CHILD_GAS_SERVICE_ADDRESS"); // Not yet used. + address childGasService = vm.envAddress("CHILD_GAS_SERVICE_ADDRESS"); // Not yet used. + address initialChildChainAdmin = vm.envAddress("INITIAL_CHILDCHAIN_ADMIN"); string memory childRpcUrl = vm.envString("CHILD_RPC_URL"); vm.createSelectFork(childRpcUrl); vm.startBroadcast(deployerPrivateKey); + ProxyAdmin proxyAdmin = new ProxyAdmin(initialChildChainAdmin); + ChildERC20 childTokenTemplate = new ChildERC20(); childTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18); ChildERC20Bridge childBridge = new ChildERC20Bridge(); + childBridge.initialize(address(1), "0x1", address(1), "root", address(1)); + + TransparentUpgradeableProxy childBridgeProxy = new TransparentUpgradeableProxy( + address(childBridge), + address(proxyAdmin), + "" + ); + // TODO put behind proxy ChildAxelarBridgeAdaptor childBridgeAdaptor = new ChildAxelarBridgeAdaptor( childGateway, // child gateway address(childBridge) // child bridge From ea2418123536d5ab538b6093e41b4adfa9b5c134 Mon Sep 17 00:00:00 2001 From: Benjamin Patch Date: Tue, 31 Oct 2023 13:54:28 +1100 Subject: [PATCH 2/8] Child chain behind proxies --- axelar-local-dev/chain-config/local.json | 4 +-- .../chain-config/local.template.json | 4 +-- deploy.sh | 29 +++++++++++++++---- lib/openzeppelin-contracts | 2 +- script/DeployChildContracts.s.sol | 27 +++++++++++------ script/InitializeChildContracts.s.sol | 3 ++ 6 files changed, 49 insertions(+), 20 deletions(-) diff --git a/axelar-local-dev/chain-config/local.json b/axelar-local-dev/chain-config/local.json index 08c7ff64a..017e00b57 100644 --- a/axelar-local-dev/chain-config/local.json +++ b/axelar-local-dev/chain-config/local.json @@ -46,13 +46,13 @@ "rpc": "http://localhost:8500/1", "contract": { "abi": [], - "address": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" + "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" }, "contract2": { "abi": [ "function rootTokenToChildToken(address rootToken) external view returns (address)" ], - "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" }, "usdc": { "abi": [ diff --git a/axelar-local-dev/chain-config/local.template.json b/axelar-local-dev/chain-config/local.template.json index 08c7ff64a..017e00b57 100644 --- a/axelar-local-dev/chain-config/local.template.json +++ b/axelar-local-dev/chain-config/local.template.json @@ -46,13 +46,13 @@ "rpc": "http://localhost:8500/1", "contract": { "abi": [], - "address": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" + "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" }, "contract2": { "abi": [ "function rootTokenToChildToken(address rootToken) external view returns (address)" ], - "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" }, "usdc": { "abi": [ diff --git a/deploy.sh b/deploy.sh index ad429dbc7..5a6f399c1 100755 --- a/deploy.sh +++ b/deploy.sh @@ -17,6 +17,9 @@ function main() { forge script script/DeployRootContracts.s.sol:DeployRootContracts --broadcast forge script script/DeployChildContracts.s.sol:DeployChildContracts --broadcast + echo "sleepy boy" + sleep 5 + root_filename="broadcast/DeployRootContracts.s.sol/$ROOT_CHAIN_ID/run-latest.json" child_filename="broadcast/DeployChildContracts.s.sol/$CHILD_CHAIN_ID/run-latest.json" @@ -30,19 +33,33 @@ function main() { export ROOT_WETH_ADDRESS=$root_weth_contract fi - child_erc20_bridge=$( get_deployed_contract "$child_filename" "ChildERC20Bridge" ) + child_erc20_bridge_implementation=$( get_deployed_contract "$child_filename" "ChildERC20Bridge" ) proxies=$( get_deployed_contract "$child_filename" "TransparentUpgradeableProxy" ) - child_bridge_adaptor=$( get_deployed_contract "$child_filename" "ChildAxelarBridgeAdaptor" ) + child_bridge_adaptor_implementation=$( get_deployed_contract "$child_filename" "ChildAxelarBridgeAdaptor" ) child_chain_child_token_template=$( get_deployed_contract "$child_filename" "ChildERC20" ) echo "Proxies: $proxies" + implementation_storage_slot="0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" + + while IFS= read -r proxy_address; do + echo "... $proxy_address ..." + implementation_slot_value=$(cast storage --rpc-url "$CHILD_RPC_URL" "$proxy_address" "$implementation_storage_slot") + implementation_address=$(cast parse-bytes32-address "$implementation_slot_value") + echo "logic: $implementation_address" + if [ "$implementation_address" = "$child_erc20_bridge_implementation" ]; then + child_erc20_bridge_proxy=$proxy_address + elif [ "$implementation_address" = "$child_bridge_adaptor_implementation" ]; then + child_bridge_adaptor_proxy=$proxy_address + fi + done <<< "$proxies" + export ROOT_ERC20_BRIDGE=$root_erc20_bridge export ROOT_BRIDGE_ADAPTOR=$root_bridge_adaptor export ROOTCHAIN_CHILD_TOKEN_TEMPLATE=$root_chain_child_token_template - export CHILD_BRIDGE_ADAPTOR=$child_bridge_adaptor - export CHILD_ERC20_BRIDGE=$child_erc20_bridge + export CHILD_BRIDGE_ADAPTOR=$child_bridge_adaptor_proxy + export CHILD_ERC20_BRIDGE=$child_erc20_bridge_proxy export CHILDCHAIN_CHILD_TOKEN_TEMPLATE=$child_chain_child_token_template forge script script/InitializeRootContracts.s.sol:InitializeRootContracts --broadcast --ffi @@ -55,8 +72,8 @@ function main() { \"root_bridge_adaptor\": \"$root_bridge_adaptor\", \"root_chain_child_token_template\": \"$root_chain_child_token_template\", \"child_chain_id\": \"$CHILD_CHAIN_ID\", - \"child_bridge_address\": \"$child_erc20_bridge\", - \"child_bridge_adaptor\": \"$child_bridge_adaptor\", + \"child_bridge_address\": \"$child_erc20_bridge_proxy\", + \"child_bridge_adaptor\": \"$child_bridge_adaptor_proxy\", \"child_chain_child_token_template\": \"$child_chain_child_token_template\" }" | jq . > addresses.json diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 94697be8a..9329cfacd 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 94697be8a3f0dfcd95dfb13ffbd39b5973f5c65d +Subproject commit 9329cfacd4c7d20bcb43d772d947ff9e39b65df9 diff --git a/script/DeployChildContracts.s.sol b/script/DeployChildContracts.s.sol index 58a190f1a..ebb745c6f 100644 --- a/script/DeployChildContracts.s.sol +++ b/script/DeployChildContracts.s.sol @@ -18,39 +18,48 @@ contract DeployChildContracts is Script { uint256 deployerPrivateKey = vm.envUint("CHILD_PRIVATE_KEY"); address childGateway = vm.envAddress("CHILD_GATEWAY_ADDRESS"); address childGasService = vm.envAddress("CHILD_GAS_SERVICE_ADDRESS"); // Not yet used. - address initialChildChainAdmin = vm.envAddress("INITIAL_CHILDCHAIN_ADMIN"); string memory childRpcUrl = vm.envString("CHILD_RPC_URL"); vm.createSelectFork(childRpcUrl); vm.startBroadcast(deployerPrivateKey); - ProxyAdmin proxyAdmin = new ProxyAdmin(initialChildChainAdmin); + ProxyAdmin proxyAdmin = new ProxyAdmin(); ChildERC20 childTokenTemplate = new ChildERC20(); childTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18); - ChildERC20Bridge childBridge = new ChildERC20Bridge(); - childBridge.initialize(address(1), "0x1", address(1), "root", address(1)); + ChildERC20Bridge childBridgeImplementation = new ChildERC20Bridge(); + childBridgeImplementation.initialize(address(1), "0x123", address(1), "root", address(1)); TransparentUpgradeableProxy childBridgeProxy = new TransparentUpgradeableProxy( - address(childBridge), + address(childBridgeImplementation), address(proxyAdmin), "" ); // TODO put behind proxy - ChildAxelarBridgeAdaptor childBridgeAdaptor = new ChildAxelarBridgeAdaptor( + ChildAxelarBridgeAdaptor childBridgeAdaptorImplementation = new ChildAxelarBridgeAdaptor( childGateway, // child gateway - address(childBridge) // child bridge + address(childBridgeProxy) // child bridge + ); + + // TODO confirm that we want the same proxyAdmin for both + TransparentUpgradeableProxy childBridgeAdaptorProxy = new TransparentUpgradeableProxy( + address(childBridgeAdaptorImplementation), + address(proxyAdmin), + "" ); WIMX wrappedIMX = new WIMX(); vm.stopBroadcast(); + console2.log(ChildAxelarBridgeAdaptor(address(childBridgeAdaptorProxy)).rootBridgeAdaptor()); + console2.log(childGateway); console2.log("====ADDRESSES===="); - console2.log("Child ERC20 Bridge: %s", address(childBridge)); - console2.log("Child Axelar Bridge Adaptor: %s", address(childBridgeAdaptor)); + console2.log("Child ERC20 Bridge: %s", address(childBridgeProxy)); + console2.log("Child Axelar Bridge Adaptor Proxy: %s", address(childBridgeAdaptorProxy)); + console2.log("Child Axelar Bridge Adaptor Implementation: %s", address(childBridgeAdaptorImplementation)); console2.log("childTokenTemplate: %s", address(childTokenTemplate)); console2.log("Wrapped IMX: %s", address(wrappedIMX)); } diff --git a/script/InitializeChildContracts.s.sol b/script/InitializeChildContracts.s.sol index f22772941..ce0769ec0 100644 --- a/script/InitializeChildContracts.s.sol +++ b/script/InitializeChildContracts.s.sol @@ -38,5 +38,8 @@ contract InitializeChildContracts is Script { childAxelarBridgeAdaptor.setRootBridgeAdaptor(); vm.stopBroadcast(); + + console2.log("DINGDING"); + console2.log(childAxelarBridgeAdaptor.rootBridgeAdaptor()); } } From 59a414002d603008bf65ee0025b8744ac2b917ef Mon Sep 17 00:00:00 2001 From: Benjamin Patch Date: Tue, 31 Oct 2023 14:07:32 +1100 Subject: [PATCH 3/8] Fix tests with child contracts initializable --- script/DeployChildContracts.s.sol | 4 +-- script/InitializeChildContracts.s.sol | 2 +- src/child/ChildAxelarBridgeAdaptor.sol | 29 +++++++++---------- src/test/child/MockChildERC20Bridge.sol | 4 +++ .../integration/child/ChildAxelarBridge.t.sol | 4 ++- .../unit/child/ChildAxelarBridgeAdaptor.t.sol | 9 +++--- 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/script/DeployChildContracts.s.sol b/script/DeployChildContracts.s.sol index ebb745c6f..10ec87111 100644 --- a/script/DeployChildContracts.s.sol +++ b/script/DeployChildContracts.s.sol @@ -37,10 +37,8 @@ contract DeployChildContracts is Script { "" ); - // TODO put behind proxy ChildAxelarBridgeAdaptor childBridgeAdaptorImplementation = new ChildAxelarBridgeAdaptor( - childGateway, // child gateway - address(childBridgeProxy) // child bridge + childGateway ); // TODO confirm that we want the same proxyAdmin for both diff --git a/script/InitializeChildContracts.s.sol b/script/InitializeChildContracts.s.sol index ce0769ec0..84fa4c370 100644 --- a/script/InitializeChildContracts.s.sol +++ b/script/InitializeChildContracts.s.sol @@ -35,7 +35,7 @@ contract InitializeChildContracts is Script { address(childAxelarBridgeAdaptor), rootBridgeAdaptorString, childTokenTemplate, rootChainName, rootIMXToken ); - childAxelarBridgeAdaptor.setRootBridgeAdaptor(); + childAxelarBridgeAdaptor.initialize(address(childERC20Bridge)); vm.stopBroadcast(); diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index fd0f983ac..ae79be872 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -2,30 +2,29 @@ pragma solidity ^0.8.21; import {AxelarExecutable} from "@axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {IChildERC20Bridge} from "../interfaces/child/IChildERC20Bridge.sol"; import {IChildAxelarBridgeAdaptorErrors} from "../interfaces/child/IChildAxelarBridgeAdaptor.sol"; -contract ChildAxelarBridgeAdaptor is AxelarExecutable, IChildAxelarBridgeAdaptorErrors { +contract ChildAxelarBridgeAdaptor is AxelarExecutable, Initializable, IChildAxelarBridgeAdaptorErrors { /// @notice Address of bridge to relay messages to. - IChildERC20Bridge public immutable CHILD_BRIDGE; + IChildERC20Bridge public childBridge; string public rootBridgeAdaptor; - constructor(address _gateway, address _childBridge) AxelarExecutable(_gateway) { + constructor(address _gateway) AxelarExecutable(_gateway) {} + + /** + * @notice Initializes the contract. + * @param _childBridge Address of the child bridge contract. + * @dev Always sets the rootBridgeAdaptor to whatever the rootERC20BridgeAdaptor of the bridge contract is. + */ + function initialize(address _childBridge) external initializer { if (_childBridge == address(0)) { revert ZeroAddress(); } - CHILD_BRIDGE = IChildERC20Bridge(_childBridge); - } - - // TODO tests for this - // TODO does this need to be permissioned? - /** - * @notice Sets the root bridge adaptor address. - * @dev Always sets it to whatever the rootERC20BridgeAdaptor of the bridge contract is. - */ - function setRootBridgeAdaptor() external { - rootBridgeAdaptor = CHILD_BRIDGE.rootERC20BridgeAdaptor(); + childBridge = IChildERC20Bridge(_childBridge); + rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor(); } /** @@ -36,6 +35,6 @@ contract ChildAxelarBridgeAdaptor is AxelarExecutable, IChildAxelarBridgeAdaptor internal override { - CHILD_BRIDGE.onMessageReceive(sourceChain_, sourceAddress_, payload_); + childBridge.onMessageReceive(sourceChain_, sourceAddress_, payload_); } } diff --git a/src/test/child/MockChildERC20Bridge.sol b/src/test/child/MockChildERC20Bridge.sol index 4bbb6f0c0..212dd0fd8 100644 --- a/src/test/child/MockChildERC20Bridge.sol +++ b/src/test/child/MockChildERC20Bridge.sol @@ -3,4 +3,8 @@ pragma solidity ^0.8.21; contract MockChildERC20Bridge { function onMessageReceive(string calldata, string calldata, bytes calldata) external {} + + function rootERC20BridgeAdaptor() external pure returns (string memory) { + return "rootERC20BridgeAdaptor"; + } } diff --git a/test/integration/child/ChildAxelarBridge.t.sol b/test/integration/child/ChildAxelarBridge.t.sol index 1bdbd36b1..ab1d86891 100644 --- a/test/integration/child/ChildAxelarBridge.t.sol +++ b/test/integration/child/ChildAxelarBridge.t.sol @@ -33,7 +33,7 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil childERC20Bridge = new ChildERC20Bridge(); mockChildAxelarGateway = new MockChildAxelarGateway(); childAxelarBridgeAdaptor = - new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway), address(childERC20Bridge)); + new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); childERC20Bridge.initialize( address(childAxelarBridgeAdaptor), @@ -42,6 +42,8 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil ROOT_CHAIN_NAME, IMX_TOKEN_ADDRESS ); + + childAxelarBridgeAdaptor.initialize(address(childERC20Bridge)); } function test_ChildTokenMap() public { diff --git a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol index e5f6c45db..fd5783fb7 100644 --- a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol +++ b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol @@ -20,18 +20,19 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro mockChildERC20Bridge = new MockChildERC20Bridge(); mockChildAxelarGateway = new MockChildAxelarGateway(); childAxelarBridgeAdaptor = - new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway), address(mockChildERC20Bridge)); + new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); + childAxelarBridgeAdaptor.initialize(address(mockChildERC20Bridge)); } function test_Constructor_SetsValues() public { - assertEq(address(childAxelarBridgeAdaptor.CHILD_BRIDGE()), address(mockChildERC20Bridge), "childBridge not set"); + assertEq(address(childAxelarBridgeAdaptor.childBridge()), address(mockChildERC20Bridge), "childBridge not set"); assertEq(address(childAxelarBridgeAdaptor.gateway()), address(mockChildAxelarGateway), "gateway not set"); } function test_RevertIf_ConstructorGivenZeroAddress() public { + ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); - // Gateway address being zero is checked in Axelar's AxelarExecutable smart contract. - new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS, address(0)); + newAdaptor.initialize(address(0)); } function test_Execute() public { From ba6b4012c5f1a663eecfe79dbfa899fb5cfaa1d3 Mon Sep 17 00:00:00 2001 From: Benjamin Patch Date: Wed, 1 Nov 2023 09:56:44 +1100 Subject: [PATCH 4/8] All contracts behind proxies --- axelar-local-dev/chain-config/local.json | 2 +- .../chain-config/local.template.json | 2 +- deploy.sh | 47 +++++++---- script/DeployChildContracts.s.sol | 17 ++-- script/DeployRootContracts.s.sol | 38 ++++++--- script/InitializeChildContracts.s.sol | 3 - script/InitializeRootContracts.s.sol | 78 ++++++++++++++----- src/child/ChildAxelarBridgeAdaptor.sol | 10 +++ src/root/RootAxelarBridgeAdaptor.sol | 45 ++++++----- .../integration/child/ChildAxelarBridge.t.sol | 3 +- .../unit/child/ChildAxelarBridgeAdaptor.t.sol | 3 +- test/unit/root/RootAxelarBridgeAdaptor.t.sol | 32 +++----- test/utils.t.sol | 9 +-- 13 files changed, 177 insertions(+), 112 deletions(-) diff --git a/axelar-local-dev/chain-config/local.json b/axelar-local-dev/chain-config/local.json index 017e00b57..9a04303f3 100644 --- a/axelar-local-dev/chain-config/local.json +++ b/axelar-local-dev/chain-config/local.json @@ -16,7 +16,7 @@ "function mapToken(address rootToken) external payable returns (address)", "function deposit(address rootToken, uint256 amount) external payable" ], - "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" }, "usdc": { "abi": [ diff --git a/axelar-local-dev/chain-config/local.template.json b/axelar-local-dev/chain-config/local.template.json index 017e00b57..9a04303f3 100644 --- a/axelar-local-dev/chain-config/local.template.json +++ b/axelar-local-dev/chain-config/local.template.json @@ -16,7 +16,7 @@ "function mapToken(address rootToken) external payable returns (address)", "function deposit(address rootToken, uint256 amount) external payable" ], - "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" }, "usdc": { "abi": [ diff --git a/deploy.sh b/deploy.sh index 5a6f399c1..c67aee212 100755 --- a/deploy.sh +++ b/deploy.sh @@ -17,45 +17,52 @@ function main() { forge script script/DeployRootContracts.s.sol:DeployRootContracts --broadcast forge script script/DeployChildContracts.s.sol:DeployChildContracts --broadcast - echo "sleepy boy" - sleep 5 - root_filename="broadcast/DeployRootContracts.s.sol/$ROOT_CHAIN_ID/run-latest.json" child_filename="broadcast/DeployChildContracts.s.sol/$CHILD_CHAIN_ID/run-latest.json" # Extract smart contract addresses from deployments JSON - root_erc20_bridge=$( get_deployed_contract "$root_filename" "RootERC20Bridge" ) - root_bridge_adaptor=$( get_deployed_contract "$root_filename" "RootAxelarBridgeAdaptor" ) + root_proxies=$( get_deployed_contract "$root_filename" "TransparentUpgradeableProxy" ) + root_erc20_bridge_implementation=$( get_deployed_contract "$root_filename" "RootERC20Bridge" ) + root_bridge_adaptor_implementation=$( get_deployed_contract "$root_filename" "RootAxelarBridgeAdaptor" ) root_chain_child_token_template=$( get_deployed_contract "$root_filename" "ChildERC20" ) + root_proxy_admin=$( get_deployed_contract "$root_filename" "ProxyAdmin" ) if [ "$ENVIRONMENT" = "local" ]; then root_weth_contract=$( get_deployed_contract "$root_filename" "WETH" ) export ROOT_WETH_ADDRESS=$root_weth_contract fi + child_proxies=$( get_deployed_contract "$child_filename" "TransparentUpgradeableProxy" ) child_erc20_bridge_implementation=$( get_deployed_contract "$child_filename" "ChildERC20Bridge" ) - proxies=$( get_deployed_contract "$child_filename" "TransparentUpgradeableProxy" ) child_bridge_adaptor_implementation=$( get_deployed_contract "$child_filename" "ChildAxelarBridgeAdaptor" ) child_chain_child_token_template=$( get_deployed_contract "$child_filename" "ChildERC20" ) + child_proxy_admin=$( get_deployed_contract "$child_filename" "ProxyAdmin" ) - echo "Proxies: $proxies" - + # In the TransparentUpgradeableProxy contract, you have to query the storage slot directly. implementation_storage_slot="0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" while IFS= read -r proxy_address; do - echo "... $proxy_address ..." implementation_slot_value=$(cast storage --rpc-url "$CHILD_RPC_URL" "$proxy_address" "$implementation_storage_slot") implementation_address=$(cast parse-bytes32-address "$implementation_slot_value") - echo "logic: $implementation_address" if [ "$implementation_address" = "$child_erc20_bridge_implementation" ]; then child_erc20_bridge_proxy=$proxy_address elif [ "$implementation_address" = "$child_bridge_adaptor_implementation" ]; then child_bridge_adaptor_proxy=$proxy_address fi - done <<< "$proxies" + done <<< "$child_proxies" + + while IFS= read -r proxy_address; do + implementation_slot_value=$(cast storage --rpc-url "$ROOT_RPC_URL" "$proxy_address" "$implementation_storage_slot") + implementation_address=$(cast parse-bytes32-address "$implementation_slot_value") + if [ "$implementation_address" = "$root_erc20_bridge_implementation" ]; then + root_erc20_bridge_proxy=$proxy_address + elif [ "$implementation_address" = "$root_bridge_adaptor_implementation" ]; then + root_bridge_adaptor_proxy=$proxy_address + fi + done <<< "$root_proxies" - export ROOT_ERC20_BRIDGE=$root_erc20_bridge - export ROOT_BRIDGE_ADAPTOR=$root_bridge_adaptor + export ROOT_ERC20_BRIDGE=$root_erc20_bridge_proxy + export ROOT_BRIDGE_ADAPTOR=$root_bridge_adaptor_proxy export ROOTCHAIN_CHILD_TOKEN_TEMPLATE=$root_chain_child_token_template export CHILD_BRIDGE_ADAPTOR=$child_bridge_adaptor_proxy @@ -68,12 +75,18 @@ function main() { # Write JSON file with contract addresses echo "{ \"root_chain_id\": \"$ROOT_CHAIN_ID\", - \"root_bridge\": \"$root_erc20_bridge\", - \"root_bridge_adaptor\": \"$root_bridge_adaptor\", + \"root_proxy_admin_address\": \"$root_proxy_admin\", + \"root_bridge_proxy_address\": \"$root_erc20_bridge_proxy\", + \"root_bridge_implementation_address\": \"$root_erc20_bridge_implementation\", + \"root_bridge_adaptor_proxy_address\": \"$root_bridge_adaptor_proxy\", + \"root_bridge_adaptor_implementation_address\": \"$root_bridge_adaptor_implementation\", \"root_chain_child_token_template\": \"$root_chain_child_token_template\", \"child_chain_id\": \"$CHILD_CHAIN_ID\", - \"child_bridge_address\": \"$child_erc20_bridge_proxy\", - \"child_bridge_adaptor\": \"$child_bridge_adaptor_proxy\", + \"child_proxy_admin_address\": \"$child_proxy_admin\", + \"child_bridge_proxy_address\": \"$child_erc20_bridge_proxy\", + \"child_bridge_implementation_address\": \"$child_erc20_bridge_implementation\", + \"child_bridge_proxy_adaptor\": \"$child_bridge_adaptor_proxy\", + \"child_bridge_adaptor_implementation_address\": \"$child_bridge_adaptor_implementation\", \"child_chain_child_token_template\": \"$child_chain_child_token_template\" }" | jq . > addresses.json diff --git a/script/DeployChildContracts.s.sol b/script/DeployChildContracts.s.sol index 10ec87111..a8d1f7c0a 100644 --- a/script/DeployChildContracts.s.sol +++ b/script/DeployChildContracts.s.sol @@ -28,11 +28,11 @@ contract DeployChildContracts is Script { ChildERC20 childTokenTemplate = new ChildERC20(); childTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18); - ChildERC20Bridge childBridgeImplementation = new ChildERC20Bridge(); - childBridgeImplementation.initialize(address(1), "0x123", address(1), "root", address(1)); + ChildERC20Bridge childERC20BridgeImplementation = new ChildERC20Bridge(); + childERC20BridgeImplementation.initialize(address(1), "0x123", address(1), "root", address(1)); - TransparentUpgradeableProxy childBridgeProxy = new TransparentUpgradeableProxy( - address(childBridgeImplementation), + TransparentUpgradeableProxy childERC20BridgeProxy = new TransparentUpgradeableProxy( + address(childERC20BridgeImplementation), address(proxyAdmin), "" ); @@ -41,7 +41,6 @@ contract DeployChildContracts is Script { childGateway ); - // TODO confirm that we want the same proxyAdmin for both TransparentUpgradeableProxy childBridgeAdaptorProxy = new TransparentUpgradeableProxy( address(childBridgeAdaptorImplementation), address(proxyAdmin), @@ -51,11 +50,11 @@ contract DeployChildContracts is Script { WIMX wrappedIMX = new WIMX(); vm.stopBroadcast(); - console2.log(ChildAxelarBridgeAdaptor(address(childBridgeAdaptorProxy)).rootBridgeAdaptor()); - console2.log(childGateway); - console2.log("====ADDRESSES===="); - console2.log("Child ERC20 Bridge: %s", address(childBridgeProxy)); + console2.log("====CHILD ADDRESSES===="); + console2.log("ProxyAdmin: %", address(proxyAdmin)); + console2.log("Child ERC20 Bridge Proxy: %s", address(childERC20BridgeProxy)); + console2.log("Child ERC20 Bridge Implementation: %s", address(childERC20BridgeImplementation)); console2.log("Child Axelar Bridge Adaptor Proxy: %s", address(childBridgeAdaptorProxy)); console2.log("Child Axelar Bridge Adaptor Implementation: %s", address(childBridgeAdaptorImplementation)); console2.log("childTokenTemplate: %s", address(childTokenTemplate)); diff --git a/script/DeployRootContracts.s.sol b/script/DeployRootContracts.s.sol index 0c3d41021..a1f49fceb 100644 --- a/script/DeployRootContracts.s.sol +++ b/script/DeployRootContracts.s.sol @@ -3,6 +3,9 @@ pragma solidity ^0.8.21; import {Script, console2} from "forge-std/Script.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + import {ChildERC20} from "../src/child/ChildERC20.sol"; import {RootERC20Bridge} from "../src/root/RootERC20Bridge.sol"; import {RootAxelarBridgeAdaptor} from "../src/root/RootAxelarBridgeAdaptor.sol"; @@ -17,9 +20,6 @@ contract DeployRootContracts is Script { function run() public { uint256 rootPrivateKey = vm.envUint("ROOT_PRIVATE_KEY"); string memory rootRpcUrl = vm.envString("ROOT_RPC_URL"); - address rootGateway = vm.envAddress("ROOT_GATEWAY_ADDRESS"); - address rootGasService = vm.envAddress("ROOT_GAS_SERVICE_ADDRESS"); - string memory childChainName = vm.envString("CHILD_CHAIN_NAME"); string memory deployEnvironment = vm.envString("ENVIRONMENT"); /** @@ -28,17 +28,30 @@ contract DeployRootContracts is Script { vm.createSelectFork(rootRpcUrl); vm.startBroadcast(rootPrivateKey); + ProxyAdmin proxyAdmin = new ProxyAdmin(); + // The ChildERC20 deployment on the root chain. ChildERC20 rootChainChildTokenTemplate = new ChildERC20(); rootChainChildTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18); - RootERC20Bridge rootERC20Bridge = new RootERC20Bridge(); + RootERC20Bridge rootERC20BridgeImplementation = new RootERC20Bridge(); + rootERC20BridgeImplementation.initialize(address(1), address(1), "filler", address(1), address(1), address(1)); + TransparentUpgradeableProxy rootERC20BridgeProxy = new TransparentUpgradeableProxy( + address(rootERC20BridgeImplementation), + address(proxyAdmin), + "" + ); - RootAxelarBridgeAdaptor rootBridgeAdaptor = new RootAxelarBridgeAdaptor( - address(rootERC20Bridge), // root bridge - childChainName, // child chain name - rootGateway, // axelar gateway - rootGasService // axelar gas service + // TODO add dummy initialize of implementation contracts! + + RootAxelarBridgeAdaptor rootBridgeAdaptorImplementation = new RootAxelarBridgeAdaptor(); + rootBridgeAdaptorImplementation.initialize( + address(rootERC20BridgeImplementation), "Filler", address(1), address(1) + ); + TransparentUpgradeableProxy rootBridgeAdaptorProxy = new TransparentUpgradeableProxy( + address(rootBridgeAdaptorImplementation), + address(proxyAdmin), + "" ); if (Strings.equal(deployEnvironment, "local")) { @@ -48,8 +61,11 @@ contract DeployRootContracts is Script { vm.stopBroadcast(); console2.log("====ROOT ADDRESSES===="); - console2.log("Root ERC20 Bridge: %s", address(rootERC20Bridge)); - console2.log("Root Axelar Bridge Adaptor: %s", address(rootBridgeAdaptor)); + console2.log("ProxyAdmin: %", address(proxyAdmin)); + console2.log("Root ERC20 Bridge Proxy: %s", address(rootERC20BridgeProxy)); + console2.log("Root ERC20 Bridge Implementation: %s", address(rootERC20BridgeImplementation)); + console2.log("Root Axelar Bridge Adaptor Proxy: %s", address(rootBridgeAdaptorProxy)); + console2.log("Root Axelar Bridge Adaptor Implementation: %s", address(rootBridgeAdaptorImplementation)); console2.log("ROOT CHAIN childTokenTemplate: %s", address(rootChainChildTokenTemplate)); } } diff --git a/script/InitializeChildContracts.s.sol b/script/InitializeChildContracts.s.sol index 84fa4c370..ec29a6cd9 100644 --- a/script/InitializeChildContracts.s.sol +++ b/script/InitializeChildContracts.s.sol @@ -38,8 +38,5 @@ contract InitializeChildContracts is Script { childAxelarBridgeAdaptor.initialize(address(childERC20Bridge)); vm.stopBroadcast(); - - console2.log("DINGDING"); - console2.log(childAxelarBridgeAdaptor.rootBridgeAdaptor()); } } diff --git a/script/InitializeRootContracts.s.sol b/script/InitializeRootContracts.s.sol index 2a8d43e13..e0c869a34 100644 --- a/script/InitializeRootContracts.s.sol +++ b/script/InitializeRootContracts.s.sol @@ -13,39 +13,75 @@ import {Utils} from "./Utils.sol"; // TODO update private key usage to be more secure: https://book.getfoundry.sh/reference/forge/forge-script#wallet-options---raw +struct InitializeRootContractsParams { + RootERC20Bridge rootERC20Bridge; + RootAxelarBridgeAdaptor rootBridgeAdaptor; + address rootChainChildTokenTemplate; + address childBridgeAdaptor; + address childERC20Bridge; + string rootRpcUrl; + uint256 rootPrivateKey; + address rootIMXToken; + address rootWETHToken; + string childChainName; + address rootGateway; + address rootGasService; +} + contract InitializeRootContracts is Script { function run() public { - RootERC20Bridge rootERC20Bridge = RootERC20Bridge(payable(vm.envAddress("ROOT_ERC20_BRIDGE"))); - RootAxelarBridgeAdaptor rootBridgeAdaptor = RootAxelarBridgeAdaptor(vm.envAddress("ROOT_BRIDGE_ADAPTOR")); - address rootChainChildTokenTemplate = vm.envAddress("ROOTCHAIN_CHILD_TOKEN_TEMPLATE"); - address childBridgeAdaptor = vm.envAddress("CHILD_BRIDGE_ADAPTOR"); - address childERC20Bridge = vm.envAddress("CHILD_ERC20_BRIDGE"); - string memory rootRpcUrl = vm.envString("ROOT_RPC_URL"); - uint256 rootPrivateKey = vm.envUint("ROOT_PRIVATE_KEY"); - address rootIMXToken = vm.envAddress("ROOT_IMX_ADDRESS"); - address rootWETHToken = vm.envAddress("ROOT_WETH_ADDRESS"); - - string[] memory checksumInputs = Utils.getChecksumInputs(childBridgeAdaptor); + InitializeRootContractsParams memory params = InitializeRootContractsParams({ + rootERC20Bridge: RootERC20Bridge(payable(vm.envAddress("ROOT_ERC20_BRIDGE"))), + rootBridgeAdaptor: RootAxelarBridgeAdaptor(vm.envAddress("ROOT_BRIDGE_ADAPTOR")), + rootChainChildTokenTemplate: vm.envAddress("ROOTCHAIN_CHILD_TOKEN_TEMPLATE"), + childBridgeAdaptor: vm.envAddress("CHILD_BRIDGE_ADAPTOR"), + childERC20Bridge: vm.envAddress("CHILD_ERC20_BRIDGE"), + rootRpcUrl: vm.envString("ROOT_RPC_URL"), + rootPrivateKey: vm.envUint("ROOT_PRIVATE_KEY"), + rootIMXToken: vm.envAddress("ROOT_IMX_ADDRESS"), + rootWETHToken: vm.envAddress("ROOT_WETH_ADDRESS"), + childChainName: vm.envString("CHILD_CHAIN_NAME"), + rootGateway: vm.envAddress("ROOT_GATEWAY_ADDRESS"), + rootGasService: vm.envAddress("ROOT_GAS_SERVICE_ADDRESS") + }); + // RootERC20Bridge rootERC20Bridge = RootERC20Bridge(payable(vm.envAddress("ROOT_ERC20_BRIDGE"))); + // RootAxelarBridgeAdaptor rootBridgeAdaptor = RootAxelarBridgeAdaptor(vm.envAddress("ROOT_BRIDGE_ADAPTOR")); + // address rootChainChildTokenTemplate = vm.envAddress("ROOTCHAIN_CHILD_TOKEN_TEMPLATE"); + // address childBridgeAdaptor = vm.envAddress("CHILD_BRIDGE_ADAPTOR"); + // address childERC20Bridge = vm.envAddress("CHILD_ERC20_BRIDGE"); + // string memory rootRpcUrl = vm.envString("ROOT_RPC_URL"); + // uint256 rootPrivateKey = vm.envUint("ROOT_PRIVATE_KEY"); + // address rootIMXToken = vm.envAddress("ROOT_IMX_ADDRESS"); + // address rootWETHToken = vm.envAddress("ROOT_WETH_ADDRESS"); + // string memory childChainName = vm.envString("CHILD_CHAIN_NAME"); + // address rootGateway = vm.envAddress("ROOT_GATEWAY_ADDRESS"); + // address rootGasService = vm.envAddress("ROOT_GAS_SERVICE_ADDRESS"); + + string[] memory checksumInputs = Utils.getChecksumInputs(params.childBridgeAdaptor); bytes memory checksumOutput = vm.ffi(checksumInputs); string memory childBridgeAdaptorChecksum = string(Utils.removeZeroByteValues(checksumOutput)); /** * INITIALIZE ROOT CHAIN CONTRACTS */ - vm.createSelectFork(rootRpcUrl); - vm.startBroadcast(rootPrivateKey); + vm.createSelectFork(params.rootRpcUrl); + vm.startBroadcast(params.rootPrivateKey); - rootERC20Bridge.initialize( - address(rootBridgeAdaptor), - childERC20Bridge, + params.rootERC20Bridge.initialize( + address(params.rootBridgeAdaptor), + params.childERC20Bridge, childBridgeAdaptorChecksum, - rootChainChildTokenTemplate, - rootIMXToken, - rootWETHToken + params.rootChainChildTokenTemplate, + params.rootIMXToken, + params.rootWETHToken ); - rootBridgeAdaptor.setChildBridgeAdaptor(); + params.rootBridgeAdaptor.initialize( + address(params.rootERC20Bridge), // root bridge + params.childChainName, // child chain name + params.rootGateway, // axelar gateway + params.rootGasService // axelar gas service + ); vm.stopBroadcast(); - console2.log(rootERC20Bridge.childBridgeAdaptor()); } } diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index ae79be872..4408bb77d 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -27,6 +27,16 @@ contract ChildAxelarBridgeAdaptor is AxelarExecutable, Initializable, IChildAxel rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor(); } + // TODO tests for this + // TODO does this need to be permissioned? + /** + * @notice Sets the root bridge adaptor address. + * @dev Always sets it to whatever the rootERC20BridgeAdaptor of the bridge contract is. + */ + function setRootBridgeAdaptor() external { + rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor(); + } + /** * @dev This function is called by the parent `AxelarExecutable` contract to execute the payload. * @custom:assumes `sourceAddress_` is a 20 byte address. diff --git a/src/root/RootAxelarBridgeAdaptor.sol b/src/root/RootAxelarBridgeAdaptor.sol index 25873923e..0f8816438 100644 --- a/src/root/RootAxelarBridgeAdaptor.sol +++ b/src/root/RootAxelarBridgeAdaptor.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache 2.0 pragma solidity ^0.8.21; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; @@ -20,22 +21,29 @@ import {IRootERC20Bridge} from "../interfaces/root/IRootERC20Bridge.sol"; * @dev This is not an upgradeable contract, because it is trivial to deploy a new one if needed. */ contract RootAxelarBridgeAdaptor is + Initializable, IRootERC20BridgeAdaptor, IRootAxelarBridgeAdaptorEvents, IRootAxelarBridgeAdaptorErrors { using SafeERC20 for IERC20Metadata; - address public immutable ROOT_BRIDGE; + address public rootBridge; string public childBridgeAdaptor; /// @dev childChain could be immutable, but as of writing this Solidity does not support immutable strings. /// see: https://ethereum.stackexchange.com/questions/127622/typeerror-immutable-variables-cannot-have-a-non-value-type string public childChain; - IAxelarGateway public immutable AXELAR_GATEWAY; - IAxelarGasService public immutable GAS_SERVICE; + IAxelarGateway public axelarGateway; + IAxelarGasService public gasService; mapping(uint256 => string) public chainIdToChainName; - constructor(address _rootBridge, string memory _childChain, address _axelarGateway, address _gasService) { + /** + * @dev Always sets it to whatever the childBridgeAdaptor of the bridge contract is. + */ + function initialize(address _rootBridge, string memory _childChain, address _axelarGateway, address _gasService) + public + initializer + { if (_rootBridge == address(0) || _axelarGateway == address(0) || _gasService == address(0)) { revert ZeroAddresses(); } @@ -43,10 +51,19 @@ contract RootAxelarBridgeAdaptor is if (bytes(_childChain).length == 0) { revert InvalidChildChain(); } - ROOT_BRIDGE = _rootBridge; + rootBridge = _rootBridge; childChain = _childChain; - AXELAR_GATEWAY = IAxelarGateway(_axelarGateway); - GAS_SERVICE = IAxelarGasService(_gasService); + axelarGateway = IAxelarGateway(_axelarGateway); + gasService = IAxelarGasService(_gasService); + childBridgeAdaptor = IRootERC20Bridge(rootBridge).childBridgeAdaptor(); + } + + /** + * @notice Sets the child bridge adaptor address. + * @dev Always sets it to whatever the childBridgeAdaptor of the bridge contract is. + */ + function setChildBridgeAdaptor() external { + childBridgeAdaptor = IRootERC20Bridge(rootBridge).childBridgeAdaptor(); } /** @@ -57,7 +74,7 @@ contract RootAxelarBridgeAdaptor is if (msg.value == 0) { revert NoGas(); } - if (msg.sender != ROOT_BRIDGE) { + if (msg.sender != rootBridge) { revert CallerNotBridge(); } @@ -66,19 +83,11 @@ contract RootAxelarBridgeAdaptor is string memory _childChain = childChain; // TODO For `sender` (first param), should likely be refundRecipient (and in which case refundRecipient should be renamed to sender and used as refund recipient) - GAS_SERVICE.payNativeGasForContractCall{value: msg.value}( + gasService.payNativeGasForContractCall{value: msg.value}( address(this), _childChain, _childBridgeAdaptor, payload, refundRecipient ); - AXELAR_GATEWAY.callContract(_childChain, _childBridgeAdaptor, payload); + axelarGateway.callContract(_childChain, _childBridgeAdaptor, payload); emit MapTokenAxelarMessage(_childChain, _childBridgeAdaptor, payload); } - - /** - * @notice Sets the child bridge adaptor address. - * @dev Always sets it to whatever the childBridgeAdaptor of the bridge contract is. - */ - function setChildBridgeAdaptor() external { - childBridgeAdaptor = IRootERC20Bridge(ROOT_BRIDGE).childBridgeAdaptor(); - } } diff --git a/test/integration/child/ChildAxelarBridge.t.sol b/test/integration/child/ChildAxelarBridge.t.sol index ab1d86891..945176926 100644 --- a/test/integration/child/ChildAxelarBridge.t.sol +++ b/test/integration/child/ChildAxelarBridge.t.sol @@ -32,8 +32,7 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil childERC20Bridge = new ChildERC20Bridge(); mockChildAxelarGateway = new MockChildAxelarGateway(); - childAxelarBridgeAdaptor = - new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); + childAxelarBridgeAdaptor = new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); childERC20Bridge.initialize( address(childAxelarBridgeAdaptor), diff --git a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol index fd5783fb7..18e324a1f 100644 --- a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol +++ b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol @@ -19,8 +19,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro function setUp() public { mockChildERC20Bridge = new MockChildERC20Bridge(); mockChildAxelarGateway = new MockChildAxelarGateway(); - childAxelarBridgeAdaptor = - new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); + childAxelarBridgeAdaptor = new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); childAxelarBridgeAdaptor.initialize(address(mockChildERC20Bridge)); } diff --git a/test/unit/root/RootAxelarBridgeAdaptor.t.sol b/test/unit/root/RootAxelarBridgeAdaptor.t.sol index f1fc3ee0e..c93c70d0c 100644 --- a/test/unit/root/RootAxelarBridgeAdaptor.t.sol +++ b/test/unit/root/RootAxelarBridgeAdaptor.t.sol @@ -33,42 +33,32 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR stubRootBridge = new StubRootBridge(); childBridgeAdaptor = stubRootBridge.childBridgeAdaptor(); - axelarAdaptor = new RootAxelarBridgeAdaptor( - address(stubRootBridge), - CHILD_CHAIN_NAME, - address(mockAxelarGateway), - address(axelarGasService) + axelarAdaptor = new RootAxelarBridgeAdaptor(); + axelarAdaptor.initialize( + address(stubRootBridge), CHILD_CHAIN_NAME, address(mockAxelarGateway), address(axelarGasService) ); axelarAdaptor.setChildBridgeAdaptor(); vm.deal(address(stubRootBridge), 99999999999); } function test_Constructor() public { - assertEq(axelarAdaptor.ROOT_BRIDGE(), address(stubRootBridge), "rootBridge not set"); + assertEq(axelarAdaptor.rootBridge(), address(stubRootBridge), "rootBridge not set"); assertEq(axelarAdaptor.childBridgeAdaptor(), childBridgeAdaptor, "childBridgeAdaptor not set"); assertEq(axelarAdaptor.childChain(), CHILD_CHAIN_NAME, "childChain not set"); - assertEq(address(axelarAdaptor.AXELAR_GATEWAY()), address(mockAxelarGateway), "axelarGateway not set"); - assertEq(address(axelarAdaptor.GAS_SERVICE()), address(axelarGasService), "axelarGasService not set"); + assertEq(address(axelarAdaptor.axelarGateway()), address(mockAxelarGateway), "axelarGateway not set"); + assertEq(address(axelarAdaptor.gasService()), address(axelarGasService), "axelarGasService not set"); } - function test_RevertWhen_ConstructorGivenZeroAddress() public { + function test_RevertWhen_InitializerGivenZeroAddress() public { + RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(); vm.expectRevert(ZeroAddresses.selector); - new RootAxelarBridgeAdaptor( - address(0), - CHILD_CHAIN_NAME, - address(mockAxelarGateway), - address(axelarGasService) - ); + newAdaptor.initialize(address(0), CHILD_CHAIN_NAME, address(mockAxelarGateway), address(axelarGasService)); } function test_RevertWhen_ConstructorGivenEmptyChildChainName() public { + RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(); vm.expectRevert(InvalidChildChain.selector); - new RootAxelarBridgeAdaptor( - address(this), - "", - address(mockAxelarGateway), - address(axelarGasService) - ); + newAdaptor.initialize(address(this), "", address(mockAxelarGateway), address(axelarGasService)); } /// @dev For this unit test we just want to make sure the correct functions are called on the Axelar Gateway and Gas Service. diff --git a/test/utils.t.sol b/test/utils.t.sol index 9a53896ae..48c309d8c 100644 --- a/test/utils.t.sol +++ b/test/utils.t.sol @@ -47,11 +47,9 @@ contract Utils is Test { mockAxelarGateway = new MockAxelarGateway(); axelarGasService = new MockAxelarGasService(); - axelarAdaptor = new RootAxelarBridgeAdaptor( - address(rootBridge), - childBridgeName, - address(mockAxelarGateway), - address(axelarGasService) + axelarAdaptor = new RootAxelarBridgeAdaptor(); + axelarAdaptor.initialize( + address(rootBridge), childBridgeName, address(mockAxelarGateway), address(axelarGasService) ); rootBridge.initialize( @@ -62,7 +60,6 @@ contract Utils is Test { imxTokenAddress, wethTokenAddress ); - axelarAdaptor.setChildBridgeAdaptor(); } function setupDeposit( From c4248b8e25e6c076f3f7d33ebfe794afa4cdabfa Mon Sep 17 00:00:00 2001 From: Benjamin Patch Date: Wed, 1 Nov 2023 10:08:07 +1100 Subject: [PATCH 5/8] Fix tests --- test/utils.t.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/utils.t.sol b/test/utils.t.sol index 48c309d8c..7151afd95 100644 --- a/test/utils.t.sol +++ b/test/utils.t.sol @@ -48,9 +48,6 @@ contract Utils is Test { axelarGasService = new MockAxelarGasService(); axelarAdaptor = new RootAxelarBridgeAdaptor(); - axelarAdaptor.initialize( - address(rootBridge), childBridgeName, address(mockAxelarGateway), address(axelarGasService) - ); rootBridge.initialize( address(axelarAdaptor), @@ -60,6 +57,10 @@ contract Utils is Test { imxTokenAddress, wethTokenAddress ); + + axelarAdaptor.initialize( + address(rootBridge), childBridgeName, address(mockAxelarGateway), address(axelarGasService) + ); } function setupDeposit( From 500215b796165e100a154e6d6f9fd153747b465a Mon Sep 17 00:00:00 2001 From: Benjamin Patch Date: Wed, 1 Nov 2023 11:53:31 +1100 Subject: [PATCH 6/8] Remove unused code --- lib/openzeppelin-contracts | 2 +- script/InitializeRootContracts.s.sol | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 9329cfacd..fd81a96f0 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 9329cfacd4c7d20bcb43d772d947ff9e39b65df9 +Subproject commit fd81a96f01cc42ef1c9a5399364968d0e07e9e90 diff --git a/script/InitializeRootContracts.s.sol b/script/InitializeRootContracts.s.sol index e0c869a34..c9a25c2c3 100644 --- a/script/InitializeRootContracts.s.sol +++ b/script/InitializeRootContracts.s.sol @@ -44,18 +44,6 @@ contract InitializeRootContracts is Script { rootGateway: vm.envAddress("ROOT_GATEWAY_ADDRESS"), rootGasService: vm.envAddress("ROOT_GAS_SERVICE_ADDRESS") }); - // RootERC20Bridge rootERC20Bridge = RootERC20Bridge(payable(vm.envAddress("ROOT_ERC20_BRIDGE"))); - // RootAxelarBridgeAdaptor rootBridgeAdaptor = RootAxelarBridgeAdaptor(vm.envAddress("ROOT_BRIDGE_ADAPTOR")); - // address rootChainChildTokenTemplate = vm.envAddress("ROOTCHAIN_CHILD_TOKEN_TEMPLATE"); - // address childBridgeAdaptor = vm.envAddress("CHILD_BRIDGE_ADAPTOR"); - // address childERC20Bridge = vm.envAddress("CHILD_ERC20_BRIDGE"); - // string memory rootRpcUrl = vm.envString("ROOT_RPC_URL"); - // uint256 rootPrivateKey = vm.envUint("ROOT_PRIVATE_KEY"); - // address rootIMXToken = vm.envAddress("ROOT_IMX_ADDRESS"); - // address rootWETHToken = vm.envAddress("ROOT_WETH_ADDRESS"); - // string memory childChainName = vm.envString("CHILD_CHAIN_NAME"); - // address rootGateway = vm.envAddress("ROOT_GATEWAY_ADDRESS"); - // address rootGasService = vm.envAddress("ROOT_GAS_SERVICE_ADDRESS"); string[] memory checksumInputs = Utils.getChecksumInputs(params.childBridgeAdaptor); bytes memory checksumOutput = vm.ffi(checksumInputs); From aa87ee04f8731eab5c3c59fd019a83e4863800ab Mon Sep 17 00:00:00 2001 From: Benjimmutable <123430337+Benjimmutable@users.noreply.github.com> Date: Thu, 2 Nov 2023 09:13:00 +1100 Subject: [PATCH 7/8] Update README.md Co-authored-by: Ermyas Abebe --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 093b7c2ad..b8d43b610 100644 --- a/README.md +++ b/README.md @@ -170,4 +170,4 @@ yarn run execute evm/call-contract local Ethereum Polygon deposit source .env cast call --rpc-url $CHILD_RPC_URL "0x3b39f73D7De57Ed2Fe85C0F30374D839dc625b93" "balanceOf(address)(uint256)" "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ``` -(Note: This assumed your address if the one associated with the above-specified private key) +(Note: This assumes your address is the one associated with the above-specified private key) From ef30f6c883e75b05d533d440f4a5243bc212aa40 Mon Sep 17 00:00:00 2001 From: Benjamin Patch Date: Thu, 2 Nov 2023 09:21:48 +1100 Subject: [PATCH 8/8] Remove other adaptor stored in adaptor --- script/DeployChildContracts.s.sol | 1 - src/child/ChildAxelarBridgeAdaptor.sol | 13 ------------- src/root/RootAxelarBridgeAdaptor.sol | 19 ++++++------------- test/unit/root/RootAxelarBridgeAdaptor.t.sol | 2 -- 4 files changed, 6 insertions(+), 29 deletions(-) diff --git a/script/DeployChildContracts.s.sol b/script/DeployChildContracts.s.sol index a8d1f7c0a..530eadb4e 100644 --- a/script/DeployChildContracts.s.sol +++ b/script/DeployChildContracts.s.sol @@ -17,7 +17,6 @@ contract DeployChildContracts is Script { function run() public { uint256 deployerPrivateKey = vm.envUint("CHILD_PRIVATE_KEY"); address childGateway = vm.envAddress("CHILD_GATEWAY_ADDRESS"); - address childGasService = vm.envAddress("CHILD_GAS_SERVICE_ADDRESS"); // Not yet used. string memory childRpcUrl = vm.envString("CHILD_RPC_URL"); vm.createSelectFork(childRpcUrl); diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index 4408bb77d..daa50d741 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -9,14 +9,12 @@ import {IChildAxelarBridgeAdaptorErrors} from "../interfaces/child/IChildAxelarB contract ChildAxelarBridgeAdaptor is AxelarExecutable, Initializable, IChildAxelarBridgeAdaptorErrors { /// @notice Address of bridge to relay messages to. IChildERC20Bridge public childBridge; - string public rootBridgeAdaptor; constructor(address _gateway) AxelarExecutable(_gateway) {} /** * @notice Initializes the contract. * @param _childBridge Address of the child bridge contract. - * @dev Always sets the rootBridgeAdaptor to whatever the rootERC20BridgeAdaptor of the bridge contract is. */ function initialize(address _childBridge) external initializer { if (_childBridge == address(0)) { @@ -24,17 +22,6 @@ contract ChildAxelarBridgeAdaptor is AxelarExecutable, Initializable, IChildAxel } childBridge = IChildERC20Bridge(_childBridge); - rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor(); - } - - // TODO tests for this - // TODO does this need to be permissioned? - /** - * @notice Sets the root bridge adaptor address. - * @dev Always sets it to whatever the rootERC20BridgeAdaptor of the bridge contract is. - */ - function setRootBridgeAdaptor() external { - rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor(); } /** diff --git a/src/root/RootAxelarBridgeAdaptor.sol b/src/root/RootAxelarBridgeAdaptor.sol index 0f8816438..e13e461ac 100644 --- a/src/root/RootAxelarBridgeAdaptor.sol +++ b/src/root/RootAxelarBridgeAdaptor.sol @@ -18,7 +18,6 @@ import {IRootERC20Bridge} from "../interfaces/root/IRootERC20Bridge.sol"; /** * @notice RootAxelarBridgeAdaptor is a bridge adaptor that allows the RootERC20Bridge to communicate with the Axelar Gateway. - * @dev This is not an upgradeable contract, because it is trivial to deploy a new one if needed. */ contract RootAxelarBridgeAdaptor is Initializable, @@ -29,7 +28,6 @@ contract RootAxelarBridgeAdaptor is using SafeERC20 for IERC20Metadata; address public rootBridge; - string public childBridgeAdaptor; /// @dev childChain could be immutable, but as of writing this Solidity does not support immutable strings. /// see: https://ethereum.stackexchange.com/questions/127622/typeerror-immutable-variables-cannot-have-a-non-value-type string public childChain; @@ -38,7 +36,11 @@ contract RootAxelarBridgeAdaptor is mapping(uint256 => string) public chainIdToChainName; /** - * @dev Always sets it to whatever the childBridgeAdaptor of the bridge contract is. + * @notice Initilization function for RootAxelarBridgeAdaptor. + * @param _rootBridge Address of root bridge contract. + * @param _childChain Name of child chain. + * @param _axelarGateway Address of Axelar Gateway contract. + * @param _gasService Address of Axelar Gas Service contract. */ function initialize(address _rootBridge, string memory _childChain, address _axelarGateway, address _gasService) public @@ -55,15 +57,6 @@ contract RootAxelarBridgeAdaptor is childChain = _childChain; axelarGateway = IAxelarGateway(_axelarGateway); gasService = IAxelarGasService(_gasService); - childBridgeAdaptor = IRootERC20Bridge(rootBridge).childBridgeAdaptor(); - } - - /** - * @notice Sets the child bridge adaptor address. - * @dev Always sets it to whatever the childBridgeAdaptor of the bridge contract is. - */ - function setChildBridgeAdaptor() external { - childBridgeAdaptor = IRootERC20Bridge(rootBridge).childBridgeAdaptor(); } /** @@ -79,7 +72,7 @@ contract RootAxelarBridgeAdaptor is } // Load from storage. - string memory _childBridgeAdaptor = childBridgeAdaptor; + string memory _childBridgeAdaptor = IRootERC20Bridge(rootBridge).childBridgeAdaptor(); string memory _childChain = childChain; // TODO For `sender` (first param), should likely be refundRecipient (and in which case refundRecipient should be renamed to sender and used as refund recipient) diff --git a/test/unit/root/RootAxelarBridgeAdaptor.t.sol b/test/unit/root/RootAxelarBridgeAdaptor.t.sol index c93c70d0c..bc0cda17f 100644 --- a/test/unit/root/RootAxelarBridgeAdaptor.t.sol +++ b/test/unit/root/RootAxelarBridgeAdaptor.t.sol @@ -37,13 +37,11 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR axelarAdaptor.initialize( address(stubRootBridge), CHILD_CHAIN_NAME, address(mockAxelarGateway), address(axelarGasService) ); - axelarAdaptor.setChildBridgeAdaptor(); vm.deal(address(stubRootBridge), 99999999999); } function test_Constructor() public { assertEq(axelarAdaptor.rootBridge(), address(stubRootBridge), "rootBridge not set"); - assertEq(axelarAdaptor.childBridgeAdaptor(), childBridgeAdaptor, "childBridgeAdaptor not set"); assertEq(axelarAdaptor.childChain(), CHILD_CHAIN_NAME, "childChain not set"); assertEq(address(axelarAdaptor.axelarGateway()), address(mockAxelarGateway), "axelarGateway not set"); assertEq(address(axelarAdaptor.gasService()), address(axelarGasService), "axelarGasService not set");