Skip to content

Commit

Permalink
Merge branch 'main' of github.com:immutable/zkevm-bridge-contracts in…
Browse files Browse the repository at this point in the history
…to smr-1935-erc20-withdraw-L1
  • Loading branch information
Benjimmutable committed Nov 5, 2023
2 parents 15e208b + 73b9139 commit b6c05a8
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 379 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,12 @@ CHILD_GAS_SERVICE_ADDRESS=
ROOT_CHAIN_NAME="ROOT"
CHILD_CHAIN_NAME="CHILD"
ROOT_IMX_ADDRESS=
INITIAL_IMX_CUMULATIVE_DEPOSIT_LIMIT="0"
```
where `{ROOT,CHILD}_{GATEWAY,GAS_SERVICE}_ADDRESS` refers to the gateway and gas service addresses used by Axelar.

`INITIAL_IMX_CUMULATIVE_DEPOSIT_LIMIT` refers to the cumulative amount of IMX that can be deposited. A value of `0` indicated unlimited.

We can just use dummy gateway/gas service addresses if we only want to test the deployment, and not bridging functionality. If wanting to use dummy addresses, any valid Ethereum address can be used here.

4. Run the deploy script.
Expand Down Expand Up @@ -138,6 +141,7 @@ ROOT_GATEWAY_ADDRESS="0x013459EC3E8Aeced878C5C4bFfe126A366cd19E9"
CHILD_GATEWAY_ADDRESS="0xc7B788E88BAaB770A6d4936cdcCcd5250E1bbAd8"
ROOT_GAS_SERVICE_ADDRESS="0x28f8B50E1Be6152da35e923602a2641491E71Ed8"
CHILD_GAS_SERVICE_ADDRESS="0xC573c722e21eD7fadD38A8f189818433e01Ae466"
INITIAL_IMX_CUMULATIVE_DEPOSIT_LIMIT="0"
ENVIRONMENT="local"
```
(Note that `{ROOT,CHILD}_PRIVATE_KEY` can be any of the standard localhost private keys that get funded)
Expand Down
5 changes: 2 additions & 3 deletions script/DeployRootContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,17 @@ contract DeployRootContracts is Script {

RootERC20Bridge rootERC20BridgeImplementation = new RootERC20Bridge();
rootERC20BridgeImplementation.initialize(
address(1), address(1), "filler", address(1), address(1), address(1), "filler_child_name"
address(1), address(1), "filler", address(1), address(1), address(1), "filler_child_name", 1
);
TransparentUpgradeableProxy rootERC20BridgeProxy = new TransparentUpgradeableProxy(
address(rootERC20BridgeImplementation),
address(proxyAdmin),
""
);

// TODO add dummy initialize of implementation contracts!

RootAxelarBridgeAdaptor rootBridgeAdaptorImplementation = new RootAxelarBridgeAdaptor(rootGateway);
rootBridgeAdaptorImplementation.initialize(address(rootERC20BridgeImplementation), "Filler", address(1));

TransparentUpgradeableProxy rootBridgeAdaptorProxy = new TransparentUpgradeableProxy(
address(rootBridgeAdaptorImplementation),
address(proxyAdmin),
Expand Down
7 changes: 5 additions & 2 deletions script/InitializeRootContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct InitializeRootContractsParams {
address rootWETHToken;
string childChainName;
address rootGasService;
uint256 initialIMXCumulativeDepositLimit;
}

contract InitializeRootContracts is Script {
Expand All @@ -40,7 +41,8 @@ contract InitializeRootContracts is Script {
rootIMXToken: vm.envAddress("ROOT_IMX_ADDRESS"),
rootWETHToken: vm.envAddress("ROOT_WETH_ADDRESS"),
childChainName: vm.envString("CHILD_CHAIN_NAME"),
rootGasService: vm.envAddress("ROOT_GAS_SERVICE_ADDRESS")
rootGasService: vm.envAddress("ROOT_GAS_SERVICE_ADDRESS"),
initialIMXCumulativeDepositLimit: vm.envUint("INITIAL_IMX_CUMULATIVE_DEPOSIT_LIMIT")
});

string[] memory checksumInputs = Utils.getChecksumInputs(params.childBridgeAdaptor);
Expand All @@ -59,7 +61,8 @@ contract InitializeRootContracts is Script {
params.rootChainChildTokenTemplate,
params.rootIMXToken,
params.rootWETHToken,
params.childChainName
params.childChainName,
params.initialIMXCumulativeDepositLimit
);

params.rootBridgeAdaptor.initialize(
Expand Down
8 changes: 8 additions & 0 deletions src/interfaces/root/IRootERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ interface IRootERC20Bridge {
}

interface IRootERC20BridgeEvents {
/// @notice Emitted when the child chain bridge adaptor is updated.
event NewRootBridgeAdaptor(address oldRootBridgeAdaptor, address newRootBridgeAdaptor);
/// @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.
event L1TokenMapped(address indexed rootToken, address indexed childToken);
/// @notice Emitted when an ERC20 deposit message is sent to the child chain.
Expand Down Expand Up @@ -109,4 +113,8 @@ interface IRootERC20BridgeErrors {
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
error ImxDepositLimitExceeded();
/// @notice Error when the IMX deposit limit is set below the amount of IMX already deposited
error ImxDepositLimitTooLow();
}
40 changes: 39 additions & 1 deletion src/root/RootERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ contract RootERC20Bridge is
/// @dev leave this as the first param for the integration tests
mapping(address => address) public rootTokenToChildToken;

uint256 public constant NO_DEPOSIT_LIMIT = 0;
bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN");
bytes32 public constant DEPOSIT_SIG = keccak256("DEPOSIT");
bytes32 public constant WITHDRAW_SIG = keccak256("WITHDRAW");
Expand All @@ -56,6 +57,9 @@ contract RootERC20Bridge is
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;

/**
* @notice Initilization function for RootERC20Bridge.
Expand All @@ -66,6 +70,7 @@ contract RootERC20Bridge is
* @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.
*/
function initialize(
Expand All @@ -75,7 +80,8 @@ contract RootERC20Bridge is
address newChildTokenTemplate,
address newRootIMXToken,
address newRootWETHToken,
string memory newChildChain
string memory newChildChain,
uint256 newImxCumulativeDepositLimit
) public initializer {
if (
newRootBridgeAdaptor == address(0) || newChildERC20Bridge == address(0)
Expand All @@ -100,15 +106,41 @@ contract RootERC20Bridge is
rootBridgeAdaptor = IRootERC20BridgeAdaptor(newRootBridgeAdaptor);
childBridgeAdaptor = newChildBridgeAdaptor;
childChain = newChildChain;
imxCumulativeDepositLimit = newImxCumulativeDepositLimit;
}

/**
* @notice Updates the root bridge adaptor.
* @param newRootBridgeAdaptor Address of new root bridge adaptor.
* @dev Can only be called by owner.
*/
function updateRootBridgeAdaptor(address newRootBridgeAdaptor) external onlyOwner {
if (newRootBridgeAdaptor == address(0)) {
revert ZeroAddress();
}
emit NewRootBridgeAdaptor(address(rootBridgeAdaptor), newRootBridgeAdaptor);
rootBridgeAdaptor = IRootERC20BridgeAdaptor(newRootBridgeAdaptor);
}

// TODO add updating of child bridge adaptor. Part of SMR-1908

/**
* @notice Updates the IMX deposit limit.
* @param newImxCumulativeDepositLimit The new cumulative IMX deposit limit.
* @dev Can only be called by owner.
* @dev The limit can decrease, but it can never decrease to below the contract's IMX balance.
*/
function updateImxCumulativeDepositLimit(uint256 newImxCumulativeDepositLimit) external onlyOwner {
if (
newImxCumulativeDepositLimit != NO_DEPOSIT_LIMIT
&& newImxCumulativeDepositLimit < IERC20Metadata(rootIMXToken).balanceOf(address(this))
) {
revert ImxDepositLimitTooLow();
}
emit NewImxDepositLimit(imxCumulativeDepositLimit, newImxCumulativeDepositLimit);
imxCumulativeDepositLimit = newImxCumulativeDepositLimit;
}

/**
* @dev method to receive the ETH back from the WETH contract when it is unwrapped
*/
Expand Down Expand Up @@ -267,6 +299,12 @@ contract RootERC20Bridge is
if (amount == 0) {
revert ZeroAmount();
}
if (
address(rootToken) == rootIMXToken && imxCumulativeDepositLimit != NO_DEPOSIT_LIMIT
&& IERC20Metadata(rootIMXToken).balanceOf(address(this)) + amount > imxCumulativeDepositLimit
) {
revert ImxDepositLimitExceeded();
}

// ETH, WETH and IMX do not need to be mapped since it should have been mapped on initialization
// ETH also cannot be transferred since it was received in the payable function call
Expand Down
Loading

0 comments on commit b6c05a8

Please sign in to comment.