Skip to content

Commit

Permalink
feedback applied
Browse files Browse the repository at this point in the history
  • Loading branch information
proletesseract committed Oct 26, 2023
1 parent 364d73f commit f2beb02
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 32 deletions.
1 change: 1 addition & 0 deletions src/interfaces/root/IRootERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ interface IRootERC20BridgeEvents {
uint256 amount
);
event IMXDeposit(address indexed rootToken, address depositor, address indexed receiver, uint256 amount);
event WETHDeposit(address indexed rootToken, address depositor, address indexed receiver, uint256 amount);
event NativeEthDeposit(
address indexed rootToken,
address indexed childToken,
Expand Down
60 changes: 33 additions & 27 deletions src/root/RootERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,26 +134,31 @@ contract RootERC20Bridge is
_depositToken(rootToken, receiver, amount);
}

function _depositUnwrappedETH(address receiver, uint256 amount) private {
_deposit(IERC20Metadata(NATIVE_ETH), receiver, amount, msg.value);
}

function _depositETH(address receiver, uint256 amount) private {
if (msg.value < amount) {
revert InsufficientValue();
}

uint256 expectedBalance = address(this).balance - (msg.value - amount);

_deposit(IERC20Metadata(NATIVE_ETH), receiver, amount, msg.value - amount);
_deposit(IERC20Metadata(NATIVE_ETH), receiver, amount);

// invariant check to ensure that the root native balance has increased by the amount deposited
if (address(this).balance != expectedBalance) {
revert BalanceInvariantCheckFailed(address(this).balance, expectedBalance);
}
}

function _unwrapWETH(uint256 amount) private {
function _depositToken(IERC20Metadata rootToken, address receiver, uint256 amount) private {
if (address(rootToken) == rootWETHToken) {
_unwrapETH(amount);
_deposit(IERC20Metadata(rootWETHToken), receiver, amount);
} else {
_depositERC20(rootToken, receiver, amount);
}
}

function _unwrapETH(uint256 amount) private {
uint256 expectedBalance = address(this).balance + amount;

IERC20Metadata erc20WETH = IERC20Metadata(rootWETHToken);
Expand All @@ -167,18 +172,9 @@ contract RootERC20Bridge is
}
}

function _depositToken(IERC20Metadata rootToken, address receiver, uint256 amount) private {
if (address(rootToken) == rootWETHToken) {
_unwrapWETH(amount);
_depositUnwrappedETH(receiver, amount);
} else {
_depositERC20(rootToken, receiver, amount);
}
}

function _depositERC20(IERC20Metadata rootToken, address receiver, uint256 amount) private {
uint256 expectedBalance = rootToken.balanceOf(address(this)) + amount;
_deposit(rootToken, receiver, amount, msg.value);
_deposit(rootToken, receiver, amount);
// invariant check to ensure that the root token balance has increased by the amount deposited
// slither-disable-next-line incorrect-equality
if (rootToken.balanceOf(address(this)) != expectedBalance) {
Expand Down Expand Up @@ -222,40 +218,50 @@ contract RootERC20Bridge is
return childToken;
}

function _deposit(IERC20Metadata rootToken, address receiver, uint256 amount, uint256 feeAmount) private {
function _deposit(IERC20Metadata rootToken, address receiver, uint256 amount) private {
if (receiver == address(0) || address(rootToken) == address(0)) {
revert ZeroAddress();
}
if (amount == 0) {
revert ZeroAmount();
}

// 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
// WETH is also not transferred here since it was earlier unwrapped to ETH

// TODO We can call _mapToken here, but ordering in the GMP is not guaranteed.
// Therefore, we need to decide how to handle this and it may be a UI decision to wait until map token message is executed on child chain.
// Discuss this, and add this decision to the design doc.

address childToken;
uint256 feeAmount = msg.value;
address payloadToken = address(rootToken);

// The native token does not need to be mapped since it should have been mapped on initialization
// The native token also cannot be transferred since it was received in the payable function call
// TODO We can call _mapToken here, but ordering in the GMP is not guaranteed.
// Therefore, we need to decide how to handle this and it may be a UI decision to wait until map token message is executed on child chain.
// Discuss this, and add this decision to the design doc.
if (address(rootToken) != NATIVE_ETH) {
if (address(rootToken) == NATIVE_ETH) {
feeAmount = msg.value - amount;
} else if (address(rootToken) == rootWETHToken) {
payloadToken = NATIVE_ETH;
} else {
if (address(rootToken) != rootIMXToken) {
childToken = rootTokenToChildToken[address(rootToken)];
if (childToken == address(0)) {
revert NotMapped();
}
}
// ERC20 must be transferred explicitly
rootToken.safeTransferFrom(msg.sender, address(this), amount);
}
}

// Deposit sig, root token address, depositor, receiver, amount
bytes memory payload = abi.encode(DEPOSIT_SIG, rootToken, msg.sender, receiver, amount);
bytes memory payload = abi.encode(DEPOSIT_SIG, payloadToken, msg.sender, receiver, amount);

// TODO investigate using delegatecall to keep the axelar message sender as the bridge contract, since adaptor can change.

rootBridgeAdaptor.sendMessage{value: feeAmount}(payload, msg.sender);

if (address(rootToken) == NATIVE_ETH) {
emit NativeEthDeposit(address(rootToken), childETHToken, msg.sender, receiver, amount);
} else if (address(rootToken) == rootWETHToken) {
emit WETHDeposit(address(rootToken), msg.sender, receiver, amount);
} else if (address(rootToken) == rootIMXToken) {
emit IMXDeposit(address(rootToken), msg.sender, receiver, amount);
} else {
Expand Down
4 changes: 2 additions & 2 deletions test/integration/root/RootERC20Bridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ contract RootERC20BridgeIntegrationTest is Test, IRootERC20BridgeEvents, IRootAx
vm.expectEmit(address(axelarAdaptor));
emit MapTokenAxelarMessage(CHILD_CHAIN_NAME, childBridgeAdaptorString, predictedPayload);
vm.expectEmit(address(rootBridge));
emit NativeEthDeposit(
address(NATIVE_ETH), rootBridge.childETHToken(), address(this), address(this), tokenAmount
emit WETHDeposit(
address(WRAPPED_ETH), address(this), address(this), tokenAmount
);
vm.expectCall(
address(axelarAdaptor),
Expand Down
6 changes: 3 additions & 3 deletions test/unit/root/RootERC20Bridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -338,17 +338,17 @@ contract RootERC20BridgeUnitTest is Test, IRootERC20BridgeEvents, IRootERC20Brid
setupDeposit(WRAPPED_ETH, rootBridge, mapTokenFee, depositFee, amount, false);

vm.expectEmit();
emit NativeEthDeposit(NATIVE_ETH, rootBridge.childETHToken(), address(this), address(this), amount);
emit WETHDeposit(WRAPPED_ETH, address(this), address(this), amount);
rootBridge.deposit{value: depositFee}(IERC20Metadata(WRAPPED_ETH), amount);
}

function test_depositToWETHEmitsNativeEthDepositEvent() public {
function test_depositToWETHEmitsWETHDepositEvent() public {
uint256 amount = 1000;
address receiver = address(12345);
setupDepositTo(WRAPPED_ETH, rootBridge, mapTokenFee, depositFee, amount, receiver, false);

vm.expectEmit();
emit NativeEthDeposit(NATIVE_ETH, rootBridge.childETHToken(), address(this), receiver, amount);
emit WETHDeposit(WRAPPED_ETH, address(this), receiver, amount);
rootBridge.depositTo{value: depositFee}(IERC20Metadata(WRAPPED_ETH), receiver, amount);
}

Expand Down

0 comments on commit f2beb02

Please sign in to comment.