Skip to content

Commit

Permalink
remove ETH_TOKEN address from child initialise
Browse files Browse the repository at this point in the history
  • Loading branch information
proletesseract committed Oct 24, 2023
1 parent fc2eaae commit e4de38e
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 39 deletions.
4 changes: 1 addition & 3 deletions script/InitializeChildContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ contract InitializeChildContracts is Script {
string memory childRpcUrl = vm.envString("CHILD_RPC_URL");
string memory rootChainName = vm.envString("ROOT_CHAIN_NAME");
address rootIMXToken = vm.envAddress("ROOT_IMX_ADDRESS");
address rootETHToken = vm.envAddress("ROOT_ETH_ADDRESS");

/**
* INITIALIZE CHILD CONTRACTS
Expand All @@ -32,8 +31,7 @@ contract InitializeChildContracts is Script {
Strings.toHexString(rootERC20BridgeAdaptor),
childTokenTemplate,
rootChainName,
rootIMXToken,
rootETHToken
rootIMXToken
);

childAxelarBridgeAdaptor.setRootBridgeAdaptor();
Expand Down
15 changes: 8 additions & 7 deletions src/child/ChildERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,19 @@ contract ChildERC20Bridge is
* @param newChildTokenTemplate Address of child token template to clone.
* @param newRootChain A stringified representation of the chain that this bridge is connected to. Used for validation.
* @param newRootIMXToken Address of ECR20 IMX on the root chain.
* @param newRootETHToken Address used to denote ETH on the root chain.
* @dev Can only be called once.
*/
function initialize(
address newBridgeAdaptor,
string memory newRootERC20BridgeAdaptor,
address newChildTokenTemplate,
string memory newRootChain,
address newRootIMXToken,
address newRootETHToken)
address newRootIMXToken)
public initializer
{
if (newBridgeAdaptor == address(0)
|| newChildTokenTemplate == address(0)
|| newRootIMXToken == address(0)
|| newRootETHToken == address(0)) {
|| newRootIMXToken == address(0)) {
revert ZeroAddress();
}

Expand All @@ -94,8 +91,8 @@ contract ChildERC20Bridge is
rootIMXToken = newRootIMXToken;

IChildERC20 clonedETHToken =
IChildERC20(Clones.cloneDeterministic(childTokenTemplate, keccak256(abi.encodePacked(newRootETHToken))));
clonedETHToken.initialize(newRootETHToken, "Ethereum", "ETH", 18);
IChildERC20(Clones.cloneDeterministic(childTokenTemplate, keccak256(abi.encodePacked(NATIVE_ETH))));
clonedETHToken.initialize(NATIVE_ETH, "Ethereum", "ETH", 18);
childETHToken = address(clonedETHToken);
}

Expand Down Expand Up @@ -142,6 +139,10 @@ contract ChildERC20Bridge is
revert CantMapIMX();
}

if (address(rootToken) == NATIVE_ETH) {
revert CantMapETH();
}

if (rootTokenToChildToken[rootToken] != address(0)) {
revert AlreadyMapped();
}
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces/child/IChildERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ interface IChildERC20BridgeErrors {
error NotMapped();
/// @notice Error when attempting to map IMX.
error CantMapIMX();
/// @notice Error when attempting to map ETH.
error CantMapETH();
/// @notice Error when a token is already mapped.
error AlreadyMapped();
/// @notice Error when a message is given to the bridge from an address not the designated bridge adaptor.
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces/root/IRootERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ interface IRootERC20BridgeErrors {
error NotMapped();
/// @notice Error when attempting to map IMX.
error CantMapIMX();
/// @notice Error when attempting to map ETH.
error CantMapETH();
/// @notice Error when token balance invariant check fails.
error BalanceInvariantCheckFailed(uint256 actualBalance, uint256 expectedBalance);
}
5 changes: 5 additions & 0 deletions src/root/RootERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ contract RootERC20Bridge is
if (address(rootToken) == rootIMXToken) {
revert CantMapIMX();
}

if (address(rootToken) == NATIVE_ETH) {
revert CantMapETH();
}

if (rootTokenToChildToken[address(rootToken)] != address(0)) {
revert AlreadyMapped();
}
Expand Down
3 changes: 1 addition & 2 deletions test/integration/child/ChildAxelarBridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil
string public ROOT_ADAPTOR_ADDRESS = Strings.toHexString(address(1));
string public ROOT_CHAIN_NAME = "ROOT_CHAIN";
address constant IMX_TOKEN_ADDRESS = address(0xccc);
address constant CHILD_ETH_TOKEN = address(0xddd);

ChildERC20Bridge public childERC20Bridge;
ChildERC20 public childERC20;
Expand All @@ -36,7 +35,7 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil
new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway), address(childERC20Bridge));

childERC20Bridge.initialize(
address(childAxelarBridgeAdaptor), ROOT_ADAPTOR_ADDRESS, address(childERC20), ROOT_CHAIN_NAME, IMX_TOKEN_ADDRESS, CHILD_ETH_TOKEN
address(childAxelarBridgeAdaptor), ROOT_ADAPTOR_ADDRESS, address(childERC20), ROOT_CHAIN_NAME, IMX_TOKEN_ADDRESS
);
}

Expand Down
30 changes: 16 additions & 14 deletions test/unit/child/ChildERC20Bridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B
childTokenTemplate.initialize(address(123), "Test", "TST", 18);

childBridge = new ChildERC20Bridge();
childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN, NATIVE_ETH);
childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN);
}

function test_Initialize() public {
Expand All @@ -50,49 +50,43 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B

function test_RevertIfInitializeTwice() public {
vm.expectRevert("Initializable: contract is already initialized");
childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN, NATIVE_ETH);
childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN);
}

function test_RevertIf_InitializeWithAZeroAddressAdapter() public {
ChildERC20Bridge bridge = new ChildERC20Bridge();
vm.expectRevert(ZeroAddress.selector);
bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(1));
bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1));
}

function test_RevertIf_InitializeWithAZeroAddressChildTemplate() public {
ChildERC20Bridge bridge = new ChildERC20Bridge();
vm.expectRevert(ZeroAddress.selector);
bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(1), address(1));
bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(1));
}

function test_RevertIf_InitializeWithAZeroAddressIMXToken() public {
ChildERC20Bridge bridge = new ChildERC20Bridge();
vm.expectRevert(ZeroAddress.selector);
bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(0), address(1));
}

function test_RevertIf_InitializeWithAZeroAddressEthRootToken() public {
ChildERC20Bridge bridge = new ChildERC20Bridge();
vm.expectRevert(ZeroAddress.selector);
bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), address(0));
bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(0));
}

function test_RevertIf_InitializeWithAZeroAddressAll() public {
ChildERC20Bridge bridge = new ChildERC20Bridge();
vm.expectRevert(ZeroAddress.selector);
bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(0), address(0));
bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(0));
}

function test_RevertIf_InitializeWithAnEmptyBridgeAdaptorString() public {
ChildERC20Bridge bridge = new ChildERC20Bridge();
vm.expectRevert(InvalidRootERC20BridgeAdaptor.selector);
bridge.initialize(address(this), "", address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN, NATIVE_ETH);
bridge.initialize(address(this), "", address(childTokenTemplate), ROOT_CHAIN_NAME, ROOT_IMX_TOKEN);
}

function test_RevertIf_InitializeWithAnEmptyChainNameString() public {
ChildERC20Bridge bridge = new ChildERC20Bridge();
vm.expectRevert(InvalidRootChain.selector);
bridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), "", ROOT_IMX_TOKEN, NATIVE_ETH);
bridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), "", ROOT_IMX_TOKEN);
}

function test_onMessageReceive_EmitsTokenMappedEvent() public {
Expand Down Expand Up @@ -200,6 +194,14 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B
childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data);
}

function test_RevertIf_mapTokenCalledWithETHAddress() public {
bytes memory data = abi.encode(
childBridge.MAP_TOKEN_SIG(), NATIVE_ETH, "Ethereum", "ETH", 18
);
vm.expectRevert(CantMapETH.selector);
childBridge.onMessageReceive(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, data);
}

function test_RevertIf_onMessageReceiveCalledTwice() public {
bytes memory data = abi.encode(
childBridge.MAP_TOKEN_SIG(), address(rootToken), rootToken.name(), rootToken.symbol(), rootToken.decimals()
Expand Down
31 changes: 18 additions & 13 deletions test/unit/root/RootERC20Bridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid
string constant CHILD_CHAIN_NAME = "test";
address constant IMX_TOKEN = address(0xccc);
address constant CHILD_ETH_TOKEN = address(0xddd);
address constant NATIVE_TOKEN = address(0xeee);
address constant NATIVE_ETH = address(0xeee);
uint256 constant mapTokenFee = 300;
uint256 constant depositFee = 200;

Expand Down Expand Up @@ -176,6 +176,11 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid
rootBridge.mapToken{value: 300}(IERC20Metadata(IMX_TOKEN));
}

function test_RevertIf_mapTokenCalledWithETHAddress() public {
vm.expectRevert(CantMapETH.selector);
rootBridge.mapToken{value: 300}(IERC20Metadata(NATIVE_ETH));
}

function test_updateRootBridgeAdaptor() public {
address newAdaptorAddress = address(0x11111);

Expand All @@ -201,7 +206,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid

function test_depositETHCallsSendMessage() public {
uint256 amount = 1000;
(, bytes memory predictedPayload) = setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false);
(, bytes memory predictedPayload) = setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectCall(
address(mockAxelarAdaptor),
Expand All @@ -214,16 +219,16 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid

function test_depositETHEmitsNativeEthDepositEvent() public {
uint256 amount = 1000;
setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false);
setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectEmit();
emit NativeEthDeposit(NATIVE_TOKEN, CHILD_ETH_TOKEN, address(this), address(this), amount);
emit NativeEthDeposit(NATIVE_ETH, CHILD_ETH_TOKEN, address(this), address(this), amount);
rootBridge.depositETH{value: amount+depositFee}(amount);
}

function test_RevertIf_depositETHInsufficientValue() public {
uint256 amount = 1000;
setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false);
setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectRevert(InsufficientValue.selector);
rootBridge.depositETH{value: (amount/2)+depositFee}(amount);
Expand All @@ -236,7 +241,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid
function test_depositToETHCallsSendMessage() public {
uint256 amount = 1000;
address receiver = address(12345);
(, bytes memory predictedPayload) = setupDepositTo(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, receiver, false);
(, bytes memory predictedPayload) = setupDepositTo(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, receiver, false);
vm.expectCall(
address(mockAxelarAdaptor),
depositFee,
Expand All @@ -249,17 +254,17 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid
function test_depositToETHEmitsNativeEthDepositEvent() public {
uint256 amount = 1000;
address receiver = address(12345);
setupDepositTo(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, receiver, false);
setupDepositTo(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, receiver, false);

vm.expectEmit();
emit NativeEthDeposit(NATIVE_TOKEN, CHILD_ETH_TOKEN, address(this), receiver, amount);
emit NativeEthDeposit(NATIVE_ETH, CHILD_ETH_TOKEN, address(this), receiver, amount);
rootBridge.depositToETH{value: amount+depositFee}(receiver, amount);
}

function test_RevertIf_depositToETHInsufficientValue() public {
uint256 amount = 1000;
address receiver = address(12345);
setupDepositTo(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, receiver, false);
setupDepositTo(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, receiver, false);

vm.expectRevert(InsufficientValue.selector);
rootBridge.depositToETH{value: (amount/2)+depositFee}(receiver, amount);
Expand All @@ -271,7 +276,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid

function test_RevertIf_depositETHAmountIsZero() public {
uint256 amount = 0;
setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false);
setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectRevert(ZeroAmount.selector);
rootBridge.depositETH{value: amount+depositFee}(amount);
Expand All @@ -281,15 +286,15 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid
uint256 amount = 0;
address receiver = address(12345);

setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false);
setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectRevert(ZeroAmount.selector);
rootBridge.depositToETH{value: amount+depositFee}(receiver, amount);
}

function test_RevertIf_depositAmountIsZero() public {
uint256 amount = 0;
setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false);
setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectRevert(ZeroAmount.selector);
rootBridge.deposit{value: depositFee}(token, amount);
Expand All @@ -298,7 +303,7 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid
function test_RevertIf_depositToAmountIsZero() public {
uint256 amount = 0;
address receiver = address(12345);
setupDeposit(ERC20PresetMinterPauser(NATIVE_TOKEN), rootBridge, mapTokenFee, depositFee, amount, false);
setupDeposit(ERC20PresetMinterPauser(NATIVE_ETH), rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectRevert(ZeroAmount.selector);
rootBridge.depositTo{value: depositFee}(token, receiver, amount);
Expand Down

0 comments on commit e4de38e

Please sign in to comment.