mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-04-23 03:00:50 -04:00
add unit tests for L2USDCGateway
This commit is contained in:
@@ -152,7 +152,7 @@ contract L1USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20Gateway
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
// 3. Generate message passed to L2USDCGateway.
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
_token,
|
||||
|
||||
@@ -90,7 +90,7 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
|
||||
require(_l2Token == l2USDC, "l2 token not USDC");
|
||||
require(!depositPaused, "deposit paused");
|
||||
|
||||
IFiatToken(_l2Token).mint(_to, _amount);
|
||||
require(IFiatToken(_l2Token).mint(_to, _amount), "mint USDC failed");
|
||||
|
||||
emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data);
|
||||
}
|
||||
@@ -135,9 +135,9 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
|
||||
|
||||
// 2. Transfer token into this contract.
|
||||
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
|
||||
IFiatToken(_token).burn(_amount);
|
||||
require(IFiatToken(_token).burn(_amount), "burn USDC failed");
|
||||
|
||||
// 3. Generate message passed to L2StandardERC20Gateway.
|
||||
// 3. Generate message passed to L1USDCGateway.
|
||||
address _l1USDC = l1USDC;
|
||||
bytes memory _message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
|
||||
@@ -19,7 +19,18 @@ contract MockERC20 is ERC20 {
|
||||
return decimals_;
|
||||
}
|
||||
|
||||
function mint(address _recipient, uint256 _amount) external {
|
||||
function mint(address _recipient, uint256 _amount) external returns (bool) {
|
||||
_mint(_recipient, _amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function burn(uint256 _amount) external returns (bool) {
|
||||
_burn(msg.sender, _amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
function burn(address _from, uint256 _amount) public virtual returns (bool) {
|
||||
_burn(_from, _amount);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
594
contracts/src/test/L2USDCGatewayTest.t.sol
Normal file
594
contracts/src/test/L2USDCGatewayTest.t.sol
Normal file
@@ -0,0 +1,594 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {IL1ERC20Gateway, L1USDCGateway} from "../L1/gateways/usdc/L1USDCGateway.sol";
|
||||
import {L2GatewayRouter} from "../L2/gateways/L2GatewayRouter.sol";
|
||||
import {IL2ERC20Gateway, L2USDCGateway} from "../L2/gateways/usdc/L2USDCGateway.sol";
|
||||
|
||||
import {MockERC20} from "../mocks/MockERC20.sol";
|
||||
|
||||
import {L2GatewayTestBase} from "./L2GatewayTestBase.t.sol";
|
||||
import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol";
|
||||
|
||||
contract L2USDCGatewayTest is L2GatewayTestBase {
|
||||
// from L2USDCGateway
|
||||
event WithdrawERC20(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes _data
|
||||
);
|
||||
event FinalizeDepositERC20(
|
||||
address indexed _l1Token,
|
||||
address indexed _l2Token,
|
||||
address indexed _from,
|
||||
address _to,
|
||||
uint256 _amount,
|
||||
bytes _data
|
||||
);
|
||||
|
||||
MockERC20 private l1USDC;
|
||||
MockERC20 private l2USDC;
|
||||
|
||||
L2USDCGateway private gateway;
|
||||
L2GatewayRouter private router;
|
||||
|
||||
L1USDCGateway private counterpartGateway;
|
||||
|
||||
function setUp() public {
|
||||
setUpBase();
|
||||
|
||||
// Deploy tokens
|
||||
l1USDC = new MockERC20("USDC", "USDC", 6);
|
||||
l2USDC = new MockERC20("USDC", "USDC", 6);
|
||||
|
||||
// Deploy L2 contracts
|
||||
gateway = new L2USDCGateway(address(l1USDC), address(l2USDC));
|
||||
router = new L2GatewayRouter();
|
||||
|
||||
// Deploy L1 contracts
|
||||
counterpartGateway = new L1USDCGateway(address(l1USDC), address(l2USDC));
|
||||
|
||||
// Initialize L2 contracts
|
||||
gateway.initialize(address(counterpartGateway), address(router), address(l2Messenger));
|
||||
router.initialize(address(0), address(gateway));
|
||||
|
||||
// Prepare token balances
|
||||
l2USDC.mint(address(this), type(uint128).max);
|
||||
l2USDC.approve(address(gateway), type(uint256).max);
|
||||
}
|
||||
|
||||
function testInitialized() public {
|
||||
assertEq(address(counterpartGateway), gateway.counterpart());
|
||||
assertEq(address(router), gateway.router());
|
||||
assertEq(address(l2Messenger), gateway.messenger());
|
||||
assertEq(address(l1USDC), gateway.l1USDC());
|
||||
assertEq(address(l2USDC), gateway.l2USDC());
|
||||
assertEq(address(l1USDC), gateway.getL1ERC20Address(address(l2USDC)));
|
||||
assertEq(address(l2USDC), gateway.getL2ERC20Address(address(l1USDC)));
|
||||
|
||||
hevm.expectRevert("Initializable: contract is already initialized");
|
||||
gateway.initialize(address(counterpartGateway), address(router), address(l2Messenger));
|
||||
}
|
||||
|
||||
function testWithdrawPaused() public {
|
||||
// non-owner call pause, should revert
|
||||
hevm.startPrank(address(1));
|
||||
hevm.expectRevert("Ownable: caller is not the owner");
|
||||
gateway.pauseWithdraw(false);
|
||||
hevm.expectRevert("Ownable: caller is not the owner");
|
||||
gateway.pauseWithdraw(true);
|
||||
hevm.stopPrank();
|
||||
|
||||
// pause withdraw
|
||||
gateway.pauseWithdraw(true);
|
||||
|
||||
// deposit paused, should revert
|
||||
hevm.expectRevert("withdraw paused");
|
||||
gateway.withdrawERC20(address(l2USDC), 1, 0);
|
||||
hevm.expectRevert("withdraw paused");
|
||||
gateway.withdrawERC20(address(l2USDC), address(this), 1, 0);
|
||||
hevm.expectRevert("withdraw paused");
|
||||
gateway.withdrawERC20AndCall(address(l2USDC), address(this), 1, new bytes(0), 0);
|
||||
}
|
||||
|
||||
function testPauseDeposit() public {
|
||||
// non-owner call pause, should revert
|
||||
hevm.startPrank(address(1));
|
||||
hevm.expectRevert("Ownable: caller is not the owner");
|
||||
gateway.pauseDeposit(false);
|
||||
hevm.expectRevert("Ownable: caller is not the owner");
|
||||
gateway.pauseDeposit(true);
|
||||
hevm.stopPrank();
|
||||
}
|
||||
|
||||
function testWithdrawERC20(
|
||||
uint256 amount,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) public {
|
||||
_withdrawERC20(false, amount, gasLimit, feePerGas);
|
||||
}
|
||||
|
||||
function testWithdrawERC20WithRecipient(
|
||||
uint256 amount,
|
||||
address recipient,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) public {
|
||||
_withdrawERC20WithRecipient(false, amount, recipient, gasLimit, feePerGas);
|
||||
}
|
||||
|
||||
function testWithdrawERC20WithRecipientAndCalldata(
|
||||
uint256 amount,
|
||||
address recipient,
|
||||
bytes memory dataToCall,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) public {
|
||||
_withdrawERC20WithRecipientAndCalldata(false, amount, recipient, dataToCall, gasLimit, feePerGas);
|
||||
}
|
||||
|
||||
function testRouterDepositERC20(
|
||||
uint256 amount,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) public {
|
||||
_withdrawERC20(true, amount, gasLimit, feePerGas);
|
||||
}
|
||||
|
||||
function testRouterDepositERC20WithRecipient(
|
||||
uint256 amount,
|
||||
address recipient,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) public {
|
||||
_withdrawERC20WithRecipient(true, amount, recipient, gasLimit, feePerGas);
|
||||
}
|
||||
|
||||
function testRouterDepositERC20WithRecipientAndCalldata(
|
||||
uint256 amount,
|
||||
address recipient,
|
||||
bytes memory dataToCall,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) public {
|
||||
_withdrawERC20WithRecipientAndCalldata(true, amount, recipient, dataToCall, gasLimit, feePerGas);
|
||||
}
|
||||
|
||||
function testFinalizeDepositERC20FailedMocking(
|
||||
address sender,
|
||||
address recipient,
|
||||
uint256 amount,
|
||||
bytes memory dataToCall
|
||||
) public {
|
||||
amount = bound(amount, 1, 100000);
|
||||
|
||||
// revert when caller is not messenger
|
||||
hevm.expectRevert("only messenger can call");
|
||||
gateway.finalizeDepositERC20(address(l1USDC), address(l2USDC), sender, recipient, amount, dataToCall);
|
||||
|
||||
MockScrollMessenger mockMessenger = new MockScrollMessenger();
|
||||
gateway = new L2USDCGateway(address(l1USDC), address(l2USDC));
|
||||
gateway.initialize(address(counterpartGateway), address(router), address(mockMessenger));
|
||||
|
||||
// only call by conterpart
|
||||
hevm.expectRevert("only call by conterpart");
|
||||
mockMessenger.callTarget(
|
||||
address(gateway),
|
||||
abi.encodeWithSelector(
|
||||
gateway.finalizeDepositERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l2USDC),
|
||||
sender,
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall
|
||||
)
|
||||
);
|
||||
|
||||
mockMessenger.setXDomainMessageSender(address(counterpartGateway));
|
||||
|
||||
// nonzero msg.value
|
||||
hevm.expectRevert("nonzero msg.value");
|
||||
mockMessenger.callTarget{value: 1}(
|
||||
address(gateway),
|
||||
abi.encodeWithSelector(
|
||||
gateway.finalizeDepositERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l2USDC),
|
||||
sender,
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall
|
||||
)
|
||||
);
|
||||
|
||||
// l1 token not USDC
|
||||
hevm.expectRevert("l1 token not USDC");
|
||||
mockMessenger.callTarget(
|
||||
address(gateway),
|
||||
abi.encodeWithSelector(
|
||||
gateway.finalizeDepositERC20.selector,
|
||||
address(l2USDC),
|
||||
address(l2USDC),
|
||||
sender,
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall
|
||||
)
|
||||
);
|
||||
|
||||
// l2 token not USDC
|
||||
hevm.expectRevert("l2 token not USDC");
|
||||
mockMessenger.callTarget(
|
||||
address(gateway),
|
||||
abi.encodeWithSelector(
|
||||
gateway.finalizeDepositERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l1USDC),
|
||||
sender,
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function testFinalizeDepositERC20Failed(
|
||||
address sender,
|
||||
address recipient,
|
||||
uint256 amount,
|
||||
bytes memory dataToCall
|
||||
) public {
|
||||
// blacklist some addresses
|
||||
hevm.assume(recipient != address(0));
|
||||
hevm.assume(recipient != address(gateway));
|
||||
|
||||
amount = bound(amount, 1, l2USDC.balanceOf(address(this)));
|
||||
|
||||
// send some USDC to L2ScrollMessenger
|
||||
gateway.withdrawERC20(address(l2USDC), amount, 21000);
|
||||
|
||||
// do finalize withdraw eth
|
||||
bytes memory message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l2USDC),
|
||||
sender,
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall
|
||||
);
|
||||
bytes memory xDomainCalldata = abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(uint160(address(counterpartGateway)) + 1),
|
||||
address(gateway),
|
||||
0,
|
||||
0,
|
||||
message
|
||||
);
|
||||
|
||||
// conterpart is not L1USDCGateway
|
||||
// emit FailedRelayedMessage from L2ScrollMessenger
|
||||
hevm.expectEmit(true, false, false, true);
|
||||
emit FailedRelayedMessage(keccak256(xDomainCalldata));
|
||||
|
||||
uint256 gatewayBalance = l2USDC.balanceOf(address(gateway));
|
||||
uint256 recipientBalance = l2USDC.balanceOf(recipient);
|
||||
assertBoolEq(false, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata)));
|
||||
l2Messenger.relayMessage(address(uint160(address(counterpartGateway)) + 1), address(gateway), 0, 0, message);
|
||||
assertEq(gatewayBalance, l2USDC.balanceOf(address(gateway)));
|
||||
assertEq(recipientBalance, l2USDC.balanceOf(recipient));
|
||||
assertBoolEq(false, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata)));
|
||||
}
|
||||
|
||||
function testFinalizeDepositERC20(
|
||||
address sender,
|
||||
address recipient,
|
||||
uint256 amount,
|
||||
bytes memory dataToCall
|
||||
) public {
|
||||
// blacklist some addresses
|
||||
hevm.assume(recipient != address(0));
|
||||
|
||||
amount = bound(amount, 1, l2USDC.balanceOf(address(this)));
|
||||
|
||||
// send some USDC to L1ScrollMessenger
|
||||
gateway.withdrawERC20(address(l2USDC), amount, 21000);
|
||||
|
||||
// do finalize withdraw USDC
|
||||
bytes memory message = abi.encodeWithSelector(
|
||||
IL2ERC20Gateway.finalizeDepositERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l2USDC),
|
||||
sender,
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall
|
||||
);
|
||||
bytes memory xDomainCalldata = abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(counterpartGateway),
|
||||
address(gateway),
|
||||
0,
|
||||
0,
|
||||
message
|
||||
);
|
||||
|
||||
// emit FinalizeDepositERC20 from L2USDCGateway
|
||||
{
|
||||
hevm.expectEmit(true, true, true, true);
|
||||
emit FinalizeDepositERC20(address(l1USDC), address(l2USDC), sender, recipient, amount, dataToCall);
|
||||
}
|
||||
|
||||
// emit RelayedMessage from L2ScrollMessenger
|
||||
{
|
||||
hevm.expectEmit(true, false, false, true);
|
||||
emit RelayedMessage(keccak256(xDomainCalldata));
|
||||
}
|
||||
|
||||
uint256 gatewayBalance = l2USDC.balanceOf(address(gateway));
|
||||
uint256 recipientBalance = l2USDC.balanceOf(recipient);
|
||||
assertBoolEq(false, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata)));
|
||||
l2Messenger.relayMessage(address(counterpartGateway), address(gateway), 0, 0, message);
|
||||
assertEq(gatewayBalance, l2USDC.balanceOf(address(gateway)));
|
||||
assertEq(recipientBalance + amount, l2USDC.balanceOf(recipient));
|
||||
assertBoolEq(true, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata)));
|
||||
}
|
||||
|
||||
function _withdrawERC20(
|
||||
bool useRouter,
|
||||
uint256 amount,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) private {
|
||||
amount = bound(amount, 0, l2USDC.balanceOf(address(this)));
|
||||
gasLimit = bound(gasLimit, 21000, 1000000);
|
||||
feePerGas = bound(feePerGas, 0, 1000);
|
||||
|
||||
setL1BaseFee(feePerGas);
|
||||
|
||||
uint256 feeToPay = feePerGas * gasLimit;
|
||||
bytes memory message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l2USDC),
|
||||
address(this),
|
||||
address(this),
|
||||
amount,
|
||||
new bytes(0)
|
||||
);
|
||||
bytes memory xDomainCalldata = abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(gateway),
|
||||
address(counterpartGateway),
|
||||
0,
|
||||
0,
|
||||
message
|
||||
);
|
||||
|
||||
if (amount == 0) {
|
||||
hevm.expectRevert("withdraw zero amount");
|
||||
if (useRouter) {
|
||||
router.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), amount, gasLimit);
|
||||
} else {
|
||||
gateway.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), amount, gasLimit);
|
||||
}
|
||||
} else {
|
||||
// token is not l2USDC
|
||||
hevm.expectRevert("only USDC is allowed");
|
||||
gateway.withdrawERC20(address(l1USDC), amount, gasLimit);
|
||||
|
||||
// emit AppendMessage from L2MessageQueue
|
||||
{
|
||||
hevm.expectEmit(false, false, false, true);
|
||||
emit AppendMessage(0, keccak256(xDomainCalldata));
|
||||
}
|
||||
|
||||
// emit SentMessage from L2ScrollMessenger
|
||||
{
|
||||
hevm.expectEmit(true, true, false, true);
|
||||
emit SentMessage(address(gateway), address(counterpartGateway), 0, 0, gasLimit, message);
|
||||
}
|
||||
|
||||
// emit WithdrawERC20 from L2USDCGateway
|
||||
hevm.expectEmit(true, true, true, true);
|
||||
emit WithdrawERC20(address(l1USDC), address(l2USDC), address(this), address(this), amount, new bytes(0));
|
||||
|
||||
uint256 senderBalance = l2USDC.balanceOf(address(this));
|
||||
uint256 gatewayBalance = l2USDC.balanceOf(address(gateway));
|
||||
uint256 feeVaultBalance = address(feeVault).balance;
|
||||
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
|
||||
if (useRouter) {
|
||||
router.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), amount, gasLimit);
|
||||
} else {
|
||||
gateway.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), amount, gasLimit);
|
||||
}
|
||||
assertEq(senderBalance - amount, l2USDC.balanceOf(address(this)));
|
||||
assertEq(gatewayBalance, l2USDC.balanceOf(address(gateway)));
|
||||
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
|
||||
assertBoolEq(true, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
|
||||
}
|
||||
}
|
||||
|
||||
function _withdrawERC20WithRecipient(
|
||||
bool useRouter,
|
||||
uint256 amount,
|
||||
address recipient,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) private {
|
||||
amount = bound(amount, 0, l2USDC.balanceOf(address(this)));
|
||||
gasLimit = bound(gasLimit, 21000, 1000000);
|
||||
feePerGas = bound(feePerGas, 0, 1000);
|
||||
|
||||
setL1BaseFee(feePerGas);
|
||||
|
||||
uint256 feeToPay = feePerGas * gasLimit;
|
||||
bytes memory message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l2USDC),
|
||||
address(this),
|
||||
recipient,
|
||||
amount,
|
||||
new bytes(0)
|
||||
);
|
||||
bytes memory xDomainCalldata = abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(gateway),
|
||||
address(counterpartGateway),
|
||||
0,
|
||||
0,
|
||||
message
|
||||
);
|
||||
|
||||
if (amount == 0) {
|
||||
hevm.expectRevert("withdraw zero amount");
|
||||
if (useRouter) {
|
||||
router.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), recipient, amount, gasLimit);
|
||||
} else {
|
||||
gateway.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), recipient, amount, gasLimit);
|
||||
}
|
||||
} else {
|
||||
// token is not l1USDC
|
||||
hevm.expectRevert("only USDC is allowed");
|
||||
gateway.withdrawERC20(address(l1USDC), recipient, amount, gasLimit);
|
||||
|
||||
// emit AppendMessage from L2MessageQueue
|
||||
{
|
||||
hevm.expectEmit(false, false, false, true);
|
||||
emit AppendMessage(0, keccak256(xDomainCalldata));
|
||||
}
|
||||
|
||||
// emit SentMessage from L2ScrollMessenger
|
||||
{
|
||||
hevm.expectEmit(true, true, false, true);
|
||||
emit SentMessage(address(gateway), address(counterpartGateway), 0, 0, gasLimit, message);
|
||||
}
|
||||
|
||||
// emit WithdrawERC20 from L2USDCGateway
|
||||
hevm.expectEmit(true, true, true, true);
|
||||
emit WithdrawERC20(address(l1USDC), address(l2USDC), address(this), recipient, amount, new bytes(0));
|
||||
|
||||
uint256 senderBalance = l2USDC.balanceOf(address(this));
|
||||
uint256 gatewayBalance = l2USDC.balanceOf(address(gateway));
|
||||
uint256 feeVaultBalance = address(feeVault).balance;
|
||||
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
|
||||
if (useRouter) {
|
||||
router.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), recipient, amount, gasLimit);
|
||||
} else {
|
||||
gateway.withdrawERC20{value: feeToPay + extraValue}(address(l2USDC), recipient, amount, gasLimit);
|
||||
}
|
||||
assertEq(senderBalance - amount, l2USDC.balanceOf(address(this)));
|
||||
assertEq(gatewayBalance, l2USDC.balanceOf(address(gateway)));
|
||||
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
|
||||
assertBoolEq(true, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
|
||||
}
|
||||
}
|
||||
|
||||
function _withdrawERC20WithRecipientAndCalldata(
|
||||
bool useRouter,
|
||||
uint256 amount,
|
||||
address recipient,
|
||||
bytes memory dataToCall,
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) private {
|
||||
amount = bound(amount, 0, l2USDC.balanceOf(address(this)));
|
||||
gasLimit = bound(gasLimit, 21000, 1000000);
|
||||
feePerGas = bound(feePerGas, 0, 1000);
|
||||
|
||||
setL1BaseFee(feePerGas);
|
||||
|
||||
uint256 feeToPay = feePerGas * gasLimit;
|
||||
bytes memory message = abi.encodeWithSelector(
|
||||
IL1ERC20Gateway.finalizeWithdrawERC20.selector,
|
||||
address(l1USDC),
|
||||
address(l2USDC),
|
||||
address(this),
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall
|
||||
);
|
||||
bytes memory xDomainCalldata = abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(gateway),
|
||||
address(counterpartGateway),
|
||||
0,
|
||||
0,
|
||||
message
|
||||
);
|
||||
|
||||
if (amount == 0) {
|
||||
hevm.expectRevert("withdraw zero amount");
|
||||
if (useRouter) {
|
||||
router.withdrawERC20AndCall{value: feeToPay + extraValue}(
|
||||
address(l2USDC),
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall,
|
||||
gasLimit
|
||||
);
|
||||
} else {
|
||||
gateway.withdrawERC20AndCall{value: feeToPay + extraValue}(
|
||||
address(l2USDC),
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall,
|
||||
gasLimit
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// token is not l1USDC
|
||||
hevm.expectRevert("only USDC is allowed");
|
||||
gateway.withdrawERC20AndCall(address(l1USDC), recipient, amount, dataToCall, gasLimit);
|
||||
|
||||
// emit AppendMessage from L2MessageQueue
|
||||
{
|
||||
hevm.expectEmit(false, false, false, true);
|
||||
emit AppendMessage(0, keccak256(xDomainCalldata));
|
||||
}
|
||||
|
||||
// emit SentMessage from L2ScrollMessenger
|
||||
{
|
||||
hevm.expectEmit(true, true, false, true);
|
||||
emit SentMessage(address(gateway), address(counterpartGateway), 0, 0, gasLimit, message);
|
||||
}
|
||||
|
||||
// emit WithdrawERC20 from L2USDCGateway
|
||||
hevm.expectEmit(true, true, true, true);
|
||||
emit WithdrawERC20(address(l1USDC), address(l2USDC), address(this), recipient, amount, dataToCall);
|
||||
|
||||
uint256 senderBalance = l2USDC.balanceOf(address(this));
|
||||
uint256 gatewayBalance = l2USDC.balanceOf(address(gateway));
|
||||
uint256 feeVaultBalance = address(feeVault).balance;
|
||||
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
|
||||
if (useRouter) {
|
||||
router.withdrawERC20AndCall{value: feeToPay + extraValue}(
|
||||
address(l2USDC),
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall,
|
||||
gasLimit
|
||||
);
|
||||
} else {
|
||||
gateway.withdrawERC20AndCall{value: feeToPay + extraValue}(
|
||||
address(l2USDC),
|
||||
recipient,
|
||||
amount,
|
||||
dataToCall,
|
||||
gasLimit
|
||||
);
|
||||
}
|
||||
assertEq(senderBalance - amount, l2USDC.balanceOf(address(this)));
|
||||
assertEq(gatewayBalance, l2USDC.balanceOf(address(gateway)));
|
||||
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
|
||||
assertBoolEq(true, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,7 +403,7 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) private {
|
||||
amount = bound(amount, 0, l1weth.balanceOf(address(this)));
|
||||
amount = bound(amount, 0, l2weth.balanceOf(address(this)));
|
||||
gasLimit = bound(gasLimit, 21000, 1000000);
|
||||
feePerGas = bound(feePerGas, 0, 1000);
|
||||
|
||||
@@ -478,7 +478,7 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
|
||||
uint256 gasLimit,
|
||||
uint256 feePerGas
|
||||
) private {
|
||||
amount = bound(amount, 0, l1weth.balanceOf(address(this)));
|
||||
amount = bound(amount, 0, l2weth.balanceOf(address(this)));
|
||||
gasLimit = bound(gasLimit, 21000, 1000000);
|
||||
feePerGas = bound(feePerGas, 0, 1000);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user