From e4de38e11e98f0c662efc82b1b4afff07403650a Mon Sep 17 00:00:00 2001 From: Craig M Date: Tue, 24 Oct 2023 14:48:22 +1300 Subject: [PATCH] remove ETH_TOKEN address from child initialise --- script/InitializeChildContracts.s.sol | 4 +-- src/child/ChildERC20Bridge.sol | 15 ++++----- src/interfaces/child/IChildERC20Bridge.sol | 2 ++ src/interfaces/root/IRootERC20Bridge.sol | 2 ++ src/root/RootERC20Bridge.sol | 5 +++ .../integration/child/ChildAxelarBridge.t.sol | 3 +- test/unit/child/ChildERC20Bridge.t.sol | 30 +++++++++--------- test/unit/root/RootERC20Bridge.t.sol | 31 +++++++++++-------- 8 files changed, 53 insertions(+), 39 deletions(-) diff --git a/script/InitializeChildContracts.s.sol b/script/InitializeChildContracts.s.sol index 8f0a6ba2..513d0b2e 100644 --- a/script/InitializeChildContracts.s.sol +++ b/script/InitializeChildContracts.s.sol @@ -19,7 +19,6 @@ contract InitializeChildContracts is Script { string memory childRpcUrl = vm.envString("CHILD_RPC_URL"); string memory rootChainName = vm.envString("ROOT_CHAIN_NAME"); address rootIMXToken = vm.envAddress("ROOT_IMX_ADDRESS"); - address rootETHToken = vm.envAddress("ROOT_ETH_ADDRESS"); /** * INITIALIZE CHILD CONTRACTS @@ -32,8 +31,7 @@ contract InitializeChildContracts is Script { Strings.toHexString(rootERC20BridgeAdaptor), childTokenTemplate, rootChainName, - rootIMXToken, - rootETHToken + rootIMXToken ); childAxelarBridgeAdaptor.setRootBridgeAdaptor(); diff --git a/src/child/ChildERC20Bridge.sol b/src/child/ChildERC20Bridge.sol index f0817a49..105d9787 100644 --- a/src/child/ChildERC20Bridge.sol +++ b/src/child/ChildERC20Bridge.sol @@ -60,7 +60,6 @@ contract ChildERC20Bridge is * @param newChildTokenTemplate Address of child token template to clone. * @param newRootChain A stringified representation of the chain that this bridge is connected to. Used for validation. * @param newRootIMXToken Address of ECR20 IMX on the root chain. - * @param newRootETHToken Address used to denote ETH on the root chain. * @dev Can only be called once. */ function initialize( @@ -68,14 +67,12 @@ contract ChildERC20Bridge is string memory newRootERC20BridgeAdaptor, address newChildTokenTemplate, string memory newRootChain, - address newRootIMXToken, - address newRootETHToken) + address newRootIMXToken) public initializer { if (newBridgeAdaptor == address(0) || newChildTokenTemplate == address(0) - || newRootIMXToken == address(0) - || newRootETHToken == address(0)) { + || newRootIMXToken == address(0)) { revert ZeroAddress(); } @@ -94,8 +91,8 @@ contract ChildERC20Bridge is rootIMXToken = newRootIMXToken; IChildERC20 clonedETHToken = - IChildERC20(Clones.cloneDeterministic(childTokenTemplate, keccak256(abi.encodePacked(newRootETHToken)))); - clonedETHToken.initialize(newRootETHToken, "Ethereum", "ETH", 18); + IChildERC20(Clones.cloneDeterministic(childTokenTemplate, keccak256(abi.encodePacked(NATIVE_ETH)))); + clonedETHToken.initialize(NATIVE_ETH, "Ethereum", "ETH", 18); childETHToken = address(clonedETHToken); } @@ -142,6 +139,10 @@ contract ChildERC20Bridge is revert CantMapIMX(); } + if (address(rootToken) == NATIVE_ETH) { + revert CantMapETH(); + } + if (rootTokenToChildToken[rootToken] != address(0)) { revert AlreadyMapped(); } diff --git a/src/interfaces/child/IChildERC20Bridge.sol b/src/interfaces/child/IChildERC20Bridge.sol index 302c37e5..94945b5b 100644 --- a/src/interfaces/child/IChildERC20Bridge.sol +++ b/src/interfaces/child/IChildERC20Bridge.sol @@ -63,6 +63,8 @@ interface IChildERC20BridgeErrors { error NotMapped(); /// @notice Error when attempting to map IMX. error CantMapIMX(); + /// @notice Error when attempting to map ETH. + error CantMapETH(); /// @notice Error when a token is already mapped. error AlreadyMapped(); /// @notice Error when a message is given to the bridge from an address not the designated bridge adaptor. diff --git a/src/interfaces/root/IRootERC20Bridge.sol b/src/interfaces/root/IRootERC20Bridge.sol index 08ee6634..1c104563 100644 --- a/src/interfaces/root/IRootERC20Bridge.sol +++ b/src/interfaces/root/IRootERC20Bridge.sol @@ -73,6 +73,8 @@ interface IRootERC20BridgeErrors { error NotMapped(); /// @notice Error when attempting to map IMX. error CantMapIMX(); + /// @notice Error when attempting to map ETH. + error CantMapETH(); /// @notice Error when token balance invariant check fails. error BalanceInvariantCheckFailed(uint256 actualBalance, uint256 expectedBalance); } diff --git a/src/root/RootERC20Bridge.sol b/src/root/RootERC20Bridge.sol index 75a0b8f1..71eebc9b 100644 --- a/src/root/RootERC20Bridge.sol +++ b/src/root/RootERC20Bridge.sol @@ -150,6 +150,11 @@ contract RootERC20Bridge is if (address(rootToken) == rootIMXToken) { revert CantMapIMX(); } + + if (address(rootToken) == NATIVE_ETH) { + revert CantMapETH(); + } + if (rootTokenToChildToken[address(rootToken)] != address(0)) { revert AlreadyMapped(); } diff --git a/test/integration/child/ChildAxelarBridge.t.sol b/test/integration/child/ChildAxelarBridge.t.sol index 850bfa2b..01144366 100644 --- a/test/integration/child/ChildAxelarBridge.t.sol +++ b/test/integration/child/ChildAxelarBridge.t.sol @@ -19,7 +19,6 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil string public ROOT_ADAPTOR_ADDRESS = Strings.toHexString(address(1)); string public ROOT_CHAIN_NAME = "ROOT_CHAIN"; address constant IMX_TOKEN_ADDRESS = address(0xccc); - address constant CHILD_ETH_TOKEN = address(0xddd); ChildERC20Bridge public childERC20Bridge; ChildERC20 public childERC20; @@ -36,7 +35,7 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway), address(childERC20Bridge)); childERC20Bridge.initialize( - address(childAxelarBridgeAdaptor), ROOT_ADAPTOR_ADDRESS, address(childERC20), ROOT_CHAIN_NAME, IMX_TOKEN_ADDRESS, CHILD_ETH_TOKEN + address(childAxelarBridgeAdaptor), ROOT_ADAPTOR_ADDRESS, address(childERC20), ROOT_CHAIN_NAME, IMX_TOKEN_ADDRESS ); } diff --git a/test/unit/child/ChildERC20Bridge.t.sol b/test/unit/child/ChildERC20Bridge.t.sol index 0218b9a7..0d6ed39d 100644 --- a/test/unit/child/ChildERC20Bridge.t.sol +++ b/test/unit/child/ChildERC20Bridge.t.sol @@ -35,7 +35,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B childTokenTemplate.initialize(address(123), "Test", "TST", 18); childBridge = new ChildERC20Bridge(); - childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN, NATIVE_ETH); + childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN); } function test_Initialize() public { @@ -50,49 +50,43 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B function test_RevertIfInitializeTwice() public { vm.expectRevert("Initializable: contract is already initialized"); - childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN, NATIVE_ETH); + childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN); } function test_RevertIf_InitializeWithAZeroAddressAdapter() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1)); } function test_RevertIf_InitializeWithAZeroAddressChildTemplate() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(1)); } function test_RevertIf_InitializeWithAZeroAddressIMXToken() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(0), address(1)); - } - - function test_RevertIf_InitializeWithAZeroAddressEthRootToken() public { - ChildERC20Bridge bridge = new ChildERC20Bridge(); - vm.expectRevert(ZeroAddress.selector); - bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(0)); + bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(0)); } function test_RevertIf_InitializeWithAZeroAddressAll() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(0), address(0)); + bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(0)); } function test_RevertIf_InitializeWithAnEmptyBridgeAdaptorString() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector); - bridge.initialize(address(this), "", address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN, NATIVE_ETH); + bridge.initialize(address(this), "", address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN); } function test_RevertIf_InitializeWithAnEmptyChainNameString() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(InvalidRootChain.selector); - bridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), "", ROOT_IMX_TOKEN, NATIVE_ETH); + bridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), "", ROOT_IMX_TOKEN); } function test_onMessageReceive_EmitsTokenMappedEvent() public { @@ -200,6 +194,14 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); } + function test_RevertIf_mapTokenCalledWithETHAddress() public { + bytes memory data = abi.encode( + childBridge.MAP_TOKEN_SIG(), NATIVE_ETH, "Ethereum", "ETH", 18 + ); + vm.expectRevert(CantMapETH.selector); + childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + } + function test_RevertIf_onMessageReceiveCalledTwice() public { bytes memory data = abi.encode( childBridge.MAP_TOKEN_SIG(), address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals() diff --git a/test/unit/root/RootERC20Bridge.t.sol b/test/unit/root/RootERC20Bridge.t.sol index 950cc6b8..95c60a78 100644 --- a/test/unit/root/RootERC20Bridge.t.sol +++ b/test/unit/root/RootERC20Bridge.t.sol @@ -22,7 +22,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid string constant CHILD_CHAIN_NAME = "test"; address constant IMX_TOKEN = address(0xccc); address constant CHILD_ETH_TOKEN = address(0xddd); - address constant NATIVE_TOKEN = address(0xeee); + address constant NATIVE_ETH = address(0xeee); uint256 constant mapTokenFee = 300; uint256 constant depositFee = 200; @@ -176,6 +176,11 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid rootBridge.mapToken{value: 300}(IERC20Metadata(IMX_TOKEN)); } + function test_RevertIf_mapTokenCalledWithETHAddress() public { + vm.expectRevert(CantMapETH.selector); + rootBridge.mapToken{value: 300}(IERC20Metadata(NATIVE_ETH)); + } + function test_updateRootBridgeAdaptor() public { address newAdaptorAddress = address(0x11111); @@ -201,7 +206,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid function test_depositETHCallsSendMessage() public { uint256 amount = 1000; - (, bytes memory predictedPayload) = setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false); + (, bytes memory predictedPayload) = setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false); vm.expectCall( address(mockAxelarAdaptor), @@ -214,16 +219,16 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid function test_depositETHEmitsNativeEthDepositEvent() public { uint256 amount = 1000; - setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false); + setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false); vm.expectEmit(); - emit NativeEthDeposit(NATIVE_TOKEN, CHILD_ETH_TOKEN, address(this), address(this), amount); + emit NativeEthDeposit(NATIVE_ETH, CHILD_ETH_TOKEN, address(this), address(this), amount); rootBridge.depositETH{value: amount+depositFee}(amount); } function test_RevertIf_depositETHInsufficientValue() public { uint256 amount = 1000; - setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false); + setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false); vm.expectRevert(InsufficientValue.selector); rootBridge.depositETH{value: (amount/2)+depositFee}(amount); @@ -236,7 +241,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid function test_depositToETHCallsSendMessage() public { uint256 amount = 1000; address receiver = address(12345); - (, bytes memory predictedPayload) = setupDepositTo(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, receiver, false); + (, bytes memory predictedPayload) = setupDepositTo(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, receiver, false); vm.expectCall( address(mockAxelarAdaptor), depositFee, @@ -249,17 +254,17 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid function test_depositToETHEmitsNativeEthDepositEvent() public { uint256 amount = 1000; address receiver = address(12345); - setupDepositTo(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, receiver, false); + setupDepositTo(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, receiver, false); vm.expectEmit(); - emit NativeEthDeposit(NATIVE_TOKEN, CHILD_ETH_TOKEN, address(this), receiver, amount); + emit NativeEthDeposit(NATIVE_ETH, CHILD_ETH_TOKEN, address(this), receiver, amount); rootBridge.depositToETH{value: amount+depositFee}(receiver, amount); } function test_RevertIf_depositToETHInsufficientValue() public { uint256 amount = 1000; address receiver = address(12345); - setupDepositTo(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, receiver, false); + setupDepositTo(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, receiver, false); vm.expectRevert(InsufficientValue.selector); rootBridge.depositToETH{value: (amount/2)+depositFee}(receiver, amount); @@ -271,7 +276,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid function test_RevertIf_depositETHAmountIsZero() public { uint256 amount = 0; - setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false); + setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false); vm.expectRevert(ZeroAmount.selector); rootBridge.depositETH{value: amount+depositFee}(amount); @@ -281,7 +286,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid uint256 amount = 0; address receiver = address(12345); - setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false); + setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false); vm.expectRevert(ZeroAmount.selector); rootBridge.depositToETH{value: amount+depositFee}(receiver, amount); @@ -289,7 +294,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid function test_RevertIf_depositAmountIsZero() public { uint256 amount = 0; - setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false); + setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false); vm.expectRevert(ZeroAmount.selector); rootBridge.deposit{value: depositFee}(token, amount); @@ -298,7 +303,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid function test_RevertIf_depositToAmountIsZero() public { uint256 amount = 0; address receiver = address(12345); - setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false); + setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false); vm.expectRevert(ZeroAmount.selector); rootBridge.depositTo{value: depositFee}(token, receiver, amount);