From 1f178d9dcffee6b89816bf2336393207f0a4efba Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Wed, 22 Nov 2023 18:29:05 +1100 Subject: [PATCH 1/7] Remove Axelar specific logic from Root bridge --- script/InitializeRootContracts.s.sol | 3 +- src/child/ChildAxelarBridgeAdaptor.sol | 13 +- src/common/AdaptorRoles.sol | 4 +- .../root/IRootAxelarBridgeAdaptor.sol | 17 ++ src/interfaces/root/IRootERC20Bridge.sol | 27 +- src/root/RootAxelarBridgeAdaptor.sol | 92 +++++-- src/root/RootERC20Bridge.sol | 50 +--- src/root/flowrate/RootERC20BridgeFlowRate.sol | 20 +- .../RootERC20BridgeFlowRateWithdraw.t.sol | 30 +-- test/mocks/root/StubRootBridge.sol | 2 +- test/unit/common/AdaptorRoles.t.sol | 2 +- test/unit/root/RootAxelarBridgeAdaptor.t.sol | 124 ++++++++-- test/unit/root/RootERC20Bridge.t.sol | 231 ++---------------- .../flowrate/RootERC20BridgeFlowRate.t.sol | 45 ++-- .../RootAxelarBridgeAdaptorWithdraw.t.sol | 61 ----- .../withdrawals/RootERC20BridgeWithdraw.t.sol | 54 ++-- test/utils.t.sol | 3 +- 17 files changed, 265 insertions(+), 513 deletions(-) delete mode 100644 test/unit/root/withdrawals/RootAxelarBridgeAdaptorWithdraw.t.sol diff --git a/script/InitializeRootContracts.s.sol b/script/InitializeRootContracts.s.sol index 7defcbf4..c227c5ae 100644 --- a/script/InitializeRootContracts.s.sol +++ b/script/InitializeRootContracts.s.sol @@ -78,11 +78,9 @@ contract InitializeRootContracts is Script { roles, address(params.rootBridgeAdaptor), params.childERC20Bridge, - childBridgeAdaptorChecksum, params.rootChainChildTokenTemplate, params.rootIMXToken, params.rootWETHToken, - params.childChainName, params.initialIMXCumulativeDepositLimit ); @@ -97,6 +95,7 @@ contract InitializeRootContracts is Script { adaptorRoles, address(params.rootERC20Bridge), // root bridge params.childChainName, // child chain name + childBridgeAdaptorChecksum, params.rootGasService // axelar gas service ); diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index 7feb0eac..970e0185 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -44,12 +44,15 @@ contract ChildAxelarBridgeAdaptor is constructor(address _gateway) AxelarExecutable(_gateway) {} /** - * @notice Initializes the contract. - * @param _childBridge Address of the child bridge contract. + * @notice Initialization function for ChildAxelarBridgeAdaptor. + * @param newRoles Struct containing addresses of roles. + * @param _rootChainId Axelar's ID for the root chain. + * @param _childBridge Address of child bridge contract. + * @param _gasService Address of Axelar Gas Service contract. */ function initialize( InitializationRoles memory newRoles, - string memory _rootChain, + string memory _rootChainId, address _childBridge, address _gasService ) external initializer { @@ -61,7 +64,7 @@ contract ChildAxelarBridgeAdaptor is revert ZeroAddress(); } - if (bytes(_rootChain).length == 0) { + if (bytes(_rootChainId).length == 0) { revert InvalidRootChain(); } @@ -73,7 +76,7 @@ contract ChildAxelarBridgeAdaptor is _grantRole(TARGET_MANAGER_ROLE, newRoles.targetManager); childBridge = IChildERC20Bridge(_childBridge); - rootChain = _rootChain; + rootChain = _rootChainId; gasService = IAxelarGasService(_gasService); } diff --git a/src/common/AdaptorRoles.sol b/src/common/AdaptorRoles.sol index b0ddc688..18784f45 100644 --- a/src/common/AdaptorRoles.sol +++ b/src/common/AdaptorRoles.sol @@ -17,7 +17,7 @@ abstract contract AdaptorRoles is AccessControlUpgradeable { /// @notice Role identifier for those who can update the gas service used by the adaptor. bytes32 public constant GAS_SERVICE_MANAGER_ROLE = keccak256("GAS_SERVICE_MANAGER"); - /// @notice Role identifier for those who can update targeted bridge used by the adpator (e.g. target is child chain on root adaptors). + /// @notice Role identifier for those who can update targeted bridge used by the adaptor (e.g. target is child chain on root adaptors). bytes32 public constant TARGET_MANAGER_ROLE = keccak256("TARGET_MANAGER"); // Role granting functions @@ -60,7 +60,7 @@ abstract contract AdaptorRoles is AccessControlUpgradeable { /** * @notice Function to target manager role from an address */ - function revokeTargetMangaerRole(address account) external onlyRole(DEFAULT_ADMIN_ROLE) { + function revokeTargetManagerRole(address account) external onlyRole(DEFAULT_ADMIN_ROLE) { revokeRole(TARGET_MANAGER_ROLE, account); } diff --git a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol index 85d2c1b6..9eefddf4 100644 --- a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol +++ b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol @@ -29,6 +29,13 @@ interface IRootAxelarBridgeAdaptor { */ function updateChildChain(string memory newChildChain) external; + /** + * @notice Update the child chain bridge address + * @param newChildBridgeAdaptor address of the new child bridge adaptor. + * @dev Can only be called by TARGET_MANAGER_ROLE. + */ + function updateChildBridgeAdaptor(string memory newChildBridgeAdaptor) external; + /** * @notice Update the gas service. * @param newGasService Address of new gas service. @@ -57,7 +64,17 @@ interface IRootAxelarBridgeAdaptorErrors { * @notice Contains the event types that can be emitted by a bridge adaptor */ interface IRootAxelarBridgeAdaptorEvents { + /// @notice Emitted when the child chain bridge adaptor is updated. + event ChildBridgeAdaptorUpdated(string oldChildBridgeAdaptor, string newChildBridgeAdaptor); + /// @notice Error when the given child chain bridge adaptor is invalid. + + error InvalidChildERC20BridgeAdaptor(); + /// @notice Error when a message received has invalid source address. + error InvalidSourceAddress(); + /// @notice Error when a message received has invalid source chain. + error InvalidSourceChain(); /// @notice Emitted when an Axelar message is sent to the child chain. + event AxelarMessageSent(string indexed childChain, string indexed childBridgeAdaptor, bytes indexed payload); /// @notice Emitted when an Axelar message is received from the child chain. event AdaptorExecute(string sourceChain, string sourceAddress_, bytes payload_); diff --git a/src/interfaces/root/IRootERC20Bridge.sol b/src/interfaces/root/IRootERC20Bridge.sol index 2299ce50..cd0ea05d 100644 --- a/src/interfaces/root/IRootERC20Bridge.sol +++ b/src/interfaces/root/IRootERC20Bridge.sol @@ -41,28 +41,13 @@ interface IRootERC20Bridge { */ function updateRootBridgeAdaptor(address newRootBridgeAdaptor) external; - /** - * @notice Updates the child bridge adaptor. - * @param newChildBridgeAdaptor String checksum address of new root bridge adaptor. - * @dev Can only be called by ADAPTOR_MANAGER_ROLE. - */ - function updateChildBridgeAdaptor(string memory newChildBridgeAdaptor) external; - - /** - * @notice Get the address of the bridge adaptor on the child chain. - * @return address of the bridge adaptor on the child chain. - */ - function childBridgeAdaptor() external view returns (string memory); - /** * @notice Receives a bridge message from the child chain. - * @param sourceChain The id of the chain the message originated from. - * @param sourceAddress The address of the contract on the child chain that sent the message. * @param data The data payload of the message. * @dev This function is called by the underlying bridge adaptor on the root chain, when it receives a validated message from the GMP. + * It assumes that the underlying adaptor has already validated the sender chain and sender address. */ - function onMessageReceive(string calldata sourceChain, string calldata sourceAddress, bytes calldata data) - external; + function onMessageReceive(bytes calldata data) external; /** * @notice Initiate sending a mapToken message to the child chain. @@ -119,8 +104,6 @@ interface IRootERC20Bridge { interface IRootERC20BridgeEvents { /// @notice Emitted when the root chain bridge adaptor is updated. event RootBridgeAdaptorUpdated(address oldRootBridgeAdaptor, address newRootBridgeAdaptor); - /// @notice Emitted when the child chain bridge adaptor is updated. - event ChildBridgeAdaptorUpdated(string oldChildBridgeAdaptor, string newChildBridgeAdaptor); /// @notice Emitted when the IMX deposit limit is updated. event NewImxDepositLimit(uint256 oldImxDepositLimit, uint256 newImxDepositLimit); /// @notice Emitted when a map token message is sent to the child chain. @@ -196,14 +179,8 @@ interface IRootERC20BridgeErrors { error CantMapWETH(); /// @notice Error when token balance invariant check fails. error BalanceInvariantCheckFailed(uint256 actualBalance, uint256 expectedBalance); - /// @notice Error when the given child chain bridge adaptor is invalid. - error InvalidChildERC20BridgeAdaptor(); /// @notice Error when a message received has invalid data. error InvalidData(string reason); - /// @notice Error when a message received has invalid source address. - error InvalidSourceAddress(); - /// @notice Error when a message received has invalid source chain. - error InvalidSourceChain(); /// @notice Error when caller is not the root bridge adaptor but should be. error NotBridgeAdaptor(); /// @notice Error when the total IMX deposit limit is exceeded diff --git a/src/root/RootAxelarBridgeAdaptor.sol b/src/root/RootAxelarBridgeAdaptor.sol index 8b2d2593..bd908640 100644 --- a/src/root/RootAxelarBridgeAdaptor.sol +++ b/src/root/RootAxelarBridgeAdaptor.sol @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache 2.0 pragma solidity 0.8.19; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {AxelarExecutable} from "@axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol"; import {IAxelarGasService} from "@axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol"; import {IRootERC20BridgeAdaptor} from "../interfaces/root/IRootERC20BridgeAdaptor.sol"; @@ -15,13 +16,14 @@ import {AdaptorRoles} from "../common/AdaptorRoles.sol"; /** * @notice Facilitates communication between the RootERC20Bridge and the Axelar Gateway. It enables sending and receiving messages to and from the child chain. + * @dev The contract ensures that any delivered message originated from the registered child chain and bridge adapter contract on the child chain. It will reject all other messages. * @dev Features: * - Send messages to the child chain via the Axelar Gateway. - * - Receive messages from the child chain via the Axelar Gateway. + * - Receive and validate messages from the child chain via the Axelar Gateway. * - Manage Role Based Access Control * @dev Roles: * - An account with a BRIDGE_MANAGER_ROLE can update the root bridge address. - * - An account with a TARGET_MANAGER_ROLE can update the child chain name. + * - An account with a TARGET_MANAGER_ROLE can update the child chain name and the child bridge adaptor address. * - An account with a GAS_SERVICE_MANAGER_ROLE can update the gas service address. * - An account with a DEFAULT_ADMIN_ROLE can grant and revoke roles. * @dev Note: @@ -36,46 +38,63 @@ contract RootAxelarBridgeAdaptor is IRootAxelarBridgeAdaptorErrors, IRootAxelarBridgeAdaptor { + /// @notice Address of the bridge contract on the root chain. IRootERC20Bridge public rootBridge; - string public childChain; + + /// @notice Axelar's ID for the child chain. Axelar uses the chain name as the chain ID. + /// @dev Messages that are sent to the chain that does not match this chain id, will be rejected. + string public childChainId; + + /// @notice Address of the bridge adaptor on the child chain, which this contract will communicate with. + /// @dev Messages that are sent to the child chain that did not originate from this address will be rejected. + string public childBridgeAdaptor; + + /// @notice Address of the Axelar Gas Service contract. IAxelarGasService public gasService; constructor(address _gateway) AxelarExecutable(_gateway) {} /** * @notice Initialization function for RootAxelarBridgeAdaptor. - * @param newRoles Struct containing addresses of roles. + * @param _newRoles Struct containing addresses of roles. * @param _rootBridge Address of root bridge contract. - * @param _childChain Name of child chain. + * @param _childChainId Axelar's ID for the child chain. + * @param _childBridgeAdaptor Address of the bridge adaptor on the child chain. * @param _gasService Address of Axelar Gas Service contract. */ function initialize( - InitializationRoles memory newRoles, + InitializationRoles memory _newRoles, address _rootBridge, - string memory _childChain, + string memory _childChainId, + string memory _childBridgeAdaptor, address _gasService ) public initializer { if ( - _rootBridge == address(0) || _gasService == address(0) || newRoles.defaultAdmin == address(0) - || newRoles.bridgeManager == address(0) || newRoles.gasServiceManager == address(0) - || newRoles.targetManager == address(0) + _rootBridge == address(0) || _gasService == address(0) || _newRoles.defaultAdmin == address(0) + || _newRoles.bridgeManager == address(0) || _newRoles.gasServiceManager == address(0) + || _newRoles.targetManager == address(0) ) { revert ZeroAddresses(); } - if (bytes(_childChain).length == 0) { + if (bytes(_childChainId).length == 0) { revert InvalidChildChain(); } + if (bytes(_childBridgeAdaptor).length == 0) { + revert InvalidChildERC20BridgeAdaptor(); + } + __AccessControl_init(); - _grantRole(DEFAULT_ADMIN_ROLE, newRoles.defaultAdmin); - _grantRole(BRIDGE_MANAGER_ROLE, newRoles.bridgeManager); - _grantRole(GAS_SERVICE_MANAGER_ROLE, newRoles.gasServiceManager); - _grantRole(TARGET_MANAGER_ROLE, newRoles.targetManager); + _grantRole(DEFAULT_ADMIN_ROLE, _newRoles.defaultAdmin); + _grantRole(BRIDGE_MANAGER_ROLE, _newRoles.bridgeManager); + _grantRole(GAS_SERVICE_MANAGER_ROLE, _newRoles.gasServiceManager); + _grantRole(TARGET_MANAGER_ROLE, _newRoles.targetManager); rootBridge = IRootERC20Bridge(_rootBridge); - childChain = _childChain; + childChainId = _childChainId; + childBridgeAdaptor = _childBridgeAdaptor; gasService = IAxelarGasService(_gasService); } @@ -99,8 +118,19 @@ contract RootAxelarBridgeAdaptor is revert InvalidChildChain(); } - emit ChildChainUpdated(childChain, newChildChain); - childChain = newChildChain; + emit ChildChainUpdated(childChainId, newChildChain); + childChainId = newChildChain; + } + + /** + * @inheritdoc IRootAxelarBridgeAdaptor + */ + function updateChildBridgeAdaptor(string memory newChildBridgeAdaptor) external onlyRole(TARGET_MANAGER_ROLE) { + if (bytes(newChildBridgeAdaptor).length == 0) { + revert InvalidChildERC20BridgeAdaptor(); + } + emit ChildBridgeAdaptorUpdated(childBridgeAdaptor, newChildBridgeAdaptor); + childBridgeAdaptor = newChildBridgeAdaptor; } /** @@ -127,8 +157,8 @@ contract RootAxelarBridgeAdaptor is } // Load from storage. - string memory _childBridgeAdaptor = IRootERC20Bridge(rootBridge).childBridgeAdaptor(); - string memory _childChain = childChain; + string memory _childBridgeAdaptor = childBridgeAdaptor; + string memory _childChain = childChainId; gasService.payNativeGasForContractCall{value: msg.value}( address(this), _childChain, _childBridgeAdaptor, payload, refundRecipient @@ -140,17 +170,25 @@ contract RootAxelarBridgeAdaptor is /** * @dev This function is called by the parent `AxelarExecutable` contract to execute the payload. - * @param sourceChain_ The chain id that the message originated from. - * @param sourceAddress_ The contract address that sent the message on the source chain. - * @param payload_ The message payload. - * @custom:assumes `sourceAddress_` is a 20 byte address. + * @param _sourceChain The chain id that the message originated from. + * @param _sourceAddress The contract address that sent the message on the source chain. + * @param _payload The message payload. + * @custom:assumes `_sourceAddress` is a 20 byte address. */ - function _execute(string calldata sourceChain_, string calldata sourceAddress_, bytes calldata payload_) + function _execute(string calldata _sourceChain, string calldata _sourceAddress, bytes calldata _payload) internal override { - emit AdaptorExecute(sourceChain_, sourceAddress_, payload_); - rootBridge.onMessageReceive(sourceChain_, sourceAddress_, payload_); + if (!Strings.equal(_sourceChain, childChainId)) { + revert InvalidSourceChain(); + } + + if (!Strings.equal(_sourceAddress, childBridgeAdaptor)) { + revert InvalidSourceAddress(); + } + + emit AdaptorExecute(_sourceChain, _sourceAddress, _payload); + rootBridge.onMessageReceive(_payload); } // slither-disable-next-line unused-state,naming-convention diff --git a/src/root/RootERC20Bridge.sol b/src/root/RootERC20Bridge.sol index f435d7c0..3ba84f0d 100644 --- a/src/root/RootERC20Bridge.sol +++ b/src/root/RootERC20Bridge.sol @@ -5,7 +5,6 @@ pragma solidity 0.8.19; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import {IAxelarGateway} from "@axelar-cgp-solidity/contracts/interfaces/IAxelarGateway.sol"; @@ -63,8 +62,6 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent address public constant NATIVE_IMX = address(0xfff); IRootERC20BridgeAdaptor public rootBridgeAdaptor; - /// @dev Used to verify source address in messages sent from child chain. - string public childBridgeAdaptor; /// @dev The address that will be minting tokens on the child chain. address public childERC20Bridge; /// @dev The address of the token template that will be cloned to create tokens on the child chain. @@ -75,8 +72,6 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent address public childETHToken; /// @dev The address of the wETH ERC20 token on L1. address public rootWETHToken; - /// @dev The name of the chain that this bridge is connected to. - string public childChain; /// @dev The maximum cumulative amount of IMX that can be deposited into the bridge. /// @dev A limit of zero indicates unlimited. uint256 public imxCumulativeDepositLimit; @@ -84,13 +79,11 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent /** * @notice Initialization function for RootERC20Bridge. * @param newRoles Struct containing addresses of roles. - * @param newRootBridgeAdaptor Address of StateSender to send bridge messages to, and receive messages from. + * @param newRootBridgeAdaptor Address of adaptor to send bridge messages to, and receive messages from. * @param newChildERC20Bridge Address of child ERC20 bridge to communicate with. - * @param newChildBridgeAdaptor Address of child bridge adaptor to communicate with (As a checksummed string). * @param newChildTokenTemplate Address of child token template to clone. * @param newRootIMXToken Address of ERC20 IMX on the root chain. * @param newRootWETHToken Address of ERC20 WETH on the root chain. - * @param newChildChain Name of child chain. * @param newImxCumulativeDepositLimit The cumulative IMX deposit limit. * @dev Can only be called once. */ @@ -98,22 +91,18 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent InitializationRoles memory newRoles, address newRootBridgeAdaptor, address newChildERC20Bridge, - string memory newChildBridgeAdaptor, address newChildTokenTemplate, address newRootIMXToken, address newRootWETHToken, - string memory newChildChain, uint256 newImxCumulativeDepositLimit ) external virtual initializer { __RootERC20Bridge_init( newRoles, newRootBridgeAdaptor, newChildERC20Bridge, - newChildBridgeAdaptor, newChildTokenTemplate, newRootIMXToken, newRootWETHToken, - newChildChain, newImxCumulativeDepositLimit ); } @@ -123,22 +112,18 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent * @param newRoles Struct containing addresses of roles. * @param newRootBridgeAdaptor Address of StateSender to send bridge messages to, and receive messages from. * @param newChildERC20Bridge Address of child ERC20 bridge to communicate with. - * @param newChildBridgeAdaptor Address of child bridge adaptor to communicate with (As a checksummed string). * @param newChildTokenTemplate Address of child token template to clone. * @param newRootIMXToken Address of ERC20 IMX on the root chain. * @param newRootWETHToken Address of ERC20 WETH on the root chain. - * @param newChildChain Name of child chain. * @param newImxCumulativeDepositLimit The cumulative IMX deposit limit. */ function __RootERC20Bridge_init( InitializationRoles memory newRoles, address newRootBridgeAdaptor, address newChildERC20Bridge, - string memory newChildBridgeAdaptor, address newChildTokenTemplate, address newRootIMXToken, address newRootWETHToken, - string memory newChildChain, uint256 newImxCumulativeDepositLimit ) internal { if ( @@ -149,12 +134,6 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent ) { revert ZeroAddress(); } - if (bytes(newChildBridgeAdaptor).length == 0) { - revert InvalidChildERC20BridgeAdaptor(); - } - if (bytes(newChildChain).length == 0) { - revert InvalidChildChain(); - } __AccessControl_init(); __Pausable_init(); @@ -173,8 +152,6 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent childTokenTemplate, keccak256(abi.encodePacked(NATIVE_ETH)), childERC20Bridge ); rootBridgeAdaptor = IRootERC20BridgeAdaptor(newRootBridgeAdaptor); - childBridgeAdaptor = newChildBridgeAdaptor; - childChain = newChildChain; imxCumulativeDepositLimit = newImxCumulativeDepositLimit; } @@ -203,17 +180,6 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent rootBridgeAdaptor = IRootERC20BridgeAdaptor(newRootBridgeAdaptor); } - /** - * @inheritdoc IRootERC20Bridge - */ - function updateChildBridgeAdaptor(string memory newChildBridgeAdaptor) external onlyRole(ADAPTOR_MANAGER_ROLE) { - if (bytes(newChildBridgeAdaptor).length == 0) { - revert InvalidChildERC20BridgeAdaptor(); - } - emit ChildBridgeAdaptorUpdated(childBridgeAdaptor, newChildBridgeAdaptor); - childBridgeAdaptor = newChildBridgeAdaptor; - } - /** * @notice Updates the IMX deposit limit. * @param newImxCumulativeDepositLimit The new cumulative IMX deposit limit. @@ -251,22 +217,12 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent /** * @inheritdoc IRootERC20Bridge * @dev This is only callable by the root chain bridge adaptor. - * @dev Validates `sourceAddress` is the child chain's bridgeAdaptor. */ - function onMessageReceive(string calldata messageSourceChain, string calldata sourceAddress, bytes calldata data) - external - override - whenNotPaused - { + function onMessageReceive(bytes calldata data) external override whenNotPaused { if (msg.sender != address(rootBridgeAdaptor)) { revert NotBridgeAdaptor(); } - if (!Strings.equal(messageSourceChain, childChain)) { - revert InvalidSourceChain(); - } - if (!Strings.equal(sourceAddress, childBridgeAdaptor)) { - revert InvalidSourceAddress(); - } + if (data.length <= 32) { // Data must always be greater than 32. // 32 bytes for the signature, and at least some information for the payload diff --git a/src/root/flowrate/RootERC20BridgeFlowRate.sol b/src/root/flowrate/RootERC20BridgeFlowRate.sol index 584609ed..ce1f6147 100644 --- a/src/root/flowrate/RootERC20BridgeFlowRate.sol +++ b/src/root/flowrate/RootERC20BridgeFlowRate.sol @@ -86,11 +86,9 @@ contract RootERC20BridgeFlowRate is InitializationRoles memory newRoles, address newRootBridgeAdaptor, address newChildERC20Bridge, - string memory newChildBridgeAdaptor, address newChildTokenTemplate, address newRootIMXToken, address newRootWETHToken, - string memory newChildChain, uint256 newImxCumulativeDepositLimit, address rateAdmin ) external initializer { @@ -102,11 +100,9 @@ contract RootERC20BridgeFlowRate is newRoles, newRootBridgeAdaptor, newChildERC20Bridge, - newChildBridgeAdaptor, newChildTokenTemplate, newRootIMXToken, newRootWETHToken, - newChildChain, newImxCumulativeDepositLimit ); @@ -116,17 +112,11 @@ contract RootERC20BridgeFlowRate is } // Ensure initialize from RootERC20Bridge can not be called. - function initialize( - InitializationRoles memory, - address, - address, - string memory, - address, - address, - address, - string memory, - uint256 - ) external pure override { + function initialize(InitializationRoles memory, address, address, address, address, address, uint256) + external + pure + override + { revert WrongInitializer(); } diff --git a/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol b/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol index 2da6803a..735e0a20 100644 --- a/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol +++ b/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol @@ -85,7 +85,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, address(token), address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectRevert(InvalidSourceChain.selector); axelarAdaptor.execute(commandId, "INVALID", sourceAddress, data); @@ -105,7 +105,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data; bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectRevert(abi.encodeWithSelector(InvalidData.selector, "Data too short")); axelarAdaptor.execute(commandId, CHILD_CHAIN_NAME, sourceAddress, data); @@ -115,7 +115,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode("INVALID_SIG", address(token), address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectRevert(abi.encodeWithSelector(InvalidData.selector, "Unsupported action signature")); axelarAdaptor.execute(commandId, CHILD_CHAIN_NAME, sourceAddress, data); @@ -125,7 +125,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, address(token), address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); uint256 thisPreBal = token.balanceOf(address(this)); uint256 bridgePreBal = token.balanceOf(address(rootBridgeFlowRate)); @@ -143,7 +143,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, IMX_TOKEN_ADDRESS, address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); uint256 thisPreBal = imxToken.balanceOf(address(this)); uint256 bridgePreBal = imxToken.balanceOf(address(rootBridgeFlowRate)); @@ -161,7 +161,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); uint256 thisPreBal = address(this).balance; uint256 bridgePreBal = address(rootBridgeFlowRate).balance; @@ -180,7 +180,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, address(token), address(this), receiver, withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); uint256 receiverPreBal = token.balanceOf(receiver); uint256 bridgePreBal = token.balanceOf(address(rootBridgeFlowRate)); @@ -199,7 +199,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, IMX_TOKEN_ADDRESS, address(this), receiver, withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); uint256 receiverPreBal = imxToken.balanceOf(receiver); uint256 bridgePreBal = imxToken.balanceOf(address(rootBridgeFlowRate)); @@ -218,7 +218,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), receiver, withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); uint256 receiverPreBal = address(receiver).balance; uint256 bridgePreBal = address(rootBridgeFlowRate).balance; @@ -236,7 +236,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, address(token), address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectEmit(); emit RootChainERC20Withdraw( @@ -253,7 +253,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, IMX_TOKEN_ADDRESS, address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectEmit(); emit RootChainERC20Withdraw(address(imxToken), NATIVE_IMX, address(this), address(this), withdrawAmount); @@ -264,7 +264,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), address(this), withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectEmit(); emit RootChainETHWithdraw( @@ -278,7 +278,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, address(token), address(this), receiver, withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectEmit(); emit RootChainERC20Withdraw( @@ -296,7 +296,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, IMX_TOKEN_ADDRESS, address(this), receiver, withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectEmit(); emit RootChainERC20Withdraw(address(imxToken), NATIVE_IMX, address(this), receiver, withdrawAmount); @@ -308,7 +308,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes memory data = abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), receiver, withdrawAmount); bytes32 commandId = bytes32("testCommandId"); - string memory sourceAddress = rootBridgeFlowRate.childBridgeAdaptor(); + string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); vm.expectEmit(); emit RootChainETHWithdraw( diff --git a/test/mocks/root/StubRootBridge.sol b/test/mocks/root/StubRootBridge.sol index 1928841c..657148a5 100644 --- a/test/mocks/root/StubRootBridge.sol +++ b/test/mocks/root/StubRootBridge.sol @@ -8,5 +8,5 @@ contract StubRootBridge { return Strings.toHexString(address(9999)); } - function onMessageReceive(string calldata, string calldata, bytes calldata) external {} + function onMessageReceive(bytes calldata) external {} } diff --git a/test/unit/common/AdaptorRoles.t.sol b/test/unit/common/AdaptorRoles.t.sol index 5cc11985..30760944 100644 --- a/test/unit/common/AdaptorRoles.t.sol +++ b/test/unit/common/AdaptorRoles.t.sol @@ -31,7 +31,7 @@ contract AdaptorRoles is Setup { vm.startPrank(admin); mockAdaptorRoles.revokeBridgeManagerRole(bridgeManager); mockAdaptorRoles.revokeGasServiceManagerRole(gasServiceManager); - mockAdaptorRoles.revokeTargetMangaerRole(targetManager); + mockAdaptorRoles.revokeTargetManagerRole(targetManager); vm.stopPrank(); } diff --git a/test/unit/root/RootAxelarBridgeAdaptor.t.sol b/test/unit/root/RootAxelarBridgeAdaptor.t.sol index 55a0d6c8..62a9fca8 100644 --- a/test/unit/root/RootAxelarBridgeAdaptor.t.sol +++ b/test/unit/root/RootAxelarBridgeAdaptor.t.sol @@ -18,8 +18,9 @@ import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IRootAxelarBridgeAdaptorErrors { address constant CHILD_BRIDGE = address(3); - string public childBridgeAdaptor; string constant CHILD_CHAIN_NAME = "test"; + address constant CHILD_BRIDGE_ADAPTOR = address(4); + string CHILD_BRIDGE_ADAPTOR_STRING = Strings.toHexString(CHILD_BRIDGE_ADAPTOR); bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN"); ERC20PresetMinterPauser public token; @@ -43,11 +44,11 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR token = new ERC20PresetMinterPauser("Test", "TST"); mockAxelarGateway = new MockAxelarGateway(); axelarGasService = new MockAxelarGasService(); - stubRootBridge = new StubRootBridge(); - childBridgeAdaptor = stubRootBridge.childBridgeAdaptor(); - axelarAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); - axelarAdaptor.initialize(roles, address(stubRootBridge), CHILD_CHAIN_NAME, address(axelarGasService)); + stubRootBridge = new StubRootBridge(); + axelarAdaptor.initialize( + roles, address(stubRootBridge), CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, address(axelarGasService) + ); vm.deal(address(stubRootBridge), 99999999999); } @@ -57,7 +58,8 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR function test_Initialize() public { assertEq(address(axelarAdaptor.rootBridge()), address(stubRootBridge), "rootBridge not set"); - assertEq(axelarAdaptor.childChain(), CHILD_CHAIN_NAME, "childChain not set"); + assertEq(axelarAdaptor.childChainId(), CHILD_CHAIN_NAME, "childChain not set"); + assertEq(axelarAdaptor.childBridgeAdaptor(), CHILD_BRIDGE_ADAPTOR_STRING, "childBridgeAdaptor not set"); assertEq(address(axelarAdaptor.gateway()), address(mockAxelarGateway), "axelarGateway not set"); assertEq(address(axelarAdaptor.gasService()), address(axelarGasService), "axelarGasService not set"); assertEq(axelarAdaptor.hasRole(axelarAdaptor.DEFAULT_ADMIN_ROLE(), address(this)), true, "defaultAdmin not set"); @@ -78,70 +80,96 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); vm.expectRevert(ZeroAddresses.selector); roles.defaultAdmin = address(0); - newAdaptor.initialize(roles, address(this), CHILD_CHAIN_NAME, address(axelarGasService)); + newAdaptor.initialize( + roles, address(this), CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, address(axelarGasService) + ); } function test_RevertIf_InitializeWithZeroBridgeManager() public { RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); vm.expectRevert(ZeroAddresses.selector); roles.bridgeManager = address(0); - newAdaptor.initialize(roles, address(this), CHILD_CHAIN_NAME, address(axelarGasService)); + newAdaptor.initialize( + roles, address(this), CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, address(axelarGasService) + ); } function test_RevertIf_InitializeWithZeroGasServiceManager() public { RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); vm.expectRevert(ZeroAddresses.selector); roles.gasServiceManager = address(0); - newAdaptor.initialize(roles, address(this), CHILD_CHAIN_NAME, address(axelarGasService)); + newAdaptor.initialize( + roles, address(this), CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, address(axelarGasService) + ); } function test_RevertIf_InitializeWithZeroTargetManager() public { RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); vm.expectRevert(ZeroAddresses.selector); roles.targetManager = address(0); - newAdaptor.initialize(roles, address(this), CHILD_CHAIN_NAME, address(axelarGasService)); + newAdaptor.initialize( + roles, address(this), CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, address(axelarGasService) + ); } function test_RevertIf_InitializeGivenZeroAddress() public { RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); vm.expectRevert(ZeroAddresses.selector); - newAdaptor.initialize(roles, address(0), CHILD_CHAIN_NAME, address(axelarGasService)); + newAdaptor.initialize( + roles, address(0), CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, address(axelarGasService) + ); } function test_RevertIf_InitializeGivenEmptyChildChainName() public { RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); vm.expectRevert(InvalidChildChain.selector); - newAdaptor.initialize(roles, address(this), "", address(axelarGasService)); + newAdaptor.initialize(roles, address(this), "", CHILD_BRIDGE_ADAPTOR_STRING, address(axelarGasService)); } + function test_RevertIf_InitializeGivenEmptyChildAdapter() public { + RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); + vm.expectRevert(InvalidChildERC20BridgeAdaptor.selector); + newAdaptor.initialize(roles, address(this), CHILD_CHAIN_NAME, "", address(axelarGasService)); + } /** * EXECUTE */ + function test_RevertIf_executeCalledWithInvalidSourceChain() public { + bytes32 commandId = bytes32("testCommandId"); + bytes memory payload = abi.encodePacked("payload"); + + vm.expectRevert(InvalidSourceChain.selector); + axelarAdaptor.execute(commandId, "Invalid-Source-Chain", CHILD_BRIDGE_ADAPTOR_STRING, payload); + } + + function test_RevertIf_executeCalledWithInvalidSourceAddress() public { + bytes32 commandId = bytes32("testCommandId"); + bytes memory payload = abi.encodePacked("payload"); + + vm.expectRevert(InvalidSourceAddress.selector); + axelarAdaptor.execute(commandId, CHILD_CHAIN_NAME, "invalid-source-address", payload); + } + function test_Execute_CallsBridge() public { bytes32 commandId = bytes32("testCommandId"); - string memory sourceChain = "test"; - string memory sourceAddress = Strings.toHexString(address(123)); bytes memory payload = abi.encodePacked("payload"); // We expect to call the bridge's onMessageReceive function. vm.expectCall( - address(stubRootBridge), - abi.encodeWithSelector(stubRootBridge.onMessageReceive.selector, sourceChain, sourceAddress, payload) + address(stubRootBridge), abi.encodeWithSelector(stubRootBridge.onMessageReceive.selector, payload) ); - axelarAdaptor.execute(commandId, sourceChain, sourceAddress, payload); + axelarAdaptor.execute(commandId, CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, payload); } function test_Execute_EmitsAdaptorExecuteEvent() public { bytes32 commandId = bytes32("testCommandId"); - string memory sourceChain = "test"; - string memory sourceAddress = Strings.toHexString(address(123)); bytes memory payload = abi.encodePacked("payload"); // We expect to call the bridge's onMessageReceive function. vm.expectEmit(); - emit AdaptorExecute(sourceChain, sourceAddress, payload); - axelarAdaptor.execute(commandId, sourceChain, sourceAddress, payload); + emit AdaptorExecute(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, payload); + axelarAdaptor.execute(commandId, CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, payload); } /** @@ -161,7 +189,7 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR axelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), CHILD_CHAIN_NAME, - childBridgeAdaptor, + CHILD_BRIDGE_ADAPTOR_STRING, payload, refundRecipient ) @@ -178,7 +206,7 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR vm.expectCall( address(mockAxelarGateway), abi.encodeWithSelector( - mockAxelarGateway.callContract.selector, CHILD_CHAIN_NAME, childBridgeAdaptor, payload + mockAxelarGateway.callContract.selector, CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, payload ) ); @@ -191,7 +219,7 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR uint256 callValue = 300; vm.expectEmit(true, true, true, false, address(axelarAdaptor)); - emit AxelarMessageSent(CHILD_CHAIN_NAME, childBridgeAdaptor, payload); + emit AxelarMessageSent(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, payload); vm.prank(address(stubRootBridge)); axelarAdaptor.sendMessage{value: callValue}(payload, address(123)); } @@ -226,7 +254,7 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR axelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), CHILD_CHAIN_NAME, - childBridgeAdaptor, + CHILD_BRIDGE_ADAPTOR_STRING, payload, refundRecipient ) @@ -307,7 +335,7 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR vm.startPrank(targetManager); string memory newChildChain = "newChildChain"; axelarAdaptor.updateChildChain(newChildChain); - assertEq(axelarAdaptor.childChain(), newChildChain, "childChain not updated"); + assertEq(axelarAdaptor.childChainId(), newChildChain, "childChain not updated"); vm.stopPrank(); } @@ -339,6 +367,50 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR axelarAdaptor.updateChildChain(""); } + /** + * UPDATE CHILD BRIDGE ADAPTOR + */ + + function test_updateChildBridgeAdaptor_UpdatesChildBridgeAdaptor() public { + vm.startPrank(targetManager); + + string memory newAdaptorAddress = Strings.toHexString(address(0x11111)); + assertEq(axelarAdaptor.childBridgeAdaptor(), CHILD_BRIDGE_ADAPTOR_STRING, "bridgeAdaptor not set"); + axelarAdaptor.updateChildBridgeAdaptor(newAdaptorAddress); + assertEq(axelarAdaptor.childBridgeAdaptor(), newAdaptorAddress, "bridgeAdaptor not updated"); + } + + function test_updateChildBridgeAdaptor_EmitsEvent() public { + vm.startPrank(targetManager); + + string memory newAdaptorAddress = Strings.toHexString(address(0x11111)); + vm.expectEmit(true, true, false, false, address(axelarAdaptor)); + emit ChildBridgeAdaptorUpdated(axelarAdaptor.childBridgeAdaptor(), newAdaptorAddress); + + axelarAdaptor.updateChildBridgeAdaptor(newAdaptorAddress); + } + + function test_RevertsIf_updateChildBridgeAdaptorCalledByNonTargetManager() public { + address caller = address(0xf00f00); + vm.startPrank(caller); + bytes32 role = axelarAdaptor.TARGET_MANAGER_ROLE(); + vm.expectRevert( + abi.encodePacked( + "AccessControl: account ", + StringsUpgradeable.toHexString(caller), + " is missing role ", + StringsUpgradeable.toHexString(uint256(role), 32) + ) + ); + axelarAdaptor.updateChildBridgeAdaptor(Strings.toHexString(address(0x11111))); + } + + function test_RevertsIf_updateChildBridgeAdaptorCalledWithEmptyString() public { + vm.startPrank(targetManager); + vm.expectRevert(InvalidChildERC20BridgeAdaptor.selector); + axelarAdaptor.updateChildBridgeAdaptor(""); + } + /** * UPDATE GAS SERVICE */ diff --git a/test/unit/root/RootERC20Bridge.t.sol b/test/unit/root/RootERC20Bridge.t.sol index 2d8c3ae4..8bdac874 100644 --- a/test/unit/root/RootERC20Bridge.t.sol +++ b/test/unit/root/RootERC20Bridge.t.sol @@ -19,11 +19,7 @@ import {MockAdaptor} from "../../mocks/root/MockAdaptor.sol"; import {Utils, IPausable} from "../../utils.t.sol"; contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20BridgeErrors, Utils { - bytes32 constant ADAPTOR_MANAGER_ROLE = keccak256("ADAPTOR_MANAGER_ROLE"); address constant CHILD_BRIDGE = address(3); - address constant CHILD_BRIDGE_ADAPTOR = address(4); - string CHILD_BRIDGE_ADAPTOR_STRING = Strings.toHexString(CHILD_BRIDGE_ADAPTOR); - string constant CHILD_CHAIN_NAME = "test"; address constant IMX_TOKEN = address(0xccc); address constant NATIVE_ETH = address(0xeee); address constant WRAPPED_ETH = address(0xddd); @@ -62,11 +58,9 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid roles, address(mockAxelarAdaptor), CHILD_BRIDGE, - CHILD_BRIDGE_ADAPTOR_STRING, address(token), IMX_TOKEN, WRAPPED_ETH, - CHILD_CHAIN_NAME, UNLIMITED_IMX_DEPOSITS ); } @@ -79,8 +73,6 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid assertEq(address(rootBridge.rootBridgeAdaptor()), address(mockAxelarAdaptor), "bridgeAdaptor not set"); assertEq(rootBridge.childERC20Bridge(), CHILD_BRIDGE, "childERC20Bridge not set"); assertEq(rootBridge.childTokenTemplate(), address(token), "childTokenTemplate not set"); - assert(Strings.equal(rootBridge.childChain(), CHILD_CHAIN_NAME)); - assert(Strings.equal(CHILD_BRIDGE_ADAPTOR_STRING, rootBridge.childBridgeAdaptor())); assertEq(address(token), rootBridge.childTokenTemplate(), "childTokenTemplate not set"); assertEq(rootBridge.rootIMXToken(), IMX_TOKEN, "rootIMXToken not set"); assertEq(rootBridge.rootWETHToken(), WRAPPED_ETH, "rootWETHToken not set"); @@ -90,7 +82,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid address caller = address(0x123a); payable(caller).transfer(2 ether); // forge inspect src/root/RootERC20Bridge.sol:RootERC20Bridge storageLayout | grep -B3 -A5 -i "rootWETHToken" - uint256 wETHStorageSlot = 258; + uint256 wETHStorageSlot = 257; vm.store(address(rootBridge), bytes32(wETHStorageSlot), bytes32(uint256(uint160(caller)))); vm.startPrank(caller); @@ -136,11 +128,9 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid roles, address(mockAxelarAdaptor), CHILD_BRIDGE, - CHILD_BRIDGE_ADAPTOR_STRING, address(token), IMX_TOKEN, WRAPPED_ETH, - CHILD_CHAIN_NAME, UNLIMITED_IMX_DEPOSITS ); } @@ -156,17 +146,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(1), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressPauser() public { @@ -180,17 +160,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(1), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressUnpauser() public { @@ -203,17 +173,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid adaptorManager: address(this) }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(1), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressVariableManager() public { @@ -226,17 +186,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid adaptorManager: address(this) }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(1), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressAdaptorManager() public { @@ -249,17 +199,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid adaptorManager: address(0) }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(1), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressRootAdapter() public { @@ -272,17 +212,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid adaptorManager: address(this) }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(0), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(0), address(1), address(1), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressChildBridge() public { @@ -295,40 +225,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid adaptorManager: address(this) }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(0), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); - } - - function test_RevertIf_InitializeWithEmptyChildAdapter() public { - RootERC20Bridge bridge = new RootERC20Bridge(); - IRootERC20Bridge.InitializationRoles memory roles = IRootERC20Bridge.InitializationRoles({ - defaultAdmin: address(this), - pauser: address(this), - unpauser: address(this), - variableManager: address(this), - adaptorManager: address(this) - }); - vm.expectRevert(InvalidChildERC20BridgeAdaptor.selector); - bridge.initialize( - roles, - address(1), - address(1), - "", - address(1), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(0), address(1), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressTokenTemplate() public { @@ -341,17 +238,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid adaptorManager: address(this) }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(0), - address(1), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(0), address(1), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressIMXToken() public { @@ -364,17 +251,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid adaptorManager: address(this) }); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(0), - address(1), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(1), address(0), address(1), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressWETHToken() public { @@ -387,17 +264,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid }); RootERC20Bridge bridge = new RootERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(0), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(1), address(1), address(1), address(1), address(0), UNLIMITED_IMX_DEPOSITS); } function test_RevertIf_InitializeWithAZeroAddressAll() public { @@ -410,40 +277,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid }); RootERC20Bridge bridge = new RootERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize( - roles, - address(0), - address(0), - "", - address(0), - address(0), - address(0), - CHILD_CHAIN_NAME, - UNLIMITED_IMX_DEPOSITS - ); - } - - function test_RevertIf_InitializeWithEmptyChildName() public { - RootERC20Bridge bridge = new RootERC20Bridge(); - IRootERC20Bridge.InitializationRoles memory roles = IRootERC20Bridge.InitializationRoles({ - defaultAdmin: address(this), - pauser: address(this), - unpauser: address(this), - variableManager: address(this), - adaptorManager: address(this) - }); - vm.expectRevert(InvalidChildChain.selector); - bridge.initialize( - roles, - address(1), - address(1), - CHILD_BRIDGE_ADAPTOR_STRING, - address(1), - address(1), - address(1), - "", - UNLIMITED_IMX_DEPOSITS - ); + bridge.initialize(roles, address(0), address(0), address(0), address(0), address(0), UNLIMITED_IMX_DEPOSITS); } /** @@ -453,7 +287,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid pause(IPausable(address(rootBridge))); bytes memory data = abi.encode(WITHDRAW_SIG, token, address(this), address(this), 1000); vm.expectRevert("Pausable: paused"); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_OnMessageReceiveResumesFunctionalityAfterUnpausing() public { @@ -462,7 +296,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid // Expect revert on standard flow, not on pause vm.expectRevert(NotBridgeAdaptor.selector); bytes memory data = abi.encode(WITHDRAW_SIG, token, address(this), address(this), 1000); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } /** @@ -625,43 +459,6 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid rootBridge.updateRootBridgeAdaptor(address(0)); } - function test_updateChildBridgeAdaptor_UpdatesChildBridgeAdaptor() public { - string memory newAdaptorAddress = Strings.toHexString(address(0x11111)); - - assertEq(rootBridge.childBridgeAdaptor(), CHILD_BRIDGE_ADAPTOR_STRING, "bridgeAdaptor not set"); - rootBridge.updateChildBridgeAdaptor(newAdaptorAddress); - assertEq(rootBridge.childBridgeAdaptor(), newAdaptorAddress, "bridgeAdaptor not updated"); - } - - function test_updateChildBridgeAdaptor_EmitsEvent() public { - string memory newAdaptorAddress = Strings.toHexString(address(0x11111)); - - vm.expectEmit(true, true, false, false, address(rootBridge)); - emit ChildBridgeAdaptorUpdated(rootBridge.childBridgeAdaptor(), newAdaptorAddress); - - rootBridge.updateChildBridgeAdaptor(newAdaptorAddress); - } - - function test_RevertsIf_updateChildBridgeAdaptorCalledByNonAdaptorManager() public { - address caller = address(0xf00f00); - bytes32 role = rootBridge.ADAPTOR_MANAGER_ROLE(); - vm.prank(caller); - vm.expectRevert( - abi.encodePacked( - "AccessControl: account ", - StringsUpgradeable.toHexString(caller), - " is missing role ", - StringsUpgradeable.toHexString(uint256(role), 32) - ) - ); - rootBridge.updateChildBridgeAdaptor(Strings.toHexString(address(0x11111))); - } - - function test_RevertsIf_updatreChildBridgeAdaptorCalledWithEmptyString() public { - vm.expectRevert(InvalidChildERC20BridgeAdaptor.selector); - rootBridge.updateChildBridgeAdaptor(""); - } - /** * DEPOSIT ETH */ diff --git a/test/unit/root/flowrate/RootERC20BridgeFlowRate.t.sol b/test/unit/root/flowrate/RootERC20BridgeFlowRate.t.sol index 0a8327c6..9f76f984 100644 --- a/test/unit/root/flowrate/RootERC20BridgeFlowRate.t.sol +++ b/test/unit/root/flowrate/RootERC20BridgeFlowRate.t.sol @@ -75,9 +75,6 @@ contract RootERC20BridgeFlowRateUnitTest is Utils { address constant CHILD_BRIDGE = address(3); - address constant CHILD_BRIDGE_ADAPTOR = address(4); - string CHILD_BRIDGE_ADAPTOR_STRING = Strings.toHexString(CHILD_BRIDGE_ADAPTOR); - string constant CHILD_CHAIN_NAME = "test"; address constant IMX_TOKEN = address(0xccc); address constant NATIVE_ETH = address(0xeee); address constant WRAPPED_ETH = address(0xddd); @@ -158,11 +155,9 @@ contract RootERC20BridgeFlowRateUnitTest is roles, address(mockAxelarAdaptor), CHILD_BRIDGE, - CHILD_BRIDGE_ADAPTOR_STRING, address(token), IMX_TOKEN, WRAPPED_ETH, - CHILD_CHAIN_NAME, UNLIMITED_IMX_DEPOSITS, rateAdmin ); @@ -213,8 +208,6 @@ contract RootERC20BridgeFlowRateUnitTest is assertEq(address(rootBridgeFlowRate.rootBridgeAdaptor()), address(mockAxelarAdaptor), "bridgeAdaptor not set"); assertEq(rootBridgeFlowRate.childERC20Bridge(), CHILD_BRIDGE, "childERC20Bridge not set"); assertEq(rootBridgeFlowRate.childTokenTemplate(), address(token), "childTokenTemplate not set"); - assert(Strings.equal(rootBridgeFlowRate.childChain(), CHILD_CHAIN_NAME)); - assert(Strings.equal(CHILD_BRIDGE_ADAPTOR_STRING, rootBridgeFlowRate.childBridgeAdaptor())); assertEq(address(token), rootBridgeFlowRate.childTokenTemplate(), "childTokenTemplate not set"); assertEq(rootBridgeFlowRate.rootIMXToken(), IMX_TOKEN, "rootIMXToken not set"); assertEq(rootBridgeFlowRate.rootWETHToken(), WRAPPED_ETH, "rootWETHToken not set"); @@ -234,11 +227,9 @@ contract RootERC20BridgeFlowRateUnitTest is roles, address(mockAxelarAdaptor), CHILD_BRIDGE, - CHILD_BRIDGE_ADAPTOR_STRING, address(token), IMX_TOKEN, WRAPPED_ETH, - CHILD_CHAIN_NAME, UNLIMITED_IMX_DEPOSITS, address(this) ); @@ -258,11 +249,9 @@ contract RootERC20BridgeFlowRateUnitTest is roles, address(mockAxelarAdaptor), CHILD_BRIDGE, - CHILD_BRIDGE_ADAPTOR_STRING, address(token), IMX_TOKEN, WRAPPED_ETH, - CHILD_CHAIN_NAME, UNLIMITED_IMX_DEPOSITS ); } @@ -281,11 +270,9 @@ contract RootERC20BridgeFlowRateUnitTest is roles, address(mockAxelarAdaptor), CHILD_BRIDGE, - CHILD_BRIDGE_ADAPTOR_STRING, address(token), IMX_TOKEN, WRAPPED_ETH, - CHILD_CHAIN_NAME, UNLIMITED_IMX_DEPOSITS, address(0) ); @@ -458,7 +445,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectRevert("Pausable: paused"); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); } function testFinaliseQueuedWithdrawalWhenPaused() public { @@ -476,7 +463,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true); emit EnQueuedWithdrawal(address(token), alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); pause(); @@ -501,7 +488,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true); emit EnQueuedWithdrawal(address(token), alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); pause(); @@ -532,7 +519,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit QueuedWithdrawal(address(token), alice, bob, amount, false, true, false); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); //assertEq(token.balanceOf(address(charlie)), CHARLIE_REMAINDER, "charlie"); assertEq(token.balanceOf(address(alice)), 0, "alice"); @@ -565,7 +552,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit QueuedWithdrawal(address(token), alice, bob, amount, true, false, false); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); assertEq(token.balanceOf(address(alice)), 0, "alice"); assertEq(token.balanceOf(address(bob)), 0, "bob"); @@ -598,7 +585,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit RootChainERC20Withdraw(address(token), childERC20Token, alice, bob, amount); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); assertFalse(rootBridgeFlowRate.withdrawalQueueActivated(), "queue activated!"); total += amount; assertEq(token.balanceOf(address(bob)), total, "bob"); @@ -608,7 +595,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit QueuedWithdrawal(address(token), alice, bob, amount, false, false, true); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); assertTrue(rootBridgeFlowRate.withdrawalQueueActivated(), "queue not activated!"); assertEq(token.balanceOf(address(bob)), total, "bob"); } @@ -632,7 +619,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(token), alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); assertEq(queueLen, 1, "bob's queue length"); @@ -672,7 +659,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(NATIVE_ETH, alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); assertEq(queueLen, 1, "bob's queue length"); @@ -708,7 +695,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(token), alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); assertEq(queueLen, 1, "bob's queue length"); @@ -749,7 +736,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(token), alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); assertEq(queueLen, 1, "bob's queue length"); @@ -786,7 +773,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(token), alice, bob, amount, now1, i); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); } uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); @@ -817,7 +804,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(NATIVE_ETH), alice, bob, amount, now1, i); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); } uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); @@ -972,7 +959,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(NATIVE_ETH), alice, bob, amount, block.timestamp, 10); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); // Indices for a withdrawal for the ERC 20 token and one for Ether uint256[] memory indices = new uint256[](2); @@ -1020,7 +1007,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(attackToken), alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); assertEq(queueLen, 1, "bob's queue length"); @@ -1058,7 +1045,7 @@ contract RootERC20BridgeFlowRateUnitTest is vm.prank(address(mockAxelarAdaptor)); vm.expectEmit(true, true, true, true, address(rootBridgeFlowRate)); emit EnQueuedWithdrawal(address(attackToken), alice, bob, amount, now1, 0); - rootBridgeFlowRate.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridgeFlowRate.onMessageReceive(data); uint256 queueLen = rootBridgeFlowRate.getPendingWithdrawalsLength(bob); assertEq(queueLen, 1, "bob's queue length"); diff --git a/test/unit/root/withdrawals/RootAxelarBridgeAdaptorWithdraw.t.sol b/test/unit/root/withdrawals/RootAxelarBridgeAdaptorWithdraw.t.sol deleted file mode 100644 index 9216aed0..00000000 --- a/test/unit/root/withdrawals/RootAxelarBridgeAdaptorWithdraw.t.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: Apache 2.0 -pragma solidity 0.8.19; - -import {Test, console2} from "forge-std/Test.sol"; -import {ERC20PresetMinterPauser} from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; -import {MockAxelarGateway} from "../../../mocks/root/MockAxelarGateway.sol"; -import {MockAxelarGasService} from "../../../mocks/root/MockAxelarGasService.sol"; -import { - RootAxelarBridgeAdaptor, - IRootAxelarBridgeAdaptorEvents, - IRootAxelarBridgeAdaptorErrors, - IRootAxelarBridgeAdaptor -} from "../../../../src/root/RootAxelarBridgeAdaptor.sol"; -import {StubRootBridge} from "../../../mocks/root/StubRootBridge.sol"; - -contract RootAxelarBridgeWithdrawAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IRootAxelarBridgeAdaptorErrors { - address constant CHILD_BRIDGE = address(3); - string public childBridgeAdaptor; - string constant CHILD_CHAIN_NAME = "test"; - bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN"); - - ERC20PresetMinterPauser public token; - RootAxelarBridgeAdaptor public axelarAdaptor; - MockAxelarGateway public mockAxelarGateway; - MockAxelarGasService public axelarGasService; - StubRootBridge public stubRootBridge; - - IRootAxelarBridgeAdaptor.InitializationRoles public roles = IRootAxelarBridgeAdaptor.InitializationRoles({ - defaultAdmin: address(this), - bridgeManager: address(this), - gasServiceManager: address(this), - targetManager: address(this) - }); - - function setUp() public { - token = new ERC20PresetMinterPauser("Test", "TST"); - mockAxelarGateway = new MockAxelarGateway(); - axelarGasService = new MockAxelarGasService(); - stubRootBridge = new StubRootBridge(); - childBridgeAdaptor = stubRootBridge.childBridgeAdaptor(); - - axelarAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); - axelarAdaptor.initialize(roles, address(stubRootBridge), CHILD_CHAIN_NAME, address(axelarGasService)); - vm.deal(address(stubRootBridge), 99999999999); - } - - function test_execute_callsBridge() public { - bytes32 commandId = bytes32("testCommandId"); - string memory sourceChain = "test"; - string memory sourceAddress = Strings.toHexString(address(123)); - bytes memory payload = abi.encodePacked("payload"); - - // We expect to call the bridge's onMessageReceive function. - vm.expectCall( - address(stubRootBridge), - abi.encodeWithSelector(stubRootBridge.onMessageReceive.selector, sourceChain, sourceAddress, payload) - ); - axelarAdaptor.execute(commandId, sourceChain, sourceAddress, payload); - } -} diff --git a/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol b/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol index 7acc8d7b..7eb28c0d 100644 --- a/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol +++ b/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol @@ -18,8 +18,6 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootERC20BridgeErrors, Utils { address constant CHILD_BRIDGE = address(3); - address constant CHILD_BRIDGE_ADAPTOR = address(4); - string CHILD_BRIDGE_ADAPTOR_STRING = Strings.toHexString(CHILD_BRIDGE_ADAPTOR); string constant CHILD_CHAIN_NAME = "test"; address constant UnmappedToken = address(0xbbb); address constant IMX_TOKEN = address(0xccc); @@ -67,11 +65,9 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE roles, address(mockAxelarAdaptor), CHILD_BRIDGE, - CHILD_BRIDGE_ADAPTOR_STRING, address(token), IMX_TOKEN, WRAPPED_ETH, - CHILD_CHAIN_NAME, UNLIMITED_IMX_DEPOSIT_LIMIT ); } @@ -80,25 +76,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE bytes memory data = abi.encode(WITHDRAW_SIG, token, address(this), address(this), withdrawAmount); vm.expectRevert(NotBridgeAdaptor.selector); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); - } - - function test_RevertsIf_OnMessageReceiveWithInvalidSourceChain() public { - bytes memory data = abi.encode(WITHDRAW_SIG, token, address(this), address(this), withdrawAmount); - - vm.prank(address(mockAxelarAdaptor)); - vm.expectRevert(InvalidSourceChain.selector); - rootBridge.onMessageReceive("ding_dong", CHILD_BRIDGE_ADAPTOR_STRING, data); - } - - function test_RevertsIf_OnMessageReceiveWithInvalidSourceAddress() public { - bytes memory data = abi.encode(WITHDRAW_SIG, token, address(this), address(this), withdrawAmount); - - console2.log(CHILD_CHAIN_NAME); - console2.log(rootBridge.childChain()); - vm.prank(address(mockAxelarAdaptor)); - vm.expectRevert(InvalidSourceAddress.selector); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, "DING_DONG", data); + rootBridge.onMessageReceive(data); } function test_RevertsIf_OnMessageReceiveWithZeroDataLength() public { @@ -107,21 +85,21 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE vm.prank(address(mockAxelarAdaptor)); vm.expectRevert(abi.encodeWithSelector(InvalidData.selector, "Data too short")); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_RevertsIf_OnMessageReceiveWithInvalidSignature() public { bytes memory data = abi.encode(keccak256("RANDOM"), token, address(this), address(this), withdrawAmount); vm.prank(address(mockAxelarAdaptor)); vm.expectRevert(abi.encodeWithSelector(InvalidData.selector, "Unsupported action signature")); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_RevertsIf_OnMessageReceiveWithUnmappedToken() public { bytes memory data = abi.encode(WITHDRAW_SIG, UnmappedToken, address(this), address(this), withdrawAmount); vm.prank(address(mockAxelarAdaptor)); vm.expectRevert(NotMapped.selector); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_onMessageReceive_TransfersTokens() public { @@ -135,7 +113,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE bytes memory data = abi.encode(WITHDRAW_SIG, token, address(this), address(this), withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); assertEq(token.balanceOf(address(this)), thisPreBal + withdrawAmount, "Tokens not transferred to receiver"); assertEq( @@ -152,7 +130,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE bytes memory data = abi.encode(WITHDRAW_SIG, imxToken, address(this), address(this), withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); assertEq(imxToken.balanceOf(address(this)), thisPreBal + withdrawAmount, "IMX not transferred to receiver"); assertEq( @@ -169,7 +147,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE bytes memory data = abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), address(this), withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); assertEq(address(this).balance, thisPreBal + withdrawAmount, "ETH not transferred to receiver"); assertEq(address(rootBridge).balance, bridgePreBal - withdrawAmount, "ETH not transferred from bridge"); @@ -187,7 +165,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE bytes memory data = abi.encode(WITHDRAW_SIG, token, address(this), receiver, withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); assertEq(token.balanceOf(receiver), receiverPreBal + withdrawAmount, "Tokens not transferred to receiver"); assertEq( @@ -205,7 +183,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE bytes memory data = abi.encode(WITHDRAW_SIG, imxToken, address(this), receiver, withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); assertEq( imxToken.balanceOf(address(receiver)), receiverPreBal + withdrawAmount, "IMX not transferred to receiver" @@ -225,7 +203,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE bytes memory data = abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), receiver, withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); assertEq(address(receiver).balance, receiverPreBal + withdrawAmount, "ETH not transferred to receiver"); assertEq(address(rootBridge).balance, bridgePreBal - withdrawAmount, "ETH not transferred from bridge"); @@ -247,7 +225,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE withdrawAmount ); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_onMessageReceive_EmitsRootChainERC20WithdrawEventForIMX() public { @@ -258,7 +236,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE vm.expectEmit(); emit RootChainERC20Withdraw(address(imxToken), NATIVE_IMX, address(this), address(this), withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_onMessageReceive_EmitsRootChainETHWithdrawEventForETH() public { @@ -271,7 +249,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE NATIVE_ETH, address(rootBridge.childETHToken()), address(this), address(this), withdrawAmount ); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_onMessageReceive_EmitsRootChainERC20WithdrawEvent_DifferentReceiver() public { @@ -287,7 +265,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE address(token), rootBridge.rootTokenToChildToken(address(token)), address(this), receiver, withdrawAmount ); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_onMessageReceive_EmitsRootChainERC20WithdrawEventForIMX_DifferentReceiver() public { @@ -299,7 +277,7 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE vm.expectEmit(); emit RootChainERC20Withdraw(address(imxToken), NATIVE_IMX, address(this), receiver, withdrawAmount); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } function test_onMessageReceive_EmitsRootChainETHWithdrawEventForETH_DifferentReceiver() public { @@ -313,6 +291,6 @@ contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootE NATIVE_ETH, address(rootBridge.childETHToken()), address(this), receiver, withdrawAmount ); vm.prank(address(mockAxelarAdaptor)); - rootBridge.onMessageReceive(CHILD_CHAIN_NAME, CHILD_BRIDGE_ADAPTOR_STRING, data); + rootBridge.onMessageReceive(data); } } diff --git a/test/utils.t.sol b/test/utils.t.sol index 935740aa..512b91cf 100644 --- a/test/utils.t.sol +++ b/test/utils.t.sol @@ -141,11 +141,9 @@ contract Utils is Test { roles, address(integrationTest.axelarAdaptor), childBridge, - Strings.toHexString(childBridgeAdaptor), address(integrationTest.token), imxTokenAddress, wethTokenAddress, - childBridgeName, imxCumulativeDepositLimit, address(this) ); @@ -161,6 +159,7 @@ contract Utils is Test { adaptorRoles, address(integrationTest.rootBridgeFlowRate), childBridgeName, + Strings.toHexString(childBridgeAdaptor), address(integrationTest.axelarGasService) ); } From abd07aaeab3dfd55d3c3eb55168f497f5d0b9638 Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 23 Nov 2023 04:34:44 +1100 Subject: [PATCH 2/7] Remove Axelar specific logic from Child bridge --- script/InitializeChildContracts.s.sol | 14 +- src/child/ChildAxelarBridgeAdaptor.sol | 63 +++++-- src/child/ChildERC20Bridge.sol | 47 +---- .../child/IChildAxelarBridgeAdaptor.sol | 15 ++ src/interfaces/child/IChildERC20Bridge.sol | 27 +-- .../root/IRootAxelarBridgeAdaptor.sol | 16 +- src/root/RootAxelarBridgeAdaptor.sol | 7 +- src/root/RootERC20Bridge.sol | 3 +- .../integration/child/ChildAxelarBridge.t.sol | 31 ++-- .../ChildAxelarBridgeWithdraw.t.sol | 10 +- .../ChildAxelarBridgeWithdrawETH.t.sol | 10 +- .../ChildAxelarBridgeWithdrawETHTo.t.sol | 12 +- .../ChildAxelarBridgeWithdrawIMX.t.sol | 10 +- .../ChildAxelarBridgeWithdrawTo.t.sol | 10 +- .../ChildAxelarBridgeWithdrawToIMX.t.sol | 20 +- .../ChildAxelarBridgeWithdrawWIMX.t.sol | 10 +- .../ChildAxelarBridgeWithdrawWIMXTo.t.sol | 20 +- .../RootERC20BridgeFlowRateWithdraw.t.sol | 8 +- test/mocks/child/MockChildERC20Bridge.sol | 2 +- .../unit/child/ChildAxelarBridgeAdaptor.t.sol | 143 ++++++++++++--- test/unit/child/ChildERC20Bridge.t.sol | 173 ++++-------------- .../ChildERC20BridgeWithdraw.t.sol | 12 +- .../ChildERC20BridgeWithdrawETH.t.sol | 10 +- .../ChildERC20BridgeWithdrawETHTo.t.sol | 12 +- .../ChildERC20BridgeWithdrawIMX.t.sol | 10 +- .../ChildERC20BridgeWithdrawIMXTo.t.sol | 10 +- .../ChildERC20BridgeWithdrawTo.t.sol | 12 +- .../ChildERC20BridgeWithdrawWIMX.t.sol | 10 +- .../ChildERC20BridgeWithdrawWIMXTo.t.sol | 10 +- test/utils.t.sol | 19 +- 30 files changed, 342 insertions(+), 414 deletions(-) diff --git a/script/InitializeChildContracts.s.sol b/script/InitializeChildContracts.s.sol index 8fa4d37d..3aaf58ec 100644 --- a/script/InitializeChildContracts.s.sol +++ b/script/InitializeChildContracts.s.sol @@ -21,7 +21,7 @@ struct InitializeChildContractsParams { ChildERC20Bridge childERC20Bridge; ChildAxelarBridgeAdaptor childAxelarBridgeAdaptor; address childTokenTemplate; - address rootERC20BridgeAdaptor; + address rootBridgeAdaptor; string rootChainName; address rootIMXToken; address wIMXToken; @@ -43,7 +43,7 @@ contract InitializeChildContracts is Script { childERC20Bridge: ChildERC20Bridge(payable(vm.envAddress("CHILD_ERC20_BRIDGE"))), childAxelarBridgeAdaptor: ChildAxelarBridgeAdaptor(vm.envAddress("CHILD_BRIDGE_ADAPTOR")), childTokenTemplate: vm.envAddress("CHILDCHAIN_CHILD_TOKEN_TEMPLATE"), - rootERC20BridgeAdaptor: vm.envAddress("ROOT_BRIDGE_ADAPTOR"), + rootBridgeAdaptor: vm.envAddress("ROOT_BRIDGE_ADAPTOR"), rootChainName: vm.envString("ROOT_CHAIN_NAME"), rootIMXToken: vm.envAddress("ROOT_IMX_ADDRESS"), wIMXToken: vm.envAddress("CHILD_WIMX_ADDRESS"), @@ -55,7 +55,7 @@ contract InitializeChildContracts is Script { /** * INITIALIZE CHILD CONTRACTS */ - string[] memory checksumInputs = Utils.getChecksumInputs(params.rootERC20BridgeAdaptor); + string[] memory checksumInputs = Utils.getChecksumInputs(params.rootBridgeAdaptor); bytes memory checksumOutput = vm.ffi(checksumInputs); string memory rootBridgeAdaptorString = string(Utils.removeZeroByteValues(checksumOutput)); @@ -72,9 +72,7 @@ contract InitializeChildContracts is Script { params.childERC20Bridge.initialize( roles, address(params.childAxelarBridgeAdaptor), - rootBridgeAdaptorString, params.childTokenTemplate, - params.rootChainName, params.rootIMXToken, params.wIMXToken ); @@ -88,7 +86,11 @@ contract InitializeChildContracts is Script { }); params.childAxelarBridgeAdaptor.initialize( - adaptorRoles, params.rootChainName, address(params.childERC20Bridge), params.childGasService + adaptorRoles, + params.rootChainName, + rootBridgeAdaptorString, + address(params.childERC20Bridge), + params.childGasService ); vm.stopBroadcast(); diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index 970e0185..b7bdae57 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache 2.0 pragma solidity 0.8.19; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {AxelarExecutable} from "@axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol"; import {IAxelarGasService} from "@axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol"; import {IChildERC20Bridge} from "../interfaces/child/IChildERC20Bridge.sol"; @@ -38,8 +39,14 @@ contract ChildAxelarBridgeAdaptor is { /// @notice Address of bridge to relay messages to. IChildERC20Bridge public childBridge; + + /// @notice Axelar's ID for the child chain. Axelar uses the chain name as the chain ID. + string public rootChainId; + + /// @notice Address of the bridge adaptor on the root chain, which this contract will communicate with. + string public rootBridgeAdaptor; + IAxelarGasService public gasService; - string public rootChain; constructor(address _gateway) AxelarExecutable(_gateway) {} @@ -53,6 +60,7 @@ contract ChildAxelarBridgeAdaptor is function initialize( InitializationRoles memory newRoles, string memory _rootChainId, + string memory _rootBridgeAdaptor, address _childBridge, address _gasService ) external initializer { @@ -68,6 +76,9 @@ contract ChildAxelarBridgeAdaptor is revert InvalidRootChain(); } + if (bytes(_rootBridgeAdaptor).length == 0) { + revert InvalidRootERC20BridgeAdaptor(); + } __AccessControl_init(); _grantRole(DEFAULT_ADMIN_ROLE, newRoles.defaultAdmin); @@ -76,7 +87,8 @@ contract ChildAxelarBridgeAdaptor is _grantRole(TARGET_MANAGER_ROLE, newRoles.targetManager); childBridge = IChildERC20Bridge(_childBridge); - rootChain = _rootChainId; + rootChainId = _rootChainId; + rootBridgeAdaptor = _rootBridgeAdaptor; gasService = IAxelarGasService(_gasService); } @@ -100,8 +112,20 @@ contract ChildAxelarBridgeAdaptor is revert InvalidRootChain(); } - emit RootChainUpdated(rootChain, newRootChain); - rootChain = newRootChain; + emit RootChainUpdated(rootChainId, newRootChain); + rootChainId = newRootChain; + } + + /** + * @inheritdoc IChildAxelarBridgeAdaptor + */ + function updateRootBridgeAdaptor(string memory newRootBridgeAdaptor) external onlyRole(TARGET_MANAGER_ROLE) { + if (bytes(newRootBridgeAdaptor).length == 0) { + revert InvalidRootERC20BridgeAdaptor(); + } + + emit RootBridgeAdaptorUpdated(rootBridgeAdaptor, newRootBridgeAdaptor); + rootBridgeAdaptor = newRootBridgeAdaptor; } /** @@ -128,8 +152,8 @@ contract ChildAxelarBridgeAdaptor is } // Load from storage. - string memory _rootBridgeAdaptor = childBridge.rootERC20BridgeAdaptor(); - string memory _rootChain = rootChain; + string memory _rootBridgeAdaptor = rootBridgeAdaptor; + string memory _rootChain = rootChainId; gasService.payNativeGasForContractCall{value: msg.value}( address(this), _rootChain, _rootBridgeAdaptor, payload, refundRecipient @@ -140,18 +164,29 @@ contract ChildAxelarBridgeAdaptor is } /** - * @dev This function is called by the parent `AxelarExecutable` contract to execute the payload. - * @param sourceChain_ The chain id that the message originated from. - * @param sourceAddress_ The contract address that sent the message on the source chain. - * @param payload_ The message payload. - * @custom:assumes `sourceAddress_` is a 20 byte address. + * @dev This function is called by the parent `AxelarExecutable` contract to execute a message payload sent from the root chain. + * The function first validates the message by checking that it originated from the registered + * root chain and bridge adaptor contract on the root chain. If not, the message is rejected. + * If a message is valid, it calls the root bridge contract's `onMessageReceive` function. + * @param _sourceChain The chain id that the message originated from. + * @param _sourceAddress The contract address that sent the message on the source chain. + * @param _payload The message payload. + * @custom:assumes `_sourceAddress` is a 20 byte address. */ - function _execute(string calldata sourceChain_, string calldata sourceAddress_, bytes calldata payload_) + function _execute(string calldata _sourceChain, string calldata _sourceAddress, bytes calldata _payload) internal override { - emit AdaptorExecute(sourceChain_, sourceAddress_, payload_); - childBridge.onMessageReceive(sourceChain_, sourceAddress_, payload_); + if (!Strings.equal(_sourceChain, rootChainId)) { + revert InvalidSourceChain(); + } + + if (!Strings.equal(_sourceAddress, rootBridgeAdaptor)) { + revert InvalidSourceAddress(); + } + + emit AdaptorExecute(_sourceChain, _sourceAddress, _payload); + childBridge.onMessageReceive(_payload); } // slither-disable-next-line unused-state,naming-convention diff --git a/src/child/ChildERC20Bridge.sol b/src/child/ChildERC20Bridge.sol index 22124e0a..c1ec8153 100644 --- a/src/child/ChildERC20Bridge.sol +++ b/src/child/ChildERC20Bridge.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.19; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import { IChildERC20BridgeEvents, @@ -55,12 +54,8 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br IChildERC20BridgeAdaptor public bridgeAdaptor; - /// @dev The address that will be sending messages to, and receiving messages from, the child chain. - string public rootERC20BridgeAdaptor; /// @dev The address of the token template that will be cloned to create tokens. address public childTokenTemplate; - /// @dev The name of the chain that this bridge is connected to. - string public rootChain; /// @dev The address of the IMX ERC20 token on L1. address public rootIMXToken; /// @dev The address of the ETH ERC20 token on L2. @@ -72,9 +67,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br * @notice Initialization function for ChildERC20Bridge. * @param newRoles Struct containing addresses of roles. * @param newBridgeAdaptor Address of StateSender to send deposit information to. - * @param newRootERC20BridgeAdaptor Stringified address of root ERC20 bridge adaptor to communicate with. * @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 newWIMXToken Address of wrapped IMX on the child chain. * @dev Can only be called once. @@ -82,9 +75,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br function initialize( InitializationRoles memory newRoles, address newBridgeAdaptor, - string memory newRootERC20BridgeAdaptor, address newChildTokenTemplate, - string memory newRootChain, address newRootIMXToken, address newWIMXToken ) public initializer { @@ -97,14 +88,6 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br revert ZeroAddress(); } - if (bytes(newRootERC20BridgeAdaptor).length == 0) { - revert InvalidRootERC20BridgeAdaptor(); - } - - if (bytes(newRootChain).length == 0) { - revert InvalidRootChain(); - } - __AccessControl_init(); __Pausable_init(); @@ -114,10 +97,8 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br _grantRole(ADAPTOR_MANAGER_ROLE, newRoles.adaptorManager); _grantRole(TREASURY_MANAGER_ROLE, newRoles.treasuryManager); - rootERC20BridgeAdaptor = newRootERC20BridgeAdaptor; childTokenTemplate = newChildTokenTemplate; bridgeAdaptor = IChildERC20BridgeAdaptor(newBridgeAdaptor); - rootChain = newRootChain; rootIMXToken = newRootIMXToken; wIMXToken = newWIMXToken; @@ -169,33 +150,15 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br /** * @inheritdoc IChildERC20Bridge + * @dev This is only callable by the child chain bridge adaptor. + * This method assumes that the adaptor will have performed all + * validations relating to the source of the message, prior to calling this method. */ - function updateRootBridgeAdaptor(string memory newRootBridgeAdaptor) external onlyRole(ADAPTOR_MANAGER_ROLE) { - if (bytes(newRootBridgeAdaptor).length == 0) { - revert InvalidRootERC20BridgeAdaptor(); - } - - emit RootBridgeAdaptorUpdated(rootERC20BridgeAdaptor, newRootBridgeAdaptor); - rootERC20BridgeAdaptor = newRootBridgeAdaptor; - } - - /** - * @inheritdoc IChildERC20Bridge - */ - function onMessageReceive(string calldata messageSourceChain, string calldata sourceAddress, bytes calldata data) - external - override - whenNotPaused - { + function onMessageReceive(bytes calldata data) external override whenNotPaused { if (msg.sender != address(bridgeAdaptor)) { revert NotBridgeAdaptor(); } - if (!Strings.equal(messageSourceChain, rootChain)) { - revert InvalidSourceChain(); - } - if (!Strings.equal(sourceAddress, rootERC20BridgeAdaptor)) { - revert InvalidSourceAddress(); - } + if (data.length <= 32) { // Data must always be greater than 32. // 32 bytes for the signature, and at least some information for the payload diff --git a/src/interfaces/child/IChildAxelarBridgeAdaptor.sol b/src/interfaces/child/IChildAxelarBridgeAdaptor.sol index fed84240..70b2d322 100644 --- a/src/interfaces/child/IChildAxelarBridgeAdaptor.sol +++ b/src/interfaces/child/IChildAxelarBridgeAdaptor.sol @@ -29,6 +29,13 @@ interface IChildAxelarBridgeAdaptor { */ function updateRootChain(string memory newRootChain) external; + /** + * @notice Update the root chain bridge adaptor address + * @param newRootBridgeAdaptor address of the new child bridge adaptor. + * @dev Can only be called by TARGET_MANAGER_ROLE. + */ + function updateRootBridgeAdaptor(string memory newRootBridgeAdaptor) external; + /** * @notice Update the gas service. * @param newGasService Address of new gas service. @@ -38,6 +45,8 @@ interface IChildAxelarBridgeAdaptor { } interface IChildAxelarBridgeAdaptorErrors { + /// @notice Error when the given bridge adaptor is invalid. + error InvalidRootERC20BridgeAdaptor(); /// @notice Error when a zero address is given when not valid. error ZeroAddress(); /// @notice Error when a message is sent with no gas payment. @@ -46,6 +55,10 @@ interface IChildAxelarBridgeAdaptorErrors { error CallerNotBridge(); /// @notice Error when the root chain name is invalid. error InvalidRootChain(); + /// @notice Error when the message's source chain is not valid. + error InvalidSourceChain(); + /// @notice Error when the source chain's message sender is not a recognised address. + error InvalidSourceAddress(); } /** @@ -53,6 +66,8 @@ interface IChildAxelarBridgeAdaptorErrors { * @notice Contains the event types that can be emitted by a bridge adaptor */ interface IChildAxelarBridgeAdaptorEvents { + /// @notice Emitted when the root chain bridge adaptor is updated. + event RootBridgeAdaptorUpdated(string oldRootBridgeAdaptor, string newRootBridgeAdaptor); /// @notice Emitted when an Axelar message is sent to the root chain. event AxelarMessageSent(string indexed rootChain, string indexed rootBridgeAdaptor, bytes indexed payload); /// @notice Emitted when an Axelar message is received from the root chain. diff --git a/src/interfaces/child/IChildERC20Bridge.sol b/src/interfaces/child/IChildERC20Bridge.sol index 1e1e45c6..31f99cfd 100644 --- a/src/interfaces/child/IChildERC20Bridge.sol +++ b/src/interfaces/child/IChildERC20Bridge.sol @@ -31,21 +31,12 @@ interface IChildERC20Bridge { */ function treasuryDeposit() external payable; - /** - * @notice Get the address of the bridge adaptor on the root chain. - * @return address of the bridge adaptor on the root chain. - */ - function rootERC20BridgeAdaptor() external view returns (string memory); - /** * @notice Receives a bridge message from the root chain. - * @param sourceChain The id of the chain the message originated from. - * @param sourceAddress The address of the contract on the root chain that sent the message. * @param data The data payload of the message. * @dev This function is called by the underlying bridge adaptor on the child chain, when it receives a validated message from the GMP. */ - function onMessageReceive(string calldata sourceChain, string calldata sourceAddress, bytes calldata data) - external; + function onMessageReceive(bytes calldata data) external; /** * @notice Sets a new bridge adaptor address to receive and send function calls for L1 messages @@ -53,12 +44,6 @@ interface IChildERC20Bridge { */ function updateChildBridgeAdaptor(address newBridgeAdaptor) external; - /** - * @notice Sets a new root chain bridge adaptor address to receive and send function calls for L2 messages - * @param newRootBridgeAdaptor The new root chain bridge adaptor address. - */ - function updateRootBridgeAdaptor(string memory newRootBridgeAdaptor) external; - /** * @notice Withdraws `amount` of `childToken` to `msg.sender` on the rootchain. * @param childToken The address of the child token to withdraw. @@ -159,8 +144,6 @@ interface IChildERC20BridgeEvents { ); /// @notice Emitted when the child chain bridge adaptor is updated. event ChildBridgeAdaptorUpdated(address oldChildBridgeAdaptor, address newChildBridgeAdaptor); - /// @notice Emitted when the root chain bridge adaptor is updated. - event RootBridgeAdaptorUpdated(string oldRootBridgeAdaptor, string newRootBridgeAdaptor); /// @notice Emitted when a treasury deposit is made. event TreasuryDeposit(address indexed depositor, uint256 amount); } @@ -182,10 +165,6 @@ interface IChildERC20BridgeErrors { error EmptyTokenContract(); /// @notice Error when the mint operation failed. error MintFailed(); - /// @notice Error when the given root chain name is invalid. - error InvalidRootChain(); - /// @notice Error when the given bridge adaptor is invalid. - error InvalidRootERC20BridgeAdaptor(); /// @notice Error when a zero address is given when not valid. error ZeroAddress(); /// @notice Error when a token is not mapped. @@ -200,10 +179,6 @@ interface IChildERC20BridgeErrors { error NotBridgeAdaptor(); /// @notice Error when the message's payload is not valid. error InvalidData(string reason); - /// @notice Error when the message's source chain is not valid. - error InvalidSourceChain(); - /// @notice Error when the source chain's message sender is not a recognised address. - error InvalidSourceAddress(); /// @notice Error when a given child token's root token is the zero address. error ZeroAddressRootToken(); /// @notice Error when a given child token's bridge address is not set. diff --git a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol index 9eefddf4..6065c5e0 100644 --- a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol +++ b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol @@ -30,7 +30,7 @@ interface IRootAxelarBridgeAdaptor { function updateChildChain(string memory newChildChain) external; /** - * @notice Update the child chain bridge address + * @notice Update the child chain bridge adaptor address * @param newChildBridgeAdaptor address of the new child bridge adaptor. * @dev Can only be called by TARGET_MANAGER_ROLE. */ @@ -57,6 +57,12 @@ interface IRootAxelarBridgeAdaptorErrors { error NoGas(); /// @notice Error when the contract calling the adaptor is not the bridge. error CallerNotBridge(); + /// @notice Error when the given child chain bridge adaptor is invalid. + error InvalidChildERC20BridgeAdaptor(); + /// @notice Error when a message received has invalid source address. + error InvalidSourceAddress(); + /// @notice Error when a message received has invalid source chain. + error InvalidSourceChain(); } /** @@ -66,15 +72,7 @@ interface IRootAxelarBridgeAdaptorErrors { interface IRootAxelarBridgeAdaptorEvents { /// @notice Emitted when the child chain bridge adaptor is updated. event ChildBridgeAdaptorUpdated(string oldChildBridgeAdaptor, string newChildBridgeAdaptor); - /// @notice Error when the given child chain bridge adaptor is invalid. - - error InvalidChildERC20BridgeAdaptor(); - /// @notice Error when a message received has invalid source address. - error InvalidSourceAddress(); - /// @notice Error when a message received has invalid source chain. - error InvalidSourceChain(); /// @notice Emitted when an Axelar message is sent to the child chain. - event AxelarMessageSent(string indexed childChain, string indexed childBridgeAdaptor, bytes indexed payload); /// @notice Emitted when an Axelar message is received from the child chain. event AdaptorExecute(string sourceChain, string sourceAddress_, bytes payload_); diff --git a/src/root/RootAxelarBridgeAdaptor.sol b/src/root/RootAxelarBridgeAdaptor.sol index bd908640..374f8e59 100644 --- a/src/root/RootAxelarBridgeAdaptor.sol +++ b/src/root/RootAxelarBridgeAdaptor.sol @@ -42,11 +42,9 @@ contract RootAxelarBridgeAdaptor is IRootERC20Bridge public rootBridge; /// @notice Axelar's ID for the child chain. Axelar uses the chain name as the chain ID. - /// @dev Messages that are sent to the chain that does not match this chain id, will be rejected. string public childChainId; /// @notice Address of the bridge adaptor on the child chain, which this contract will communicate with. - /// @dev Messages that are sent to the child chain that did not originate from this address will be rejected. string public childBridgeAdaptor; /// @notice Address of the Axelar Gas Service contract. @@ -169,7 +167,10 @@ contract RootAxelarBridgeAdaptor is } /** - * @dev This function is called by the parent `AxelarExecutable` contract to execute the payload. + * @dev This function is called by the parent `AxelarExecutable` contract to execute a message payload sent from the child chain. + * The function first validates the message by checking that it originated from the registered + * child chain and bridge adaptor contract on the child chain. If not, the message is rejected. + * If a message is valid, it calls the root bridge contract's `onMessageReceive` function. * @param _sourceChain The chain id that the message originated from. * @param _sourceAddress The contract address that sent the message on the source chain. * @param _payload The message payload. diff --git a/src/root/RootERC20Bridge.sol b/src/root/RootERC20Bridge.sol index 3ba84f0d..1321d1f1 100644 --- a/src/root/RootERC20Bridge.sol +++ b/src/root/RootERC20Bridge.sol @@ -7,7 +7,6 @@ import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; -import {IAxelarGateway} from "@axelar-cgp-solidity/contracts/interfaces/IAxelarGateway.sol"; import { IRootERC20Bridge, IERC20Metadata, @@ -217,6 +216,8 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent /** * @inheritdoc IRootERC20Bridge * @dev This is only callable by the root chain bridge adaptor. + * This method assumes that the adaptor will have performed all + * validations relating to the source of the message, prior to calling this method. */ function onMessageReceive(bytes calldata data) external override whenNotPaused { if (msg.sender != address(rootBridgeAdaptor)) { diff --git a/test/integration/child/ChildAxelarBridge.t.sol b/test/integration/child/ChildAxelarBridge.t.sol index 408a0d8e..8c699a7f 100644 --- a/test/integration/child/ChildAxelarBridge.t.sol +++ b/test/integration/child/ChildAxelarBridge.t.sol @@ -4,13 +4,18 @@ pragma solidity 0.8.19; import {Test} from "forge-std/Test.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; -import {ChildAxelarBridgeAdaptor, IChildAxelarBridgeAdaptor} from "../../../src/child/ChildAxelarBridgeAdaptor.sol"; +import {ChildAxelarBridgeAdaptor} from "../../../src/child/ChildAxelarBridgeAdaptor.sol"; import { ChildERC20Bridge, IChildERC20Bridge, - IChildERC20BridgeEvents, - IChildERC20BridgeErrors + IChildERC20BridgeErrors, + IChildERC20BridgeEvents } from "../../../src/child/ChildERC20Bridge.sol"; +import { + IChildAxelarBridgeAdaptorErrors, + IChildAxelarBridgeAdaptorEvents, + IChildAxelarBridgeAdaptor +} from "../../../src/interfaces/child/IChildAxelarBridgeAdaptor.sol"; import {IChildERC20, ChildERC20} from "../../../src/child/ChildERC20.sol"; import {MockChildAxelarGateway} from "../../mocks/child/MockChildAxelarGateway.sol"; import {MockChildAxelarGasService} from "../../mocks/child/MockChildAxelarGasService.sol"; @@ -46,13 +51,7 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil treasuryManager: address(this) }); childERC20Bridge.initialize( - roles, - address(childAxelarBridgeAdaptor), - ROOT_ADAPTOR_ADDRESS, - address(childERC20), - ROOT_CHAIN_NAME, - IMX_TOKEN_ADDRESS, - WIMX_TOKEN_ADDRESS + roles, address(childAxelarBridgeAdaptor), address(childERC20), IMX_TOKEN_ADDRESS, WIMX_TOKEN_ADDRESS ); IChildAxelarBridgeAdaptor.InitializationRoles memory adaptorRoles = IChildAxelarBridgeAdaptor @@ -64,7 +63,11 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil }); childAxelarBridgeAdaptor.initialize( - adaptorRoles, ROOT_CHAIN_NAME, address(childERC20Bridge), address(mockChildAxelarGasService) + adaptorRoles, + ROOT_CHAIN_NAME, + ROOT_ADAPTOR_ADDRESS, + address(childERC20Bridge), + address(mockChildAxelarGasService) ); } @@ -135,16 +138,14 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil bytes32 commandId = bytes32("testCommandId"); bytes memory payload = abi.encode(childERC20Bridge.MAP_TOKEN_SIG(), address(456), "test name", "TSTNME", 17); - vm.expectRevert(InvalidSourceChain.selector); + vm.expectRevert(IChildAxelarBridgeAdaptorErrors.InvalidSourceChain.selector); childAxelarBridgeAdaptor.execute(commandId, "FAKE_CHAIN", ROOT_ADAPTOR_ADDRESS, payload); } function mapToken(address root) public returns (address childToken) { bytes32 mapTokenSig = childERC20Bridge.MAP_TOKEN_SIG(); vm.prank(address(childAxelarBridgeAdaptor)); - childERC20Bridge.onMessageReceive( - ROOT_CHAIN_NAME, ROOT_ADAPTOR_ADDRESS, abi.encode(mapTokenSig, root, "test name", "TSTNME", 17) - ); + childERC20Bridge.onMessageReceive(abi.encode(mapTokenSig, root, "test name", "TSTNME", 17)); return Clones.predictDeterministicAddress( address(childERC20), keccak256(abi.encodePacked(root)), address(childERC20Bridge) ); diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdraw.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdraw.t.sol index 646a727a..576e6038 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdraw.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdraw.t.sol @@ -66,8 +66,8 @@ contract ChildERC20BridgeWithdrawIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -86,8 +86,8 @@ contract ChildERC20BridgeWithdrawIntegrationTest is abi.encodeWithSelector( mockAxelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -103,7 +103,7 @@ contract ChildERC20BridgeWithdrawIntegrationTest is abi.encode(WITHDRAW_SIG, rootToken, address(this), address(this), withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdraw{value: withdrawFee}(childToken, withdrawAmount); } diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETH.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETH.t.sol index a6ddd227..a03eb30f 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETH.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETH.t.sol @@ -67,8 +67,8 @@ contract ChildERC20BridgeWithdrawETHIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -89,8 +89,8 @@ contract ChildERC20BridgeWithdrawETHIntegrationTest is abi.encodeWithSelector( mockAxelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -107,7 +107,7 @@ contract ChildERC20BridgeWithdrawETHIntegrationTest is abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), address(this), withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawETH{value: withdrawFee}(withdrawAmount); } diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETHTo.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETHTo.t.sol index f3243522..9fa5c0ea 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETHTo.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawETHTo.t.sol @@ -82,8 +82,8 @@ contract ChildERC20BridgeWithdrawETHToIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -102,8 +102,8 @@ contract ChildERC20BridgeWithdrawETHToIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -119,7 +119,7 @@ contract ChildERC20BridgeWithdrawETHToIntegrationTest is abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), address(this), withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawETHTo{value: withdrawFee}(address(this), withdrawAmount); } @@ -132,7 +132,7 @@ contract ChildERC20BridgeWithdrawETHToIntegrationTest is bytes memory predictedPayload = abi.encode(WITHDRAW_SIG, NATIVE_ETH, address(this), receiver, withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawETHTo{value: withdrawFee}(receiver, withdrawAmount); } diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawIMX.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawIMX.t.sol index c08ed389..cf85297d 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawIMX.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawIMX.t.sol @@ -67,8 +67,8 @@ contract ChildERC20BridgeWithdrawIMXIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -89,8 +89,8 @@ contract ChildERC20BridgeWithdrawIMXIntegrationTest is abi.encodeWithSelector( axelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -107,7 +107,7 @@ contract ChildERC20BridgeWithdrawIMXIntegrationTest is abi.encode(WITHDRAW_SIG, ROOT_IMX_TOKEN, address(this), address(this), withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawIMX{value: withdrawFee + withdrawAmount}(withdrawAmount); } diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawTo.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawTo.t.sol index a5344353..455f1ace 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawTo.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawTo.t.sol @@ -64,8 +64,8 @@ contract ChildERC20BridgeWithdrawToIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -83,8 +83,8 @@ contract ChildERC20BridgeWithdrawToIntegrationTest is abi.encodeWithSelector( mockAxelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -99,7 +99,7 @@ contract ChildERC20BridgeWithdrawToIntegrationTest is bytes memory predictedPayload = abi.encode(WITHDRAW_SIG, rootToken, address(this), receiver, withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawTo{value: withdrawFee}(childToken, receiver, withdrawAmount); } diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawToIMX.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawToIMX.t.sol index 7fd11b04..0d972662 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawToIMX.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawToIMX.t.sol @@ -84,8 +84,8 @@ contract ChildERC20BridgewithdrawIMXToIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -105,8 +105,8 @@ contract ChildERC20BridgewithdrawIMXToIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -127,8 +127,8 @@ contract ChildERC20BridgewithdrawIMXToIntegrationTest is abi.encodeWithSelector( axelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -151,8 +151,8 @@ contract ChildERC20BridgewithdrawIMXToIntegrationTest is abi.encodeWithSelector( axelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -169,7 +169,7 @@ contract ChildERC20BridgewithdrawIMXToIntegrationTest is abi.encode(WITHDRAW_SIG, ROOT_IMX_TOKEN, address(this), address(this), withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawIMXTo{value: withdrawFee + withdrawAmount}(address(this), withdrawAmount); } @@ -183,7 +183,7 @@ contract ChildERC20BridgewithdrawIMXToIntegrationTest is abi.encode(WITHDRAW_SIG, ROOT_IMX_TOKEN, address(this), receiver, withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawIMXTo{value: withdrawFee + withdrawAmount}(receiver, withdrawAmount); } diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMX.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMX.t.sol index f3dc6ad3..8c6c5d3c 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMX.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMX.t.sol @@ -64,8 +64,8 @@ contract ChildERC20BridgeWithdrawWIMXIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -87,8 +87,8 @@ contract ChildERC20BridgeWithdrawWIMXIntegrationTest is abi.encodeWithSelector( mockAxelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -106,7 +106,7 @@ contract ChildERC20BridgeWithdrawWIMXIntegrationTest is abi.encode(WITHDRAW_SIG, ROOT_IMX_TOKEN, address(this), address(this), withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawWIMX{value: withdrawFee}(withdrawAmount); } diff --git a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMXTo.t.sol b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMXTo.t.sol index 9be8cf84..11bf5ec4 100644 --- a/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMXTo.t.sol +++ b/test/integration/child/withdrawals/ChildAxelarBridgeWithdrawWIMXTo.t.sol @@ -91,8 +91,8 @@ contract ChildERC20BridgeWithdrawWIMXToIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -113,8 +113,8 @@ contract ChildERC20BridgeWithdrawWIMXToIntegrationTest is 0, abi.encodeWithSelector( mockAxelarGateway.callContract.selector, - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload ) ); @@ -137,8 +137,8 @@ contract ChildERC20BridgeWithdrawWIMXToIntegrationTest is abi.encodeWithSelector( axelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -162,8 +162,8 @@ contract ChildERC20BridgeWithdrawWIMXToIntegrationTest is abi.encodeWithSelector( axelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), - childBridge.rootChain(), - childBridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootChainId(), + axelarAdaptor.rootBridgeAdaptor(), predictedPayload, address(this) ) @@ -182,7 +182,7 @@ contract ChildERC20BridgeWithdrawWIMXToIntegrationTest is abi.encode(WITHDRAW_SIG, ROOT_IMX_TOKEN, address(this), receiver, withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawWIMXTo{value: withdrawFee}(receiver, withdrawAmount); } @@ -197,7 +197,7 @@ contract ChildERC20BridgeWithdrawWIMXToIntegrationTest is abi.encode(WITHDRAW_SIG, ROOT_IMX_TOKEN, address(this), receiver, withdrawAmount); vm.expectEmit(address(axelarAdaptor)); - emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload); + emit AxelarMessageSent(axelarAdaptor.rootChainId(), axelarAdaptor.rootBridgeAdaptor(), predictedPayload); childBridge.withdrawWIMXTo{value: withdrawFee}(receiver, withdrawAmount); } diff --git a/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol b/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol index 735e0a20..9bfae48e 100644 --- a/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol +++ b/test/integration/root/withdrawals/RootERC20BridgeFlowRateWithdraw.t.sol @@ -16,7 +16,9 @@ import { import {RootERC20BridgeFlowRate} from "../../../../src/root/flowrate/RootERC20BridgeFlowRate.sol"; import { - RootAxelarBridgeAdaptor, IRootAxelarBridgeAdaptorEvents + RootAxelarBridgeAdaptor, + IRootAxelarBridgeAdaptorEvents, + IRootAxelarBridgeAdaptorErrors } from "../../../../src/root/RootAxelarBridgeAdaptor.sol"; import {Utils} from "../../../utils.t.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; @@ -87,7 +89,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes32 commandId = bytes32("testCommandId"); string memory sourceAddress = axelarAdaptor.childBridgeAdaptor(); - vm.expectRevert(InvalidSourceChain.selector); + vm.expectRevert(IRootAxelarBridgeAdaptorErrors.InvalidSourceChain.selector); axelarAdaptor.execute(commandId, "INVALID", sourceAddress, data); } @@ -97,7 +99,7 @@ contract RootERC20BridgeFlowRateWithdrawIntegrationTest is bytes32 commandId = bytes32("testCommandId"); string memory sourceAddress = Strings.toHexString(address(123)); - vm.expectRevert(InvalidSourceAddress.selector); + vm.expectRevert(IRootAxelarBridgeAdaptorErrors.InvalidSourceAddress.selector); axelarAdaptor.execute(commandId, CHILD_CHAIN_NAME, sourceAddress, data); } diff --git a/test/mocks/child/MockChildERC20Bridge.sol b/test/mocks/child/MockChildERC20Bridge.sol index dc2caa22..fb5818b4 100644 --- a/test/mocks/child/MockChildERC20Bridge.sol +++ b/test/mocks/child/MockChildERC20Bridge.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.19; contract MockChildERC20Bridge { - function onMessageReceive(string calldata, string calldata, bytes calldata) external {} + function onMessageReceive(bytes calldata) external {} function rootERC20BridgeAdaptor() external pure returns (string memory) { return "rootERC20BridgeAdaptor"; diff --git a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol index 6b50dbb9..74e5c055 100644 --- a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol +++ b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol @@ -18,6 +18,7 @@ import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErrors, IChildAxelarBridgeAdaptorEvents { address public GATEWAY_ADDRESS = address(1); string public constant ROOT_CHAIN_NAME = "root"; + string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); bytes32 public constant WITHDRAW_SIG = keccak256("WITHDRAW"); ERC20PresetMinterPauser public token; @@ -44,7 +45,11 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro mockChildAxelarGasService = new MockChildAxelarGasService(); axelarAdaptor = new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); axelarAdaptor.initialize( - roles, ROOT_CHAIN_NAME, address(mockChildERC20Bridge), address(mockChildAxelarGasService) + roles, + ROOT_CHAIN_NAME, + ROOT_BRIDGE_ADAPTOR, + address(mockChildERC20Bridge), + address(mockChildAxelarGasService) ); } @@ -54,8 +59,9 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro function test_Initialize() public { assertEq(address(axelarAdaptor.childBridge()), address(mockChildERC20Bridge), "childBridge not set"); + assertEq(axelarAdaptor.rootChainId(), ROOT_CHAIN_NAME, "rootChain not set"); + assertEq(axelarAdaptor.rootBridgeAdaptor(), ROOT_BRIDGE_ADAPTOR, "rootBridgeAdaptor not set"); assertEq(address(axelarAdaptor.gateway()), address(mockChildAxelarGateway), "gateway not set"); - assertEq(axelarAdaptor.rootChain(), ROOT_CHAIN_NAME, "rootChain not set"); assertEq(address(axelarAdaptor.gasService()), address(mockChildAxelarGasService), "gasService not set"); assertEq( axelarAdaptor.hasRole(axelarAdaptor.BRIDGE_MANAGER_ROLE(), bridgeManager), true, "bridgeManager not set" @@ -74,76 +80,124 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); roles.defaultAdmin = address(0); - newAdaptor.initialize(roles, "root", address(mockChildERC20Bridge), address(mockChildAxelarGasService)); + newAdaptor.initialize( + roles, + ROOT_CHAIN_NAME, + ROOT_BRIDGE_ADAPTOR, + address(mockChildERC20Bridge), + address(mockChildAxelarGasService) + ); } function test_RevertIf_InitializeWithZeroBridgeManager() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); roles.bridgeManager = address(0); - newAdaptor.initialize(roles, "root", address(mockChildERC20Bridge), address(mockChildAxelarGasService)); + newAdaptor.initialize( + roles, + ROOT_CHAIN_NAME, + ROOT_BRIDGE_ADAPTOR, + address(mockChildERC20Bridge), + address(mockChildAxelarGasService) + ); } function test_RevertIf_InitializeWithZeroGasServiceManager() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); roles.gasServiceManager = address(0); - newAdaptor.initialize(roles, "root", address(mockChildERC20Bridge), address(mockChildAxelarGasService)); + newAdaptor.initialize( + roles, + ROOT_CHAIN_NAME, + ROOT_BRIDGE_ADAPTOR, + address(mockChildERC20Bridge), + address(mockChildAxelarGasService) + ); } function test_RevertIf_InitializeWithZeroTargetManager() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); roles.targetManager = address(0); - newAdaptor.initialize(roles, "root", address(mockChildERC20Bridge), address(mockChildAxelarGasService)); + newAdaptor.initialize( + roles, + ROOT_CHAIN_NAME, + ROOT_BRIDGE_ADAPTOR, + address(mockChildERC20Bridge), + address(mockChildAxelarGasService) + ); } function test_RevertIf_InitializeGivenZeroAddress() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); - newAdaptor.initialize(roles, "root", address(0), address(mockChildAxelarGasService)); + newAdaptor.initialize( + roles, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, address(0), address(mockChildAxelarGasService) + ); } function test_RevertIf_InitializeGivenEmptyRootChain() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(InvalidRootChain.selector); - newAdaptor.initialize(roles, "", address(mockChildERC20Bridge), address(mockChildAxelarGasService)); + newAdaptor.initialize( + roles, "", ROOT_BRIDGE_ADAPTOR, address(mockChildERC20Bridge), address(mockChildAxelarGasService) + ); + } + + function test_RevertIf_InitializeGivenAnEmptyBridgeAdaptorString() public { + ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); + vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector); + newAdaptor.initialize( + roles, ROOT_CHAIN_NAME, "", address(mockChildERC20Bridge), address(mockChildAxelarGasService) + ); } function test_RevertIf_InitializeGivenZeroGasService() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); - newAdaptor.initialize(roles, "root", address(mockChildERC20Bridge), address(0)); + newAdaptor.initialize(roles, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, address(mockChildERC20Bridge), address(0)); } /** * EXECUTE */ + function test_RevertIf_executeCalledWithInvalidSourceChain() public { + bytes32 commandId = bytes32("testCommandId"); + bytes memory payload = abi.encodePacked("payload"); + + vm.expectRevert(InvalidSourceChain.selector); + axelarAdaptor.execute(commandId, "Invalid-Source-Chain", ROOT_BRIDGE_ADAPTOR, payload); + } + + function test_RevertIf_executeCalledWithInvalidSourceAddress() public { + bytes32 commandId = bytes32("testCommandId"); + bytes memory payload = abi.encodePacked("payload"); + + vm.expectRevert(InvalidSourceAddress.selector); + axelarAdaptor.execute(commandId, ROOT_CHAIN_NAME, "invalid-source-address", payload); + } + function test_Execute_CallsBridge() public { bytes32 commandId = bytes32("testCommandId"); - string memory sourceChain = "test"; - string memory sourceAddress = Strings.toHexString(address(123)); bytes memory payload = abi.encodePacked("payload"); // We expect to call the bridge's onMessageReceive function. vm.expectCall( address(mockChildERC20Bridge), - abi.encodeWithSelector(mockChildERC20Bridge.onMessageReceive.selector, sourceChain, sourceAddress, payload) + abi.encodeWithSelector(mockChildERC20Bridge.onMessageReceive.selector, payload) ); - axelarAdaptor.execute(commandId, sourceChain, sourceAddress, payload); + axelarAdaptor.execute(commandId, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, payload); } function test_Execute_EmitsAdaptorExecuteEvent() public { bytes32 commandId = bytes32("testCommandId"); - string memory sourceChain = "test"; - string memory sourceAddress = Strings.toHexString(address(123)); bytes memory payload = abi.encodePacked("payload"); // We expect to call the bridge's onMessageReceive function. vm.expectEmit(); - emit AdaptorExecute(sourceChain, sourceAddress, payload); - axelarAdaptor.execute(commandId, sourceChain, sourceAddress, payload); + emit AdaptorExecute(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, payload); + axelarAdaptor.execute(commandId, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, payload); } /** @@ -162,7 +216,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro mockChildAxelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), ROOT_CHAIN_NAME, - mockChildERC20Bridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootBridgeAdaptor(), payload, refundRecipient ) @@ -182,7 +236,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro abi.encodeWithSelector( mockChildAxelarGateway.callContract.selector, ROOT_CHAIN_NAME, - mockChildERC20Bridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootBridgeAdaptor(), payload ) ); @@ -197,7 +251,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro uint256 callValue = 300; vm.expectEmit(); - emit AxelarMessageSent(ROOT_CHAIN_NAME, mockChildERC20Bridge.rootERC20BridgeAdaptor(), payload); + emit AxelarMessageSent(ROOT_CHAIN_NAME, axelarAdaptor.rootBridgeAdaptor(), payload); vm.deal(address(mockChildERC20Bridge), callValue); vm.prank(address(mockChildERC20Bridge)); @@ -238,7 +292,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro mockChildAxelarGasService.payNativeGasForContractCall.selector, address(axelarAdaptor), ROOT_CHAIN_NAME, - mockChildERC20Bridge.rootERC20BridgeAdaptor(), + axelarAdaptor.rootBridgeAdaptor(), payload, refundRecipient ) @@ -317,7 +371,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro vm.startPrank(targetManager); string memory newRootChain = "newRoot"; axelarAdaptor.updateRootChain(newRootChain); - assertEq(axelarAdaptor.rootChain(), newRootChain, "rootChain not updated"); + assertEq(axelarAdaptor.rootChainId(), newRootChain, "rootChain not updated"); vm.stopPrank(); } @@ -350,6 +404,51 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro vm.stopPrank(); } + /** + * UPDATE ROOT BRIDGE ADAPTOR + */ + + function test_updateRootBridgeAdaptor_UpdatesRootBridgeAdaptor() public { + vm.startPrank(targetManager); + string memory newAdaptor = "newAdaptor"; + + assertEq(axelarAdaptor.rootBridgeAdaptor(), ROOT_BRIDGE_ADAPTOR, "rootBridgeAdaptor not set"); + axelarAdaptor.updateRootBridgeAdaptor(newAdaptor); + assertEq(axelarAdaptor.rootBridgeAdaptor(), newAdaptor, "rootBridgeAdaptor not updated"); + } + + function test_updateRootBridgeAdaptor_EmitsEvent() public { + vm.startPrank(targetManager); + + string memory newAdaptor = "newAdaptor"; + vm.expectEmit(true, true, false, false, address(axelarAdaptor)); + emit RootBridgeAdaptorUpdated(axelarAdaptor.rootBridgeAdaptor(), newAdaptor); + + axelarAdaptor.updateRootBridgeAdaptor(newAdaptor); + } + + function test_RevertIf_updateRootBridgeAdaptorCalledByNotTargetManager() public { + address caller = address(0xf00f00); + vm.startPrank(caller); + + bytes32 role = axelarAdaptor.TARGET_MANAGER_ROLE(); + vm.expectRevert( + abi.encodePacked( + "AccessControl: account ", + StringsUpgradeable.toHexString(caller), + " is missing role ", + StringsUpgradeable.toHexString(uint256(role), 32) + ) + ); + axelarAdaptor.updateRootBridgeAdaptor("newAdaptor"); + } + + function test_RevertIf_updateRootBridgeAdaptorCalledWithEmptyString() public { + vm.startPrank(targetManager); + vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector); + axelarAdaptor.updateRootBridgeAdaptor(""); + } + /** * UPDATE GAS SERVICE */ diff --git a/test/unit/child/ChildERC20Bridge.t.sol b/test/unit/child/ChildERC20Bridge.t.sol index d7d24400..76a5ffa2 100644 --- a/test/unit/child/ChildERC20Bridge.t.sol +++ b/test/unit/child/ChildERC20Bridge.t.sol @@ -16,8 +16,6 @@ import {Utils, IPausable} from "../../utils.t.sol"; contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { address constant ROOT_BRIDGE = address(3); - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant CHILD_WIMX_TOKEN = address(0xabc); address constant NATIVE_ETH = address(0xeee); @@ -45,15 +43,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B childBridge = new ChildERC20Bridge(); - childBridge.initialize( - roles, - address(this), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - CHILD_WIMX_TOKEN - ); + childBridge.initialize(roles, address(this), address(childTokenTemplate), ROOT_IMX_TOKEN, CHILD_WIMX_TOKEN); } /** @@ -64,7 +54,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B address caller = address(0x123a); payable(caller).transfer(2 ether); // forge inspect src/child/ChildERC20Bridge.sol:ChildERC20Bridge storageLayout | grep -B3 -A5 -i "wIMXToken" - uint256 wIMXStorageSlot = 258; + uint256 wIMXStorageSlot = 256; vm.store(address(childBridge), bytes32(wIMXStorageSlot), bytes32(uint256(uint160(caller)))); vm.startPrank(caller); @@ -145,9 +135,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B function test_Initialize() public { assertEq(address(childBridge.bridgeAdaptor()), address(address(this)), "bridgeAdaptor not set"); - assertEq(childBridge.rootERC20BridgeAdaptor(), ROOT_BRIDGE_ADAPTOR, "rootERC20BridgeAdaptor not set"); assertEq(childBridge.childTokenTemplate(), address(childTokenTemplate), "childTokenTemplate not set"); - assertEq(childBridge.rootChain(), ROOT_CHAIN_NAME, "rootChain not set"); assertEq(childBridge.rootIMXToken(), ROOT_IMX_TOKEN, "rootIMXToken not set"); assertTrue(childBridge.hasRole(childBridge.ADAPTOR_MANAGER_ROLE(), address(this)), "adaptorManager not set"); assertTrue(childBridge.hasRole(childBridge.PAUSER_ROLE(), pauser), "pauser not set"); @@ -159,62 +147,54 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B function test_RevertIfInitializeTwice() public { vm.expectRevert("Initializable: contract is already initialized"); - childBridge.initialize( - roles, - address(this), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - CHILD_WIMX_TOKEN - ); + childBridge.initialize(roles, address(this), address(childTokenTemplate), ROOT_IMX_TOKEN, CHILD_WIMX_TOKEN); } function test_RevertIf_InitializeWithAZeroAddressDefaultAdmin() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); roles.defaultAdmin = address(0); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(roles, address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(roles, address(1), address(1), address(1), address(1)); } function test_RevertIf_InitializeWithAZeroAddressPauser() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); roles.pauser = address(0); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(roles, address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(roles, address(1), address(1), address(1), address(1)); } function test_RevertIf_InitializeWithAZeroAddressUnpauser() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); roles.unpauser = address(0); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(roles, address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(roles, address(1), address(1), address(1), address(1)); } function test_RevertIf_InitializeWithAZeroAddressAdapter() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); roles.adaptorManager = address(0); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(roles, address(0), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(roles, address(0), address(1), address(1), address(1)); } function test_RevertIf_InitializeWithAZeroAddressTreasuryManager() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); roles.treasuryManager = address(0); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(roles, address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(roles, address(1), address(1), address(1), address(1)); } function test_RevertIf_InitializeWithAZeroAddressChildTemplate() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(roles, address(1), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(1), address(1)); + bridge.initialize(roles, address(1), address(0), address(1), address(1)); } function test_RevertIf_InitializeWithAZeroAddressIMXToken() public { ChildERC20Bridge bridge = new ChildERC20Bridge(); vm.expectRevert(ZeroAddress.selector); - bridge.initialize(roles, address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(0), address(1)); + bridge.initialize(roles, address(1), address(1), address(0), address(1)); } function test_RevertIf_InitializeWithAZeroAddressAll() public { @@ -225,23 +205,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B roles.unpauser = address(0); roles.adaptorManager = address(0); roles.treasuryManager = address(0); - bridge.initialize(roles, address(0), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(0), address(0)); - } - - function test_RevertIf_InitializeWithAnEmptyBridgeAdaptorString() public { - ChildERC20Bridge bridge = new ChildERC20Bridge(); - vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector); - bridge.initialize( - roles, address(this), "", address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN, CHILD_WIMX_TOKEN - ); - } - - function test_RevertIf_InitializeWithAnEmptyChainNameString() public { - ChildERC20Bridge bridge = new ChildERC20Bridge(); - vm.expectRevert(InvalidRootChain.selector); - bridge.initialize( - roles, address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), "", ROOT_IMX_TOKEN, CHILD_WIMX_TOKEN - ); + bridge.initialize(roles, address(0), address(0), address(0), address(0)); } function test_onMessageReceive_EmitsTokenMappedEvent() public { @@ -256,7 +220,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B vm.expectEmit(true, true, false, false, address(childBridge)); emit L2TokenMapped(address(rootToken), predictedChildToken); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); } /** @@ -300,47 +264,6 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B childBridge.updateChildBridgeAdaptor(address(0)); } - /** - * UPDATE ROOT BRIDGE ADAPTOR - */ - - function test_updateRootBridgeAdaptor_UpdatesRootBridgeAdaptor() public { - string memory newAdaptor = "newAdaptor"; - - assertEq(childBridge.rootERC20BridgeAdaptor(), ROOT_BRIDGE_ADAPTOR, "rootERC20BridgeAdaptor not set"); - childBridge.updateRootBridgeAdaptor(newAdaptor); - assertEq(childBridge.rootERC20BridgeAdaptor(), newAdaptor, "rootERC20BridgeAdaptor not updated"); - } - - function test_updateRootBridgeAdaptor_EmitsEvent() public { - string memory newAdaptor = "newAdaptor"; - - vm.expectEmit(true, true, false, false, address(childBridge)); - emit RootBridgeAdaptorUpdated(childBridge.rootERC20BridgeAdaptor(), newAdaptor); - - childBridge.updateRootBridgeAdaptor(newAdaptor); - } - - function test_RevertIf_updateRootBridgeAdaptorCalledByNotAdaptorManager() public { - address caller = address(0xf00f00); - bytes32 role = childBridge.ADAPTOR_MANAGER_ROLE(); - vm.prank(caller); - vm.expectRevert( - abi.encodePacked( - "AccessControl: account ", - StringsUpgradeable.toHexString(caller), - " is missing role ", - StringsUpgradeable.toHexString(uint256(role), 32) - ) - ); - childBridge.updateRootBridgeAdaptor("newAdaptor"); - } - - function test_RevertIf_updateRootBridgeAdaptorCalledWithEmptyString() public { - vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector); - childBridge.updateRootBridgeAdaptor(""); - } - /** * ON MESSAGE RECIEVE */ @@ -354,7 +277,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B childBridge.MAP_TOKEN_SIG(), address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals() ); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); assertEq( childBridge.rootTokenToChildToken(address(rootToken)), predictedChildToken, @@ -371,7 +294,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B childBridge.MAP_TOKEN_SIG(), address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals() ); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); assertEq(ChildERC20(predictedChildToken).symbol(), rootToken.symbol(), "token symbol not set"); } @@ -383,31 +306,13 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B vm.expectRevert(NotBridgeAdaptor.selector); vm.prank(address(123)); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); - } - - function test_RevertIf_onMessageReceiveCalledWithSourceChainNotRootChain() public { - bytes memory data = abi.encode( - childBridge.MAP_TOKEN_SIG(), address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals() - ); - - vm.expectRevert(InvalidSourceChain.selector); - childBridge.onMessageReceive("FAKE_CHAIN", ROOT_BRIDGE_ADAPTOR, data); - } - - function test_RevertIf_onMessageReceiveCalledWithSourceAddressNotRootAdaptor() public { - bytes memory data = abi.encode( - childBridge.MAP_TOKEN_SIG(), address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals() - ); - - vm.expectRevert(InvalidSourceAddress.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, Strings.toHexString(address(456)), data); + childBridge.onMessageReceive(data); } function test_RevertIf_onMessageReceiveCalledWithDataLengthZero() public { bytes memory data = ""; vm.expectRevert(abi.encodeWithSelector(InvalidData.selector, "Data too short")); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); } function test_RevertIf_onMessageReceiveCalledWithDataInvalid() public { @@ -415,7 +320,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B abi.encode("FAKEDATA", address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals()); vm.expectRevert(abi.encodeWithSelector(InvalidData.selector, "Unsupported action signature")); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); } function test_RevertIf_onMessageReceiveCalledWithZeroAddress() public { @@ -424,28 +329,28 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B ); vm.expectRevert(ZeroAddress.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); } function test_RevertIf_mapTokenCalledWithIMXAddress() public { bytes memory data = abi.encode(childBridge.MAP_TOKEN_SIG(), ROOT_IMX_TOKEN, "ImmutableX", "IMX", 18); vm.expectRevert(CantMapIMX.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(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); + childBridge.onMessageReceive(data); } function test_RevertIf_onMessageReceiveCalledTwice() public { bytes memory data = abi.encode( childBridge.MAP_TOKEN_SIG(), address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals() ); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); vm.expectRevert(AlreadyMapped.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); } /** @@ -457,7 +362,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B bytes memory depositData = abi.encode(childBridge.DEPOSIT_SIG(), address(NATIVE_ETH), address(100), address(200), 1000); vm.expectRevert("Pausable: paused"); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } function test_OnMessageReceiveResumesFunctionalityAfterUnpausing() public { @@ -480,7 +385,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B vm.expectEmit(address(childBridge)); emit NativeEthDeposit(address(NATIVE_ETH), predictedChildETHToken, sender, receiver, amount); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } function test_onMessageReceive_DepositETH_TransfersTokensToReceiver() public { @@ -496,7 +401,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B uint256 receiverPreBal = ChildERC20(predictedChildETHToken).balanceOf(receiver); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); assertEq( ChildERC20(predictedChildETHToken).balanceOf(receiver), @@ -517,7 +422,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B ); uint256 totalSupplyPre = ChildERC20(predictedChildETHToken).totalSupply(); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); assertEq(ChildERC20(predictedChildETHToken).totalSupply(), totalSupplyPre + amount, "totalSupply not increased"); } @@ -538,7 +443,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B vm.expectEmit(address(childBridge)); emit IMXDeposit(ROOT_IMX_TOKEN, sender, receiver, amount); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } function test_onMessageReceive_DepositIMX_BalancesChanged() public { @@ -551,7 +456,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B bytes memory depositData = abi.encode(childBridge.DEPOSIT_SIG(), ROOT_IMX_TOKEN, sender, receiver, amount); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); assertEq(address(childBridge).balance, fundedAmount - amount, "contract balance not decreased"); assertEq(receiver.balance, amount, "receiver balance not increased"); @@ -568,11 +473,11 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B bytes memory depositData = abi.encode(childBridge.DEPOSIT_SIG(), ROOT_IMX_TOKEN, sender, receiver, amount); vm.expectRevert("Address: insufficient balance"); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } function test_onMessageReceive_Deposit_EmitsChildChainERC20DepositEvent() public { - setupChildDeposit(rootToken, childBridge, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR); + setupChildDeposit(rootToken, childBridge); address sender = address(100); address receiver = address(200); @@ -584,11 +489,11 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B vm.expectEmit(address(childBridge)); emit ChildChainERC20Deposit(address(rootToken), childToken, sender, receiver, amount); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } function test_onMessageReceive_Deposit_TransfersTokensToReceiver() public { - setupChildDeposit(rootToken, childBridge, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR); + setupChildDeposit(rootToken, childBridge); address sender = address(100); address receiver = address(200); @@ -600,13 +505,13 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B uint256 receiverPreBal = ChildERC20(childTokenTemplate).balanceOf(receiver); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); assertEq(ChildERC20(childToken).balanceOf(receiver), receiverPreBal + amount, "receiver balance not increased"); } function test_onMessageReceive_Deposit_IncreasesTotalSupply() public { - setupChildDeposit(rootToken, childBridge, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR); + setupChildDeposit(rootToken, childBridge); address sender = address(100); address receiver = address(200); @@ -618,7 +523,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B uint256 totalSupplyPre = ChildERC20(childToken).totalSupply(); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); assertEq(ChildERC20(childToken).totalSupply(), totalSupplyPre + amount, "totalSupply not increased"); } @@ -631,7 +536,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B bytes memory data = abi.encode(childBridge.DEPOSIT_SIG(), address(rootToken), sender, receiver, amount); vm.expectRevert(NotMapped.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data); + childBridge.onMessageReceive(data); } function test_RevertIf_onMessageReceive_Deposit_RootZeroAddress() public { @@ -642,7 +547,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B bytes memory depositData = abi.encode(childBridge.DEPOSIT_SIG(), address(0), sender, receiver, amount); vm.expectRevert(ZeroAddress.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } function test_RevertIf_onMessageReceive_Deposit_ReceiverZeroAddress() public { @@ -653,7 +558,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B bytes memory depositData = abi.encode(childBridge.DEPOSIT_SIG(), address(rootToken), sender, receiver, amount); vm.expectRevert(ZeroAddress.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } function test_RevertIf_onMessageReceive_DepositWithEmptyContract() public { @@ -674,6 +579,6 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B bytes memory depositData = abi.encode(childBridge.DEPOSIT_SIG(), rootAddress, sender, receiver, amount); vm.expectRevert(EmptyTokenContract.selector); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, depositData); + childBridge.onMessageReceive(depositData); } } diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdraw.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdraw.t.sol index 66444daa..7e993639 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdraw.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdraw.t.sol @@ -15,8 +15,6 @@ import {Utils, IPausable} from "../../../utils.t.sol"; contract ChildERC20BridgeWithdrawUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { address constant ROOT_BRIDGE = address(3); - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant NATIVE_ETH = address(0xeee); address constant WIMX_TOKEN_ADDRESS = address(0xabc); @@ -45,20 +43,14 @@ contract ChildERC20BridgeWithdrawUnitTest is Test, IChildERC20BridgeEvents, IChi }); childBridge = new ChildERC20Bridge(); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - WIMX_TOKEN_ADDRESS + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, WIMX_TOKEN_ADDRESS ); bytes memory mapTokenData = abi.encode(MAP_TOKEN_SIG, rootToken, rootToken.name(), rootToken.symbol(), rootToken.decimals()); vm.prank(address(mockAdaptor)); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, mapTokenData); + childBridge.onMessageReceive(mapTokenData); childToken = ChildERC20(childBridge.rootTokenToChildToken(address(rootToken))); vm.prank(address(childBridge)); diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETH.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETH.t.sol index 15e7dabb..d86c22eb 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETH.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETH.t.sol @@ -15,8 +15,6 @@ import {MockAdaptor} from "../../../mocks/root/MockAdaptor.sol"; import {Utils, IPausable} from "../../../utils.t.sol"; contract ChildERC20BridgeWithdrawETHUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant NATIVE_ETH = address(0xeee); address constant WIMX_TOKEN_ADDRESS = address(0xabc); @@ -39,13 +37,7 @@ contract ChildERC20BridgeWithdrawETHUnitTest is Test, IChildERC20BridgeEvents, I treasuryManager: address(this) }); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - WIMX_TOKEN_ADDRESS + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, WIMX_TOKEN_ADDRESS ); childETHToken = ChildERC20(childBridge.childETHToken()); diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETHTo.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETHTo.t.sol index a9ee0538..8647cee2 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETHTo.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawETHTo.t.sol @@ -18,8 +18,6 @@ import {Utils, IPausable} from "../../../utils.t.sol"; contract ChildERC20BridgeWithdrawETHToUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { address constant ROOT_BRIDGE = address(3); - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant NATIVE_ETH = address(0xeee); address constant WIMX_TOKEN_ADDRESS = address(0xabc); @@ -48,20 +46,14 @@ contract ChildERC20BridgeWithdrawETHToUnitTest is Test, IChildERC20BridgeEvents, treasuryManager: address(this) }); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - WIMX_TOKEN_ADDRESS + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, WIMX_TOKEN_ADDRESS ); bytes memory mapTokenData = abi.encode(MAP_TOKEN_SIG, rootToken, rootToken.name(), rootToken.symbol(), rootToken.decimals()); vm.prank(address(mockAdaptor)); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, mapTokenData); + childBridge.onMessageReceive(mapTokenData); childToken = ChildERC20(childBridge.rootTokenToChildToken(address(rootToken))); vm.prank(address(childBridge)); diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMX.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMX.t.sol index 6f75801c..89ac15f0 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMX.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMX.t.sol @@ -15,8 +15,6 @@ import {Utils, IPausable} from "../../../utils.t.sol"; contract ChildERC20BridgeWithdrawIMXUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { address constant ROOT_BRIDGE = address(3); - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant WIMX_TOKEN_ADDRESS = address(0xabc); ChildERC20 public childTokenTemplate; @@ -38,13 +36,7 @@ contract ChildERC20BridgeWithdrawIMXUnitTest is Test, IChildERC20BridgeEvents, I treasuryManager: address(this) }); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - WIMX_TOKEN_ADDRESS + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, WIMX_TOKEN_ADDRESS ); } diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMXTo.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMXTo.t.sol index fc55abb4..92ac5937 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMXTo.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawIMXTo.t.sol @@ -15,8 +15,6 @@ import {Utils, IPausable} from "../../../utils.t.sol"; contract ChildERC20BridgeWithdrawIMXToUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { address constant ROOT_BRIDGE = address(3); - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant WIMX_TOKEN_ADDRESS = address(0xabc); address constant NATIVE_ETH = address(0xeee); @@ -42,13 +40,7 @@ contract ChildERC20BridgeWithdrawIMXToUnitTest is Test, IChildERC20BridgeEvents, treasuryManager: address(this) }); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - WIMX_TOKEN_ADDRESS + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, WIMX_TOKEN_ADDRESS ); } diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawTo.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawTo.t.sol index 2d293748..a239e86e 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawTo.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawTo.t.sol @@ -15,8 +15,6 @@ import {Utils, IPausable} from "../../../utils.t.sol"; contract ChildERC20BridgeWithdrawToUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { address constant ROOT_BRIDGE = address(3); - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant WIMX_TOKEN_ADDRESS = address(0xabc); address constant NATIVE_ETH = address(0xeee); @@ -45,20 +43,14 @@ contract ChildERC20BridgeWithdrawToUnitTest is Test, IChildERC20BridgeEvents, IC }); childBridge = new ChildERC20Bridge(); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - WIMX_TOKEN_ADDRESS + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, WIMX_TOKEN_ADDRESS ); bytes memory mapTokenData = abi.encode(MAP_TOKEN_SIG, rootToken, rootToken.name(), rootToken.symbol(), rootToken.decimals()); vm.prank(address(mockAdaptor)); - childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, mapTokenData); + childBridge.onMessageReceive(mapTokenData); childToken = ChildERC20(childBridge.rootTokenToChildToken(address(rootToken))); vm.prank(address(childBridge)); diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMX.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMX.t.sol index b6df68f9..aadb70e0 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMX.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMX.t.sol @@ -16,8 +16,6 @@ import {WIMX} from "../../../../src/child/WIMX.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; contract ChildERC20BridgeWithdrawWIMXUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); ChildERC20 public childTokenTemplate; ChildERC20Bridge public childBridge; @@ -42,13 +40,7 @@ contract ChildERC20BridgeWithdrawWIMXUnitTest is Test, IChildERC20BridgeEvents, treasuryManager: address(this) }); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - address(wIMXToken) + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, address(wIMXToken) ); } diff --git a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMXTo.t.sol b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMXTo.t.sol index 213a9a60..d61deb94 100644 --- a/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMXTo.t.sol +++ b/test/unit/child/withdrawals/ChildERC20BridgeWithdrawWIMXTo.t.sol @@ -17,8 +17,6 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; contract ChildERC20BridgeWithdrawWIMXToUnitTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils { address constant ROOT_BRIDGE = address(3); - string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4)); - string constant ROOT_CHAIN_NAME = "test"; address constant ROOT_IMX_TOKEN = address(0xccc); address constant WIMX_TOKEN_ADDRESS = address(0xabc); ChildERC20 public childTokenTemplate; @@ -44,13 +42,7 @@ contract ChildERC20BridgeWithdrawWIMXToUnitTest is Test, IChildERC20BridgeEvents treasuryManager: address(this) }); childBridge.initialize( - roles, - address(mockAdaptor), - ROOT_BRIDGE_ADAPTOR, - address(childTokenTemplate), - ROOT_CHAIN_NAME, - ROOT_IMX_TOKEN, - address(wIMXToken) + roles, address(mockAdaptor), address(childTokenTemplate), ROOT_IMX_TOKEN, address(wIMXToken) ); } diff --git a/test/utils.t.sol b/test/utils.t.sol index 512b91cf..0acc2b2b 100644 --- a/test/utils.t.sol +++ b/test/utils.t.sol @@ -75,9 +75,7 @@ contract Utils is Test { adaptorManager: address(this), treasuryManager: address(this) }); - childBridge.initialize( - roles, address(childBridgeAdaptor), rootAdaptor, address(childTokenTemplate), "ROOT", rootIMX, childWIMX - ); + childBridge.initialize(roles, address(childBridgeAdaptor), address(childTokenTemplate), rootIMX, childWIMX); IChildAxelarBridgeAdaptor.InitializationRoles memory adaptorRoles = IChildAxelarBridgeAdaptor .InitializationRoles({ @@ -87,11 +85,13 @@ contract Utils is Test { targetManager: address(this) }); - childBridgeAdaptor.initialize(adaptorRoles, "ROOT", address(childBridge), address(axelarGasService)); + childBridgeAdaptor.initialize( + adaptorRoles, "ROOT", rootAdaptor, address(childBridge), address(axelarGasService) + ); bytes memory mapTokenData = abi.encode(MAP_TOKEN_SIG, rootToken, "TEST NAME", "TNM", 18); vm.prank(address(childBridgeAdaptor)); - childBridge.onMessageReceive("ROOT", rootAdaptor, mapTokenData); + childBridge.onMessageReceive(mapTokenData); ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(address(rootToken))); vm.prank(address(childBridge)); @@ -218,19 +218,14 @@ contract Utils is Test { return (childToken, predictedPayload); } - function setupChildDeposit( - ChildERC20 token, - ChildERC20Bridge childBridge, - string memory sourceChain, - string memory sourceAddress - ) public { + function setupChildDeposit(ChildERC20 token, ChildERC20Bridge childBridge) public { string memory name = token.name(); string memory symbol = token.symbol(); uint8 decimals = token.decimals(); bytes memory payload = abi.encode(childBridge.MAP_TOKEN_SIG(), address(token), name, symbol, decimals); - childBridge.onMessageReceive(sourceChain, sourceAddress, payload); + childBridge.onMessageReceive(payload); } function getMappingStorageSlotFor(address key, uint256 position) public pure returns (bytes32 slot) { From ee6653aa143883ca2d54df338ffa12d63556be07 Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 23 Nov 2023 04:49:13 +1100 Subject: [PATCH 3/7] Rename bridge adaptor interfaces --- src/child/ChildAxelarBridgeAdaptor.sol | 6 +++--- src/child/ChildERC20Bridge.sol | 8 ++++---- ...hildERC20BridgeAdaptor.sol => IChildBridgeAdaptor.sol} | 3 +-- ...IRootERC20BridgeAdaptor.sol => IRootBridgeAdaptor.sol} | 2 +- src/root/RootAxelarBridgeAdaptor.sol | 6 +++--- src/root/RootERC20Bridge.sol | 8 ++++---- 6 files changed, 16 insertions(+), 17 deletions(-) rename src/interfaces/child/{IChildERC20BridgeAdaptor.sol => IChildBridgeAdaptor.sol} (85%) rename src/interfaces/root/{IRootERC20BridgeAdaptor.sol => IRootBridgeAdaptor.sol} (96%) diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index b7bdae57..198ace2f 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -11,7 +11,7 @@ import { IChildAxelarBridgeAdaptorEvents, IChildAxelarBridgeAdaptor } from "../interfaces/child/IChildAxelarBridgeAdaptor.sol"; -import {IChildERC20BridgeAdaptor} from "../interfaces/child/IChildERC20BridgeAdaptor.sol"; +import {IChildBridgeAdaptor} from "../interfaces/child/IChildBridgeAdaptor.sol"; import {AdaptorRoles} from "../common/AdaptorRoles.sol"; /** @@ -32,7 +32,7 @@ import {AdaptorRoles} from "../common/AdaptorRoles.sol"; contract ChildAxelarBridgeAdaptor is AdaptorRoles, AxelarExecutable, - IChildERC20BridgeAdaptor, + IChildBridgeAdaptor, IChildAxelarBridgeAdaptorErrors, IChildAxelarBridgeAdaptorEvents, IChildAxelarBridgeAdaptor @@ -141,7 +141,7 @@ contract ChildAxelarBridgeAdaptor is } /** - * @inheritdoc IChildERC20BridgeAdaptor + * @inheritdoc IChildBridgeAdaptor */ function sendMessage(bytes calldata payload, address refundRecipient) external payable override { if (msg.value == 0) { diff --git a/src/child/ChildERC20Bridge.sol b/src/child/ChildERC20Bridge.sol index c1ec8153..dd34d87a 100644 --- a/src/child/ChildERC20Bridge.sol +++ b/src/child/ChildERC20Bridge.sol @@ -9,7 +9,7 @@ import { IChildERC20BridgeErrors, IChildERC20Bridge } from "../interfaces/child/IChildERC20Bridge.sol"; -import {IChildERC20BridgeAdaptor} from "../interfaces/child/IChildERC20BridgeAdaptor.sol"; +import {IChildBridgeAdaptor} from "../interfaces/child/IChildBridgeAdaptor.sol"; import {IChildERC20} from "../interfaces/child/IChildERC20.sol"; import {IWIMX} from "../interfaces/child/IWIMX.sol"; import {BridgeRoles} from "../common/BridgeRoles.sol"; @@ -52,7 +52,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br address public constant NATIVE_ETH = address(0xeee); address public constant NATIVE_IMX = address(0xfff); - IChildERC20BridgeAdaptor public bridgeAdaptor; + IChildBridgeAdaptor public bridgeAdaptor; /// @dev The address of the token template that will be cloned to create tokens. address public childTokenTemplate; @@ -98,7 +98,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br _grantRole(TREASURY_MANAGER_ROLE, newRoles.treasuryManager); childTokenTemplate = newChildTokenTemplate; - bridgeAdaptor = IChildERC20BridgeAdaptor(newBridgeAdaptor); + bridgeAdaptor = IChildBridgeAdaptor(newBridgeAdaptor); rootIMXToken = newRootIMXToken; wIMXToken = newWIMXToken; @@ -145,7 +145,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br } emit ChildBridgeAdaptorUpdated(address(bridgeAdaptor), newBridgeAdaptor); - bridgeAdaptor = IChildERC20BridgeAdaptor(newBridgeAdaptor); + bridgeAdaptor = IChildBridgeAdaptor(newBridgeAdaptor); } /** diff --git a/src/interfaces/child/IChildERC20BridgeAdaptor.sol b/src/interfaces/child/IChildBridgeAdaptor.sol similarity index 85% rename from src/interfaces/child/IChildERC20BridgeAdaptor.sol rename to src/interfaces/child/IChildBridgeAdaptor.sol index 139e61f2..cb511061 100644 --- a/src/interfaces/child/IChildERC20BridgeAdaptor.sol +++ b/src/interfaces/child/IChildBridgeAdaptor.sol @@ -7,9 +7,8 @@ pragma solidity 0.8.19; * @notice Defines the functions that can be used be used by a Child ERC20 Bridge to send messages through an underlying GMP * @dev This interface abstracts the details of the underlying General Purpose Message Passing protocol. * This minimizes changes to the interface consumer if the underlying GMP is changed in the future. - * In addition, this interface is not specific to an ERC20 bridge, and will likely eventually be renamed to be more generic. */ -interface IChildERC20BridgeAdaptor { +interface IChildBridgeAdaptor { /** * @notice Send an arbitrary message to the root chain via the message passing protocol. * @param payload The message to send, encoded in a `bytes` array. diff --git a/src/interfaces/root/IRootERC20BridgeAdaptor.sol b/src/interfaces/root/IRootBridgeAdaptor.sol similarity index 96% rename from src/interfaces/root/IRootERC20BridgeAdaptor.sol rename to src/interfaces/root/IRootBridgeAdaptor.sol index 902b1c84..1389b820 100644 --- a/src/interfaces/root/IRootERC20BridgeAdaptor.sol +++ b/src/interfaces/root/IRootBridgeAdaptor.sol @@ -9,7 +9,7 @@ pragma solidity 0.8.19; * This minimizes changes to the interface consumer if the underlying GMP is changed in the future. * In addition, this interface is not specific to an ERC20 bridge, and will likely eventually be renamed to be more generic. */ -interface IRootERC20BridgeAdaptor { +interface IRootBridgeAdaptor { /** * @notice Send an arbitrary message to the child chain via the message passing protocol. * @param payload The message to send, encoded in a `bytes` array. diff --git a/src/root/RootAxelarBridgeAdaptor.sol b/src/root/RootAxelarBridgeAdaptor.sol index 374f8e59..f872d449 100644 --- a/src/root/RootAxelarBridgeAdaptor.sol +++ b/src/root/RootAxelarBridgeAdaptor.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.19; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {AxelarExecutable} from "@axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol"; import {IAxelarGasService} from "@axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol"; -import {IRootERC20BridgeAdaptor} from "../interfaces/root/IRootERC20BridgeAdaptor.sol"; +import {IRootBridgeAdaptor} from "../interfaces/root/IRootBridgeAdaptor.sol"; import { IRootAxelarBridgeAdaptorEvents, IRootAxelarBridgeAdaptorErrors, @@ -33,7 +33,7 @@ import {AdaptorRoles} from "../common/AdaptorRoles.sol"; contract RootAxelarBridgeAdaptor is AdaptorRoles, AxelarExecutable, - IRootERC20BridgeAdaptor, + IRootBridgeAdaptor, IRootAxelarBridgeAdaptorEvents, IRootAxelarBridgeAdaptorErrors, IRootAxelarBridgeAdaptor @@ -144,7 +144,7 @@ contract RootAxelarBridgeAdaptor is } /** - * @inheritdoc IRootERC20BridgeAdaptor + * @inheritdoc IRootBridgeAdaptor */ function sendMessage(bytes calldata payload, address refundRecipient) external payable override { if (msg.value == 0) { diff --git a/src/root/RootERC20Bridge.sol b/src/root/RootERC20Bridge.sol index 1321d1f1..dbc505ad 100644 --- a/src/root/RootERC20Bridge.sol +++ b/src/root/RootERC20Bridge.sol @@ -13,7 +13,7 @@ import { IRootERC20BridgeEvents, IRootERC20BridgeErrors } from "../interfaces/root/IRootERC20Bridge.sol"; -import {IRootERC20BridgeAdaptor} from "../interfaces/root/IRootERC20BridgeAdaptor.sol"; +import {IRootBridgeAdaptor} from "../interfaces/root/IRootBridgeAdaptor.sol"; import {IWETH} from "../interfaces/root/IWETH.sol"; import {BridgeRoles} from "../common/BridgeRoles.sol"; @@ -60,7 +60,7 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent address public constant NATIVE_ETH = address(0xeee); address public constant NATIVE_IMX = address(0xfff); - IRootERC20BridgeAdaptor public rootBridgeAdaptor; + IRootBridgeAdaptor public rootBridgeAdaptor; /// @dev The address that will be minting tokens on the child chain. address public childERC20Bridge; /// @dev The address of the token template that will be cloned to create tokens on the child chain. @@ -150,7 +150,7 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent childETHToken = Clones.predictDeterministicAddress( childTokenTemplate, keccak256(abi.encodePacked(NATIVE_ETH)), childERC20Bridge ); - rootBridgeAdaptor = IRootERC20BridgeAdaptor(newRootBridgeAdaptor); + rootBridgeAdaptor = IRootBridgeAdaptor(newRootBridgeAdaptor); imxCumulativeDepositLimit = newImxCumulativeDepositLimit; } @@ -176,7 +176,7 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent revert ZeroAddress(); } emit RootBridgeAdaptorUpdated(address(rootBridgeAdaptor), newRootBridgeAdaptor); - rootBridgeAdaptor = IRootERC20BridgeAdaptor(newRootBridgeAdaptor); + rootBridgeAdaptor = IRootBridgeAdaptor(newRootBridgeAdaptor); } /** From 5baba4e40e8b931aa3bb8789208c54b2c7cb748f Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 23 Nov 2023 08:14:45 +1100 Subject: [PATCH 4/7] Rename adaptor error --- src/child/ChildAxelarBridgeAdaptor.sol | 17 ++++++++++++----- .../child/IChildAxelarBridgeAdaptor.sol | 2 +- .../root/IRootAxelarBridgeAdaptor.sol | 2 +- src/root/RootAxelarBridgeAdaptor.sol | 14 ++++++++++---- test/mocks/child/MockChildERC20Bridge.sol | 4 ---- test/unit/child/ChildAxelarBridgeAdaptor.t.sol | 4 ++-- test/unit/root/RootAxelarBridgeAdaptor.t.sol | 4 ++-- 7 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index 198ace2f..4f5e37aa 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -15,7 +15,8 @@ import {IChildBridgeAdaptor} from "../interfaces/child/IChildBridgeAdaptor.sol"; import {AdaptorRoles} from "../common/AdaptorRoles.sol"; /** - * @notice Facilitates communication between the ChildERC20Bridge and the Axelar Gateway. It enables sending and receiving messages to and from the root chain. + * @notice Facilitates communication between the ChildERC20Bridge and the Axelar core contracts,to send and receive messages to and from the root chain. + * @dev The contract ensures that any delivered message originated from the registered root chain and bridge adapter contract on the root chain. It will reject all other messages. * @dev Features: * - Send messages to the root chain via the Axelar Gateway. * - Receive messages from the root chain via the Axelar Gateway. @@ -77,7 +78,7 @@ contract ChildAxelarBridgeAdaptor is } if (bytes(_rootBridgeAdaptor).length == 0) { - revert InvalidRootERC20BridgeAdaptor(); + revert InvalidRootBridgeAdaptor(); } __AccessControl_init(); @@ -121,7 +122,7 @@ contract ChildAxelarBridgeAdaptor is */ function updateRootBridgeAdaptor(string memory newRootBridgeAdaptor) external onlyRole(TARGET_MANAGER_ROLE) { if (bytes(newRootBridgeAdaptor).length == 0) { - revert InvalidRootERC20BridgeAdaptor(); + revert InvalidRootBridgeAdaptor(); } emit RootBridgeAdaptorUpdated(rootBridgeAdaptor, newRootBridgeAdaptor); @@ -165,9 +166,15 @@ contract ChildAxelarBridgeAdaptor is /** * @dev This function is called by the parent `AxelarExecutable` contract to execute a message payload sent from the root chain. - * The function first validates the message by checking that it originated from the registered + * It is only called after the message has been validated by the Axelar core contracts. + * Validations include, ensuring that the Axelar validator set has signed the message and that the message has not been executed before. + * For more details see: + * - [AxelarExecutable.sol](https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/main/contracts/executable/AxelarExecutable.sol#L17), + * - [AxelarGateway.sol](https://github.com/axelarnetwork/axelar-cgp-solidity/blob/d4536599321774927bf9716178a9e360f8e0efac/contracts/AxelarGateway.sol#L233) + * + * @dev The function first validates the message by checking that it originated from the registered * root chain and bridge adaptor contract on the root chain. If not, the message is rejected. - * If a message is valid, it calls the root bridge contract's `onMessageReceive` function. + * If a message is valid, it calls the child bridge contract's `onMessageReceive` function. * @param _sourceChain The chain id that the message originated from. * @param _sourceAddress The contract address that sent the message on the source chain. * @param _payload The message payload. diff --git a/src/interfaces/child/IChildAxelarBridgeAdaptor.sol b/src/interfaces/child/IChildAxelarBridgeAdaptor.sol index 70b2d322..fe568c8a 100644 --- a/src/interfaces/child/IChildAxelarBridgeAdaptor.sol +++ b/src/interfaces/child/IChildAxelarBridgeAdaptor.sol @@ -46,7 +46,7 @@ interface IChildAxelarBridgeAdaptor { interface IChildAxelarBridgeAdaptorErrors { /// @notice Error when the given bridge adaptor is invalid. - error InvalidRootERC20BridgeAdaptor(); + error InvalidRootBridgeAdaptor(); /// @notice Error when a zero address is given when not valid. error ZeroAddress(); /// @notice Error when a message is sent with no gas payment. diff --git a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol index 6065c5e0..6ade4629 100644 --- a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol +++ b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol @@ -58,7 +58,7 @@ interface IRootAxelarBridgeAdaptorErrors { /// @notice Error when the contract calling the adaptor is not the bridge. error CallerNotBridge(); /// @notice Error when the given child chain bridge adaptor is invalid. - error InvalidChildERC20BridgeAdaptor(); + error InvalidChildBridgeAdaptor(); /// @notice Error when a message received has invalid source address. error InvalidSourceAddress(); /// @notice Error when a message received has invalid source chain. diff --git a/src/root/RootAxelarBridgeAdaptor.sol b/src/root/RootAxelarBridgeAdaptor.sol index f872d449..ec7c796f 100644 --- a/src/root/RootAxelarBridgeAdaptor.sol +++ b/src/root/RootAxelarBridgeAdaptor.sol @@ -15,7 +15,7 @@ import {IRootERC20Bridge} from "../interfaces/root/IRootERC20Bridge.sol"; import {AdaptorRoles} from "../common/AdaptorRoles.sol"; /** - * @notice Facilitates communication between the RootERC20Bridge and the Axelar Gateway. It enables sending and receiving messages to and from the child chain. + * @notice Facilitates communication between the RootERC20Bridge and the Axelar core contracts, to send and receive messages to and from the child chain. * @dev The contract ensures that any delivered message originated from the registered child chain and bridge adapter contract on the child chain. It will reject all other messages. * @dev Features: * - Send messages to the child chain via the Axelar Gateway. @@ -80,7 +80,7 @@ contract RootAxelarBridgeAdaptor is } if (bytes(_childBridgeAdaptor).length == 0) { - revert InvalidChildERC20BridgeAdaptor(); + revert InvalidChildBridgeAdaptor(); } __AccessControl_init(); @@ -125,7 +125,7 @@ contract RootAxelarBridgeAdaptor is */ function updateChildBridgeAdaptor(string memory newChildBridgeAdaptor) external onlyRole(TARGET_MANAGER_ROLE) { if (bytes(newChildBridgeAdaptor).length == 0) { - revert InvalidChildERC20BridgeAdaptor(); + revert InvalidChildBridgeAdaptor(); } emit ChildBridgeAdaptorUpdated(childBridgeAdaptor, newChildBridgeAdaptor); childBridgeAdaptor = newChildBridgeAdaptor; @@ -168,7 +168,13 @@ contract RootAxelarBridgeAdaptor is /** * @dev This function is called by the parent `AxelarExecutable` contract to execute a message payload sent from the child chain. - * The function first validates the message by checking that it originated from the registered + * It is only called after the message has been validated by the Axelar core contracts. + * Validations include, ensuring that the Axelar validator set has signed the message and that the message has not been executed before. + * For more details see: + * - [AxelarExecutable.sol](https://github.com/axelarnetwork/axelar-cgp-solidity/blob/d4536599321774927bf9716178a9e360f8e0efac/contracts/AxelarGateway.sol#L233), + * - [AxelarGateway.sol](https://github.com/axelarnetwork/axelar-cgp-solidity/blob/d4536599321774927bf9716178a9e360f8e0efac/contracts/AxelarGateway.sol#L233) + * + * @dev The function first validates the message by checking that it originated from the registered * child chain and bridge adaptor contract on the child chain. If not, the message is rejected. * If a message is valid, it calls the root bridge contract's `onMessageReceive` function. * @param _sourceChain The chain id that the message originated from. diff --git a/test/mocks/child/MockChildERC20Bridge.sol b/test/mocks/child/MockChildERC20Bridge.sol index fb5818b4..342930c6 100644 --- a/test/mocks/child/MockChildERC20Bridge.sol +++ b/test/mocks/child/MockChildERC20Bridge.sol @@ -3,8 +3,4 @@ pragma solidity 0.8.19; contract MockChildERC20Bridge { function onMessageReceive(bytes calldata) external {} - - function rootERC20BridgeAdaptor() external pure returns (string memory) { - return "rootERC20BridgeAdaptor"; - } } diff --git a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol index 74e5c055..60e7af8e 100644 --- a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol +++ b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol @@ -146,7 +146,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro function test_RevertIf_InitializeGivenAnEmptyBridgeAdaptorString() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); - vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector); + vm.expectRevert(InvalidRootBridgeAdaptor.selector); newAdaptor.initialize( roles, ROOT_CHAIN_NAME, "", address(mockChildERC20Bridge), address(mockChildAxelarGasService) ); @@ -445,7 +445,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro function test_RevertIf_updateRootBridgeAdaptorCalledWithEmptyString() public { vm.startPrank(targetManager); - vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector); + vm.expectRevert(InvalidRootBridgeAdaptor.selector); axelarAdaptor.updateRootBridgeAdaptor(""); } diff --git a/test/unit/root/RootAxelarBridgeAdaptor.t.sol b/test/unit/root/RootAxelarBridgeAdaptor.t.sol index 62a9fca8..1ac939ef 100644 --- a/test/unit/root/RootAxelarBridgeAdaptor.t.sol +++ b/test/unit/root/RootAxelarBridgeAdaptor.t.sol @@ -128,7 +128,7 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR function test_RevertIf_InitializeGivenEmptyChildAdapter() public { RootAxelarBridgeAdaptor newAdaptor = new RootAxelarBridgeAdaptor(address(mockAxelarGateway)); - vm.expectRevert(InvalidChildERC20BridgeAdaptor.selector); + vm.expectRevert(InvalidChildBridgeAdaptor.selector); newAdaptor.initialize(roles, address(this), CHILD_CHAIN_NAME, "", address(axelarGasService)); } /** @@ -407,7 +407,7 @@ contract RootAxelarBridgeAdaptorTest is Test, IRootAxelarBridgeAdaptorEvents, IR function test_RevertsIf_updateChildBridgeAdaptorCalledWithEmptyString() public { vm.startPrank(targetManager); - vm.expectRevert(InvalidChildERC20BridgeAdaptor.selector); + vm.expectRevert(InvalidChildBridgeAdaptor.selector); axelarAdaptor.updateChildBridgeAdaptor(""); } From 44bfbb5bda93aac5c4d7fec29f572ec723113891 Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 23 Nov 2023 08:40:21 +1100 Subject: [PATCH 5/7] Minor refactoring and adding comments --- script/InitializeChildContracts.s.sol | 2 +- src/child/ChildAxelarBridgeAdaptor.sol | 23 ++++++++++--------- .../child/IChildAxelarBridgeAdaptor.sol | 12 ++++++++++ .../root/IRootAxelarBridgeAdaptor.sol | 12 ++++++++++ src/root/RootAxelarBridgeAdaptor.sol | 18 +++++++-------- .../integration/child/ChildAxelarBridge.t.sol | 2 +- .../unit/child/ChildAxelarBridgeAdaptor.t.sol | 18 +++++++-------- .../withdrawals/RootERC20BridgeWithdraw.t.sol | 1 - test/utils.t.sol | 2 +- 9 files changed, 57 insertions(+), 33 deletions(-) diff --git a/script/InitializeChildContracts.s.sol b/script/InitializeChildContracts.s.sol index 3aaf58ec..1f069ff5 100644 --- a/script/InitializeChildContracts.s.sol +++ b/script/InitializeChildContracts.s.sol @@ -87,9 +87,9 @@ contract InitializeChildContracts is Script { params.childAxelarBridgeAdaptor.initialize( adaptorRoles, + address(params.childERC20Bridge), params.rootChainName, rootBridgeAdaptorString, - address(params.childERC20Bridge), params.childGasService ); diff --git a/src/child/ChildAxelarBridgeAdaptor.sol b/src/child/ChildAxelarBridgeAdaptor.sol index 4f5e37aa..ebef9f72 100644 --- a/src/child/ChildAxelarBridgeAdaptor.sol +++ b/src/child/ChildAxelarBridgeAdaptor.sol @@ -53,22 +53,23 @@ contract ChildAxelarBridgeAdaptor is /** * @notice Initialization function for ChildAxelarBridgeAdaptor. - * @param newRoles Struct containing addresses of roles. - * @param _rootChainId Axelar's ID for the root chain. + * @param _roles Struct containing addresses of roles. * @param _childBridge Address of child bridge contract. + * @param _rootChainId Axelar's string ID for the root chain. + * @param _rootBridgeAdaptor Address of the bridge adaptor on the root chain. * @param _gasService Address of Axelar Gas Service contract. */ function initialize( - InitializationRoles memory newRoles, + InitializationRoles memory _roles, + address _childBridge, string memory _rootChainId, string memory _rootBridgeAdaptor, - address _childBridge, address _gasService ) external initializer { if ( - _childBridge == address(0) || _gasService == address(0) || newRoles.defaultAdmin == address(0) - || newRoles.bridgeManager == address(0) || newRoles.gasServiceManager == address(0) - || newRoles.targetManager == address(0) + _childBridge == address(0) || _gasService == address(0) || _roles.defaultAdmin == address(0) + || _roles.bridgeManager == address(0) || _roles.gasServiceManager == address(0) + || _roles.targetManager == address(0) ) { revert ZeroAddress(); } @@ -82,10 +83,10 @@ contract ChildAxelarBridgeAdaptor is } __AccessControl_init(); - _grantRole(DEFAULT_ADMIN_ROLE, newRoles.defaultAdmin); - _grantRole(BRIDGE_MANAGER_ROLE, newRoles.bridgeManager); - _grantRole(GAS_SERVICE_MANAGER_ROLE, newRoles.gasServiceManager); - _grantRole(TARGET_MANAGER_ROLE, newRoles.targetManager); + _grantRole(DEFAULT_ADMIN_ROLE, _roles.defaultAdmin); + _grantRole(BRIDGE_MANAGER_ROLE, _roles.bridgeManager); + _grantRole(GAS_SERVICE_MANAGER_ROLE, _roles.gasServiceManager); + _grantRole(TARGET_MANAGER_ROLE, _roles.targetManager); childBridge = IChildERC20Bridge(_childBridge); rootChainId = _rootChainId; diff --git a/src/interfaces/child/IChildAxelarBridgeAdaptor.sol b/src/interfaces/child/IChildAxelarBridgeAdaptor.sol index fe568c8a..ce565ab0 100644 --- a/src/interfaces/child/IChildAxelarBridgeAdaptor.sol +++ b/src/interfaces/child/IChildAxelarBridgeAdaptor.sol @@ -42,6 +42,18 @@ interface IChildAxelarBridgeAdaptor { * @dev Can only be called by GAS_SERVICE_MANAGER_ROLE. */ function updateGasService(address newGasService) external; + + /** + * @notice Get the root chain id + * @return Axelar's string id of the root chain. + */ + function rootChainId() external view returns (string memory); + + /** + * @notice Get the root bridge adaptor address. + * @return String representation of the check sum address of the bridge adaptor on the root chain + */ + function rootBridgeAdaptor() external view returns (string memory); } interface IChildAxelarBridgeAdaptorErrors { diff --git a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol index 6ade4629..e789a555 100644 --- a/src/interfaces/root/IRootAxelarBridgeAdaptor.sol +++ b/src/interfaces/root/IRootAxelarBridgeAdaptor.sol @@ -42,6 +42,18 @@ interface IRootAxelarBridgeAdaptor { * @dev Can only be called by GAS_SERVICE_MANAGER_ROLE. */ function updateGasService(address newGasService) external; + + /** + * @notice Get the child chain id + * @return Axelar's string id of the child chain. + */ + function childChainId() external view returns (string memory); + + /** + * @notice Get the child bridge adaptor address. + * @return String representation of the check sum address of the bridge adaptor on the child chain + */ + function childBridgeAdaptor() external view returns (string memory); } /** diff --git a/src/root/RootAxelarBridgeAdaptor.sol b/src/root/RootAxelarBridgeAdaptor.sol index ec7c796f..22266d82 100644 --- a/src/root/RootAxelarBridgeAdaptor.sol +++ b/src/root/RootAxelarBridgeAdaptor.sol @@ -54,23 +54,23 @@ contract RootAxelarBridgeAdaptor is /** * @notice Initialization function for RootAxelarBridgeAdaptor. - * @param _newRoles Struct containing addresses of roles. + * @param _roles Struct containing addresses of roles. * @param _rootBridge Address of root bridge contract. * @param _childChainId Axelar's ID for the child chain. * @param _childBridgeAdaptor Address of the bridge adaptor on the child chain. * @param _gasService Address of Axelar Gas Service contract. */ function initialize( - InitializationRoles memory _newRoles, + InitializationRoles memory _roles, address _rootBridge, string memory _childChainId, string memory _childBridgeAdaptor, address _gasService ) public initializer { if ( - _rootBridge == address(0) || _gasService == address(0) || _newRoles.defaultAdmin == address(0) - || _newRoles.bridgeManager == address(0) || _newRoles.gasServiceManager == address(0) - || _newRoles.targetManager == address(0) + _rootBridge == address(0) || _gasService == address(0) || _roles.defaultAdmin == address(0) + || _roles.bridgeManager == address(0) || _roles.gasServiceManager == address(0) + || _roles.targetManager == address(0) ) { revert ZeroAddresses(); } @@ -85,10 +85,10 @@ contract RootAxelarBridgeAdaptor is __AccessControl_init(); - _grantRole(DEFAULT_ADMIN_ROLE, _newRoles.defaultAdmin); - _grantRole(BRIDGE_MANAGER_ROLE, _newRoles.bridgeManager); - _grantRole(GAS_SERVICE_MANAGER_ROLE, _newRoles.gasServiceManager); - _grantRole(TARGET_MANAGER_ROLE, _newRoles.targetManager); + _grantRole(DEFAULT_ADMIN_ROLE, _roles.defaultAdmin); + _grantRole(BRIDGE_MANAGER_ROLE, _roles.bridgeManager); + _grantRole(GAS_SERVICE_MANAGER_ROLE, _roles.gasServiceManager); + _grantRole(TARGET_MANAGER_ROLE, _roles.targetManager); rootBridge = IRootERC20Bridge(_rootBridge); childChainId = _childChainId; diff --git a/test/integration/child/ChildAxelarBridge.t.sol b/test/integration/child/ChildAxelarBridge.t.sol index 8c699a7f..28f683f9 100644 --- a/test/integration/child/ChildAxelarBridge.t.sol +++ b/test/integration/child/ChildAxelarBridge.t.sol @@ -64,9 +64,9 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil childAxelarBridgeAdaptor.initialize( adaptorRoles, + address(childERC20Bridge), ROOT_CHAIN_NAME, ROOT_ADAPTOR_ADDRESS, - address(childERC20Bridge), address(mockChildAxelarGasService) ); } diff --git a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol index 60e7af8e..94e505e8 100644 --- a/test/unit/child/ChildAxelarBridgeAdaptor.t.sol +++ b/test/unit/child/ChildAxelarBridgeAdaptor.t.sol @@ -46,9 +46,9 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro axelarAdaptor = new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway)); axelarAdaptor.initialize( roles, + address(mockChildERC20Bridge), ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, - address(mockChildERC20Bridge), address(mockChildAxelarGasService) ); } @@ -82,9 +82,9 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro roles.defaultAdmin = address(0); newAdaptor.initialize( roles, + address(mockChildERC20Bridge), ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, - address(mockChildERC20Bridge), address(mockChildAxelarGasService) ); } @@ -95,9 +95,9 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro roles.bridgeManager = address(0); newAdaptor.initialize( roles, + address(mockChildERC20Bridge), ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, - address(mockChildERC20Bridge), address(mockChildAxelarGasService) ); } @@ -108,9 +108,9 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro roles.gasServiceManager = address(0); newAdaptor.initialize( roles, + address(mockChildERC20Bridge), ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, - address(mockChildERC20Bridge), address(mockChildAxelarGasService) ); } @@ -121,9 +121,9 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro roles.targetManager = address(0); newAdaptor.initialize( roles, + address(mockChildERC20Bridge), ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, - address(mockChildERC20Bridge), address(mockChildAxelarGasService) ); } @@ -132,7 +132,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); newAdaptor.initialize( - roles, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, address(0), address(mockChildAxelarGasService) + roles, address(0), ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, address(mockChildAxelarGasService) ); } @@ -140,7 +140,7 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(InvalidRootChain.selector); newAdaptor.initialize( - roles, "", ROOT_BRIDGE_ADAPTOR, address(mockChildERC20Bridge), address(mockChildAxelarGasService) + roles, address(mockChildERC20Bridge), "", ROOT_BRIDGE_ADAPTOR, address(mockChildAxelarGasService) ); } @@ -148,14 +148,14 @@ contract ChildAxelarBridgeAdaptorUnitTest is Test, IChildAxelarBridgeAdaptorErro ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(InvalidRootBridgeAdaptor.selector); newAdaptor.initialize( - roles, ROOT_CHAIN_NAME, "", address(mockChildERC20Bridge), address(mockChildAxelarGasService) + roles, address(mockChildERC20Bridge), ROOT_CHAIN_NAME, "", address(mockChildAxelarGasService) ); } function test_RevertIf_InitializeGivenZeroGasService() public { ChildAxelarBridgeAdaptor newAdaptor = new ChildAxelarBridgeAdaptor(GATEWAY_ADDRESS); vm.expectRevert(ZeroAddress.selector); - newAdaptor.initialize(roles, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, address(mockChildERC20Bridge), address(0)); + newAdaptor.initialize(roles, address(mockChildERC20Bridge), ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, address(0)); } /** diff --git a/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol b/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol index 7eb28c0d..274b7871 100644 --- a/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol +++ b/test/unit/root/withdrawals/RootERC20BridgeWithdraw.t.sol @@ -18,7 +18,6 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; contract RootERC20BridgeWithdrawUnitTest is Test, IRootERC20BridgeEvents, IRootERC20BridgeErrors, Utils { address constant CHILD_BRIDGE = address(3); - string constant CHILD_CHAIN_NAME = "test"; address constant UnmappedToken = address(0xbbb); address constant IMX_TOKEN = address(0xccc); address constant WRAPPED_ETH = address(0xddd); diff --git a/test/utils.t.sol b/test/utils.t.sol index 0acc2b2b..e06cc70b 100644 --- a/test/utils.t.sol +++ b/test/utils.t.sol @@ -86,7 +86,7 @@ contract Utils is Test { }); childBridgeAdaptor.initialize( - adaptorRoles, "ROOT", rootAdaptor, address(childBridge), address(axelarGasService) + adaptorRoles, address(childBridge), "ROOT", rootAdaptor, address(axelarGasService) ); bytes memory mapTokenData = abi.encode(MAP_TOKEN_SIG, rootToken, "TEST NAME", "TNM", 18); From 6408377c76628c3ef3407f225ad226e38d41688c Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 23 Nov 2023 09:00:00 +1100 Subject: [PATCH 6/7] Use modifier to check bridge caller --- src/child/ChildERC20Bridge.sol | 27 ++++++++++++++++---------- src/root/RootERC20Bridge.sol | 18 ++++++++++++----- test/unit/child/ChildERC20Bridge.t.sol | 8 ++++---- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/child/ChildERC20Bridge.sol b/src/child/ChildERC20Bridge.sol index dd34d87a..c0ef5e60 100644 --- a/src/child/ChildERC20Bridge.sol +++ b/src/child/ChildERC20Bridge.sol @@ -52,7 +52,8 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br address public constant NATIVE_ETH = address(0xeee); address public constant NATIVE_IMX = address(0xfff); - IChildBridgeAdaptor public bridgeAdaptor; + /// @dev The address of the bridge adapter used to send and receive messages to and from the root chain. + IChildBridgeAdaptor public childBridgeAdaptor; /// @dev The address of the token template that will be cloned to create tokens. address public childTokenTemplate; @@ -63,6 +64,16 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br /// @dev The address of the wrapped IMX token on L2. address public wIMXToken; + /** + * @notice Modifier to ensure that the caller is the registered child bridge adaptor. + */ + modifier onlyBridgeAdaptor() { + if (msg.sender != address(childBridgeAdaptor)) { + revert NotBridgeAdaptor(); + } + _; + } + /** * @notice Initialization function for ChildERC20Bridge. * @param newRoles Struct containing addresses of roles. @@ -98,7 +109,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br _grantRole(TREASURY_MANAGER_ROLE, newRoles.treasuryManager); childTokenTemplate = newChildTokenTemplate; - bridgeAdaptor = IChildBridgeAdaptor(newBridgeAdaptor); + childBridgeAdaptor = IChildBridgeAdaptor(newBridgeAdaptor); rootIMXToken = newRootIMXToken; wIMXToken = newWIMXToken; @@ -144,8 +155,8 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br revert ZeroAddress(); } - emit ChildBridgeAdaptorUpdated(address(bridgeAdaptor), newBridgeAdaptor); - bridgeAdaptor = IChildBridgeAdaptor(newBridgeAdaptor); + emit ChildBridgeAdaptorUpdated(address(childBridgeAdaptor), newBridgeAdaptor); + childBridgeAdaptor = IChildBridgeAdaptor(newBridgeAdaptor); } /** @@ -154,11 +165,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br * This method assumes that the adaptor will have performed all * validations relating to the source of the message, prior to calling this method. */ - function onMessageReceive(bytes calldata data) external override whenNotPaused { - if (msg.sender != address(bridgeAdaptor)) { - revert NotBridgeAdaptor(); - } - + function onMessageReceive(bytes calldata data) external override whenNotPaused onlyBridgeAdaptor { if (data.length <= 32) { // Data must always be greater than 32. // 32 bytes for the signature, and at least some information for the payload @@ -323,7 +330,7 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br bytes memory payload = abi.encode(WITHDRAW_SIG, rootToken, msg.sender, receiver, amount); // Send the message to the bridge adaptor and up to root chain - bridgeAdaptor.sendMessage{value: feeAmount}(payload, msg.sender); + childBridgeAdaptor.sendMessage{value: feeAmount}(payload, msg.sender); if (childTokenAddr == NATIVE_IMX) { emit ChildChainNativeIMXWithdraw(rootToken, msg.sender, receiver, amount); diff --git a/src/root/RootERC20Bridge.sol b/src/root/RootERC20Bridge.sol index dbc505ad..d1046750 100644 --- a/src/root/RootERC20Bridge.sol +++ b/src/root/RootERC20Bridge.sol @@ -60,7 +60,9 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent address public constant NATIVE_ETH = address(0xeee); address public constant NATIVE_IMX = address(0xfff); + /// @dev The address of the bridge adapter used to send and receive messages to and from the child chain. IRootBridgeAdaptor public rootBridgeAdaptor; + /// @dev The address that will be minting tokens on the child chain. address public childERC20Bridge; /// @dev The address of the token template that will be cloned to create tokens on the child chain. @@ -75,6 +77,16 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent /// @dev A limit of zero indicates unlimited. uint256 public imxCumulativeDepositLimit; + /** + * @notice Modifier to ensure that the caller is the registered root bridge adaptor. + */ + modifier onlyBridgeAdaptor() { + if (msg.sender != address(rootBridgeAdaptor)) { + revert NotBridgeAdaptor(); + } + _; + } + /** * @notice Initialization function for RootERC20Bridge. * @param newRoles Struct containing addresses of roles. @@ -219,11 +231,7 @@ contract RootERC20Bridge is BridgeRoles, IRootERC20Bridge, IRootERC20BridgeEvent * This method assumes that the adaptor will have performed all * validations relating to the source of the message, prior to calling this method. */ - function onMessageReceive(bytes calldata data) external override whenNotPaused { - if (msg.sender != address(rootBridgeAdaptor)) { - revert NotBridgeAdaptor(); - } - + function onMessageReceive(bytes calldata data) external override whenNotPaused onlyBridgeAdaptor { if (data.length <= 32) { // Data must always be greater than 32. // 32 bytes for the signature, and at least some information for the payload diff --git a/test/unit/child/ChildERC20Bridge.t.sol b/test/unit/child/ChildERC20Bridge.t.sol index 76a5ffa2..dc4cf684 100644 --- a/test/unit/child/ChildERC20Bridge.t.sol +++ b/test/unit/child/ChildERC20Bridge.t.sol @@ -134,7 +134,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B */ function test_Initialize() public { - assertEq(address(childBridge.bridgeAdaptor()), address(address(this)), "bridgeAdaptor not set"); + assertEq(address(childBridge.childBridgeAdaptor()), address(address(this)), "bridgeAdaptor not set"); assertEq(childBridge.childTokenTemplate(), address(childTokenTemplate), "childTokenTemplate not set"); assertEq(childBridge.rootIMXToken(), ROOT_IMX_TOKEN, "rootIMXToken not set"); assertTrue(childBridge.hasRole(childBridge.ADAPTOR_MANAGER_ROLE(), address(this)), "adaptorManager not set"); @@ -230,16 +230,16 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B function test_updateChildBridgeAdaptor_UpdatesChildBridgeAdaptor() public { address newAdaptorAddress = address(0x11111); - assertEq(address(childBridge.bridgeAdaptor()), address(this), "bridgeAdaptor not set"); + assertEq(address(childBridge.childBridgeAdaptor()), address(this), "bridgeAdaptor not set"); childBridge.updateChildBridgeAdaptor(newAdaptorAddress); - assertEq(address(childBridge.bridgeAdaptor()), newAdaptorAddress, "bridgeAdaptor not updated"); + assertEq(address(childBridge.childBridgeAdaptor()), newAdaptorAddress, "bridgeAdaptor not updated"); } function test_updateChildBridgeAdpator_EmitsEvent() public { address newAdaptorAddress = address(0x11111); vm.expectEmit(true, true, false, false, address(childBridge)); - emit ChildBridgeAdaptorUpdated(address(childBridge.bridgeAdaptor()), newAdaptorAddress); + emit ChildBridgeAdaptorUpdated(address(childBridge.childBridgeAdaptor()), newAdaptorAddress); childBridge.updateChildBridgeAdaptor(newAdaptorAddress); } From 25f81faa39a176f4264ba232addd8dbd66755cfb Mon Sep 17 00:00:00 2001 From: Ermyas Abebe Date: Thu, 23 Nov 2023 09:25:16 +1100 Subject: [PATCH 7/7] Minor refactoring for readability --- src/child/ChildERC20Bridge.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/child/ChildERC20Bridge.sol b/src/child/ChildERC20Bridge.sol index 94172d66..ced13e94 100644 --- a/src/child/ChildERC20Bridge.sol +++ b/src/child/ChildERC20Bridge.sol @@ -175,9 +175,10 @@ contract ChildERC20Bridge is BridgeRoles, IChildERC20BridgeErrors, IChildERC20Br revert InvalidData("Data too short"); } - if (bytes32(data[:32]) == MAP_TOKEN_SIG) { + bytes32 sig = bytes32(data[:32]); + if (sig == MAP_TOKEN_SIG) { _mapToken(data); - } else if (bytes32(data[:32]) == DEPOSIT_SIG) { + } else if (sig == DEPOSIT_SIG) { _deposit(data[32:]); } else { revert InvalidData("Unsupported action signature");