Skip to content

Commit

Permalink
Merge pull request #37 from immutable/SMR-1677-add-withdrawTo-integra…
Browse files Browse the repository at this point in the history
…tion-test

Add integration test for withdrawTo
  • Loading branch information
ermyas authored Nov 15, 2023
2 parents 5a46b04 + 2b02f46 commit 50eb5e2
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 15 deletions.
24 changes: 9 additions & 15 deletions test/integration/child/withdrawals/ChildAxelarBridgeWithdraw.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,20 @@ contract ChildERC20BridgeWithdrawIntegrationTest is
IChildAxelarBridgeAdaptorErrors,
Utils
{
address constant CHILD_BRIDGE = address(3);
address constant CHILD_BRIDGE_ADAPTOR = address(4);
string constant CHILD_CHAIN_NAME = "test";
address constant IMX_TOKEN_ADDRESS = address(0xccc);
address constant NATIVE_ETH = address(0xeee);
address constant WRAPPED_ETH = address(0xddd);

uint256 constant withdrawFee = 200;
uint256 constant withdrawAmount = 99999999999;

ChildERC20Bridge public childBridge;
ChildAxelarBridgeAdaptor public axelarAdaptor;
address public rootToken;
address public rootImxToken;
ChildERC20 public childTokenTemplate;
MockAxelarGasService public axelarGasService;
MockAxelarGasService public mockAxelarGasService;
MockAxelarGateway public mockAxelarGateway;

address receiver = address(0xabcd);

function setUp() public {
(childBridge, axelarAdaptor, rootToken, rootImxToken, childTokenTemplate, axelarGasService, mockAxelarGateway) =
ChildERC20 childTokenTemplate;
(childBridge, axelarAdaptor, rootToken,, childTokenTemplate, mockAxelarGasService, mockAxelarGateway) =
childIntegrationSetup();
}

Expand Down Expand Up @@ -87,10 +81,10 @@ contract ChildERC20BridgeWithdrawIntegrationTest is
bytes memory predictedPayload =
abi.encode(WITHDRAW_SIG, rootToken, address(this), address(this), withdrawAmount);
vm.expectCall(
address(axelarGasService),
address(mockAxelarGasService),
withdrawFee,
abi.encodeWithSelector(
axelarGasService.payNativeGasForContractCall.selector,
mockAxelarGasService.payNativeGasForContractCall.selector,
address(axelarAdaptor),
childBridge.rootChain(),
childBridge.rootERC20BridgeAdaptor(),
Expand All @@ -117,12 +111,12 @@ contract ChildERC20BridgeWithdrawIntegrationTest is
ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(rootToken));

uint256 preBal = childToken.balanceOf(address(this));
uint256 preGasBal = address(axelarGasService).balance;
uint256 preGasBal = address(mockAxelarGasService).balance;

childBridge.withdraw{value: withdrawFee}(childToken, withdrawAmount);

uint256 postBal = childToken.balanceOf(address(this));
uint256 postGasBal = address(axelarGasService).balance;
uint256 postGasBal = address(mockAxelarGasService).balance;

assertEq(postBal, preBal - withdrawAmount, "Balance not reduced");
assertEq(postGasBal, preGasBal + withdrawFee, "Gas not transferred");
Expand Down
126 changes: 126 additions & 0 deletions test/integration/child/withdrawals/ChildAxelarBridgeWithdrawTo.t.sol
Original file line number Diff line number Diff line change
@@ -1 +1,127 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity 0.8.19;

import {Test} from "forge-std/Test.sol";
import {MockAxelarGateway} from "../../../../src/test/root/MockAxelarGateway.sol";
import {MockAxelarGasService} from "../../../../src/test/root/MockAxelarGasService.sol";
import {ChildERC20Bridge, IChildERC20BridgeEvents} from "../../../../src/child/ChildERC20Bridge.sol";
import {
ChildAxelarBridgeAdaptor,
IChildAxelarBridgeAdaptorEvents,
IChildAxelarBridgeAdaptorErrors
} from "../../../../src/child/ChildAxelarBridgeAdaptor.sol";
import {Utils} from "../../../utils.t.sol";
import {ChildERC20} from "../../../../src/child/ChildERC20.sol";

contract ChildERC20BridgeWithdrawToIntegrationTest is
Test,
IChildERC20BridgeEvents,
IChildAxelarBridgeAdaptorEvents,
IChildAxelarBridgeAdaptorErrors,
Utils
{
uint256 constant withdrawFee = 200;
uint256 constant withdrawAmount = 99999999999;

ChildERC20Bridge public childBridge;
ChildAxelarBridgeAdaptor public axelarAdaptor;
address public rootToken;
MockAxelarGasService public mockAxelarGasService;
MockAxelarGateway public mockAxelarGateway;

address receiver = address(0xabcd);

function setUp() public {
ChildERC20 childTokenTemplate;
(childBridge, axelarAdaptor, rootToken,, childTokenTemplate, mockAxelarGasService, mockAxelarGateway) =
childIntegrationSetup();
}

/**
* @dev A future test will assert that the computed childToken is the same as what gets deployed on L2.
* This test uses the same code as the mapToken function does to calculate this address, so we can
* not consider it sufficient.
*/
function test_withdrawTo_CallsBridgeAdaptor() public {
ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(rootToken));

bytes memory predictedPayload = abi.encode(WITHDRAW_SIG, rootToken, address(this), receiver, withdrawAmount);
vm.expectCall(
address(axelarAdaptor),
withdrawFee,
abi.encodeWithSelector(axelarAdaptor.sendMessage.selector, predictedPayload, address(this))
);

childBridge.withdrawTo{value: withdrawFee}(childToken, receiver, withdrawAmount);
}

function test_withdrawTo_CallsAxelarGateway() public {
ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(rootToken));

bytes memory predictedPayload = abi.encode(WITHDRAW_SIG, rootToken, address(this), receiver, withdrawAmount);
vm.expectCall(
address(mockAxelarGateway),
0,
abi.encodeWithSelector(
mockAxelarGateway.callContract.selector,
childBridge.rootChain(),
childBridge.rootERC20BridgeAdaptor(),
predictedPayload
)
);

childBridge.withdrawTo{value: withdrawFee}(childToken, receiver, withdrawAmount);
}

function test_withdrawTo_CallsGasService() public {
ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(rootToken));

bytes memory predictedPayload = abi.encode(WITHDRAW_SIG, rootToken, address(this), receiver, withdrawAmount);
vm.expectCall(
address(mockAxelarGasService),
withdrawFee,
abi.encodeWithSelector(
mockAxelarGasService.payNativeGasForContractCall.selector,
address(axelarAdaptor),
childBridge.rootChain(),
childBridge.rootERC20BridgeAdaptor(),
predictedPayload,
address(this)
)
);

childBridge.withdrawTo{value: withdrawFee}(childToken, receiver, withdrawAmount);
}

function test_withdrawTo_EmitsAxelarMessageSentEvent() public {
ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(rootToken));

bytes memory predictedPayload = abi.encode(WITHDRAW_SIG, rootToken, address(this), receiver, withdrawAmount);

vm.expectEmit(address(axelarAdaptor));
emit AxelarMessageSent(childBridge.rootChain(), childBridge.rootERC20BridgeAdaptor(), predictedPayload);
childBridge.withdrawTo{value: withdrawFee}(childToken, receiver, withdrawAmount);
}

function test_withdrawTo_BurnsFundsAndTransfersGas() public {
ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(rootToken));

uint256 preBal = childToken.balanceOf(address(this));
uint256 preGasBal = address(mockAxelarGasService).balance;

childBridge.withdrawTo{value: withdrawFee}(childToken, receiver, withdrawAmount);

uint256 postBal = childToken.balanceOf(address(this));
uint256 postGasBal = address(mockAxelarGasService).balance;

assertEq(postBal, preBal - withdrawAmount, "Balance not reduced");
assertEq(postGasBal, preGasBal + withdrawFee, "Gas not transferred");
}

function test_RevertIf_WithdrawToCalledWithNoGas() public {
ChildERC20 childToken = ChildERC20(childBridge.rootTokenToChildToken(rootToken));

vm.expectRevert(NoGas.selector);
childBridge.withdrawTo(childToken, receiver, withdrawAmount);
}
}

0 comments on commit 50eb5e2

Please sign in to comment.