Skip to content

Commit

Permalink
initialising with child eth token implemented and tested
Browse files Browse the repository at this point in the history
  • Loading branch information
proletesseract committed Oct 19, 2023
1 parent 1e55235 commit 82d032c
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 30 deletions.
4 changes: 3 additions & 1 deletion script/InitializeChildContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ 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 childETHToken = vm.envAddress("CHILD_ETH_ADDRESS");

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

childAxelarBridgeAdaptor.setRootBridgeAdaptor();
Expand Down
37 changes: 25 additions & 12 deletions src/child/ChildERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,38 +33,49 @@ contract ChildERC20Bridge is
{
using SafeERC20 for IERC20Metadata;

/// @dev leave this as the first param for the integration tests
mapping(address => address) public rootTokenToChildToken;

bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN");
bytes32 public constant DEPOSIT_SIG = keccak256("DEPOSIT");
address public constant NATIVE_TOKEN = address(0xeee);

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;
mapping(address => address) public rootTokenToChildToken;

bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN");
bytes32 public constant DEPOSIT_SIG = keccak256("DEPOSIT");
address public imxToken;
/// @dev The address of the IMX ERC20 token on L1.
address public rootIMXToken;
/// @dev The address of the ETH ERC20 token on L2.
address public childETHToken;
/// @dev The address of the token template that will be cloned to create tokens on the child chain.

/**
* @notice Initilization function for RootERC20Bridge.
* @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 newIMXToken Address of ECR20 IMX on the root chain.
* @param newRootIMXToken Address of ECR20 IMX on the root chain.
* @param newChildETHToken Address of ERC20 ETH on the child chain.
* @dev Can only be called once.
*/
function initialize(
address newBridgeAdaptor,
string memory newRootERC20BridgeAdaptor,
address newChildTokenTemplate,
string memory newRootChain,
address newIMXToken
) public initializer {
address newRootIMXToken,
address newChildETHToken)
public initializer
{
if (newBridgeAdaptor == address(0)
|| newChildTokenTemplate == address(0)
|| newIMXToken == address(0)) {
|| newRootIMXToken == address(0)
|| newChildETHToken == address(0)) {
revert ZeroAddress();
}

Expand All @@ -80,7 +91,9 @@ contract ChildERC20Bridge is
childTokenTemplate = newChildTokenTemplate;
bridgeAdaptor = IChildERC20BridgeAdaptor(newBridgeAdaptor);
rootChain = newRootChain;
imxToken = newIMXToken;
rootIMXToken = newRootIMXToken;
childETHToken = newChildETHToken;

}

/**
Expand Down Expand Up @@ -122,7 +135,7 @@ contract ChildERC20Bridge is
revert ZeroAddress();
}

if (address(rootToken) == imxToken) {
if (address(rootToken) == rootIMXToken) {
revert CantMapIMX();
}

Expand All @@ -149,7 +162,7 @@ contract ChildERC20Bridge is

address childToken;

if (address(rootToken) != imxToken) {
if (address(rootToken) != rootIMXToken) {
childToken = rootTokenToChildToken[address(rootToken)];
if (childToken == address(0)) {
revert NotMapped();
Expand Down
5 changes: 3 additions & 2 deletions src/root/RootERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,20 @@ contract RootERC20Bridge is
{
using SafeERC20 for IERC20Metadata;

/// @dev leave this as the first param for the integration tests
mapping(address => address) public rootTokenToChildToken;

bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN");
bytes32 public constant DEPOSIT_SIG = keccak256("DEPOSIT");
address public constant NATIVE_TOKEN = address(0xeee);

IRootERC20BridgeAdaptor public rootBridgeAdaptor;
/// @dev Used to verify source address in messages sent from child chain.
/// @dev Stringified version of address.
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.
address public childTokenTemplate;
mapping(address => address) public rootTokenToChildToken;
/// @dev The address of the IMX ERC20 token on L1.
address public rootIMXToken;
/// @dev The address of the ETH ERC20 token on L2.
Expand Down
9 changes: 5 additions & 4 deletions test/integration/child/ChildAxelarBridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {Utils} from "../../utils.t.sol";
contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChildERC20BridgeErrors, Utils {
string public ROOT_ADAPTOR_ADDRESS = Strings.toHexString(address(1));
string public ROOT_CHAIN_NAME = "ROOT_CHAIN";
address constant IMX_TOKEN = address(9);
address constant IMX_TOKEN_ADDRESS = address(0xccc);
address constant CHILD_ETH_TOKEN = address(0xddd);

ChildERC20Bridge public childERC20Bridge;
ChildERC20 public childERC20;
Expand All @@ -35,7 +36,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(childAxelarBridgeAdaptor), ROOT_ADAPTOR_ADDRESS, address(childERC20), ROOT_CHAIN_NAME, IMX_TOKEN_ADDRESS, CHILD_ETH_TOKEN
);
}

Expand Down Expand Up @@ -246,8 +247,8 @@ contract ChildERC20BridgeIntegrationTest is Test, IChildERC20BridgeEvents, IChil
bytes32 depositSig = childERC20Bridge.DEPOSIT_SIG();
address rootAddress = address(0x123);
{
// Slot is 6 because of the Ownable, Initializable contracts coming first.
uint256 rootTokenToChildTokenMappingSlot = 6;
// Slot is 2 because of the Ownable, Initializable contracts coming first.
uint256 rootTokenToChildTokenMappingSlot = 2;
address childAddress = address(444444);
bytes32 slot = getMappingStorageSlotFor(rootAddress, rootTokenToChildTokenMappingSlot);
bytes32 data = bytes32(uint256(uint160(childAddress)));
Expand Down
30 changes: 19 additions & 11 deletions test/unit/child/ChildERC20Bridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B
string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4));
string constant ROOT_CHAIN_NAME = "test";

address constant IMX_TOKEN = address(99);
address constant IMX_TOKEN = address(0xccc);
address constant CHILD_ETH_TOKEN = address(0xddd);
address constant NATIVE_TOKEN = address(0xeee);
ChildERC20 public childTokenTemplate;
ChildERC20 public rootToken;
ChildERC20Bridge public childBridge;
Expand All @@ -33,7 +35,7 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B

childBridge = new ChildERC20Bridge();

childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, IMX_TOKEN);
childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, IMX_TOKEN, CHILD_ETH_TOKEN);
}

function test_Initialize() public {
Expand All @@ -45,43 +47,49 @@ 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, IMX_TOKEN);
childBridge.initialize(address(this), ROOT_BRIDGE_ADAPTOR, address(childTokenTemplate), ROOT_CHAIN_NAME, IMX_TOKEN, CHILD_ETH_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));
bridge.initialize(address(0), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(1), 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));
bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(0), ROOT_CHAIN_NAME, address(1), 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));
bridge.initialize(address(1), ROOT_BRIDGE_ADAPTOR, address(1), ROOT_CHAIN_NAME, address(0), address(1));
}

function test_RevertIf_InitializeWithAZeroAddressEthChildToken() 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));
}

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));
bridge.initialize(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(address(this), "", address(childTokenTemplate), ROOT_CHAIN_NAME, IMX_TOKEN);
bridge.initialize(address(this), "", address(childTokenTemplate), ROOT_CHAIN_NAME, IMX_TOKEN, CHILD_ETH_TOKEN);
}

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

function test_onMessageReceive_EmitsTokenMappedEvent() public {
Expand Down Expand Up @@ -357,8 +365,8 @@ contract ChildERC20BridgeUnitTest is Test, IChildERC20BridgeEvents, IChildERC20B

address rootAddress = address(0x123);
{
// Slot is 6 because of the Ownable, Initializable contracts coming first.
uint256 rootTokenToChildTokenMappingSlot = 6;
// Slot is 2 because of the Ownable, Initializable contracts coming first.
uint256 rootTokenToChildTokenMappingSlot = 2;
address childAddress = address(444444);
bytes32 slot = getMappingStorageSlotFor(rootAddress, rootTokenToChildTokenMappingSlot);
bytes32 data = bytes32(uint256(uint160(childAddress)));
Expand Down

0 comments on commit 82d032c

Please sign in to comment.