Skip to content

Commit 8f95ec2

Browse files
Merge pull request #9 from bnb-chain/contracts-withdraw-fee-to-l1
contracts: add function "withdrawFeeToL1"
2 parents b97601d + 798a563 commit 8f95ec2

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

contracts/src/L2StandardBridgeBot.sol

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pragma solidity 0.8.20;
33
import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol";
44
import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
55

6+
// See also https://github.com/bnb-chain/opbnb/blob/9505ae88d0ec8f593ee036284c9a13672526a232/packages/contracts-bedrock/contracts/L2/L2StandardBridge.sol#L20
67
interface IL2StandardBridge {
78
function withdrawTo(
89
address _l2Token,
@@ -51,6 +52,7 @@ contract L2StandardBridgeBot is Ownable {
5152
require(approveSuccess, "BEP20 withdrawal: approve failed");
5253
bool transferSuccess = l2Token.transferFrom(msg.sender, address(this), _amount);
5354
require(transferSuccess, "BEP20 withdrawal: transferFrom failed");
55+
5456
L2_STANDARD_BRIDGE.withdrawTo{value: 0}(_l2Token, _to, _amount, _minGasLimit, _extraData);
5557
}
5658

@@ -66,12 +68,27 @@ contract L2StandardBridgeBot is Ownable {
6668
withdrawTo(_l2Token, msg.sender, _amount, _minGasLimit, _extraData);
6769
}
6870

69-
// withdrawFee withdraw the delegation fee vault to _recipient address, only owner can call this function.
71+
// withdrawFee withdraw the delegation fee vault to _recipient address on L2, only owner can call this function.
7072
function withdrawFee(address _recipient) external onlyOwner {
7173
(bool sent, ) = _recipient.call{ value: address(this).balance }("");
7274
require(sent, "Failed to send Ether");
7375
}
7476

77+
// withdrawFeeToL1 withdraw the delegation fee vault to _recipient address on L1, only owner can call this function.
78+
function withdrawFeeToL1(address _recipient, uint32 _minGasLimit, bytes calldata _extraData) external onlyOwner {
79+
uint256 _balance = address(this).balance;
80+
require(_balance > delegationFee, "fee vault balance is insufficient to pay the required delegation fee");
81+
82+
uint256 _amount = _balance - delegationFee;
83+
this.withdrawTo{ value: _balance }(
84+
LEGACY_ERC20_ETH,
85+
_recipient,
86+
_amount,
87+
_minGasLimit,
88+
_extraData
89+
);
90+
}
91+
7592
// setDelegationFee set the delegation fee, only owner can call this function.
7693
function setDelegationFee(uint256 _delegationFee) external onlyOwner {
7794
delegationFee = _delegationFee;

contracts/test/L2StandardBridgeBot.t.sol

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ contract L2StandardBridgeBotTest is Test {
1313
address user = 0x3977f9B1F4912a783B44aBa813dA388AC73a1428;
1414
uint withdrawFee = 10000;
1515
address constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000;
16+
address constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;
1617

1718
event WithdrawTo(address indexed from, address l2Token, address to, uint256 amount, uint32 minGasLimit, bytes extraData);
1819

20+
event SentMessageExtension1(address indexed sender , uint256 value);
21+
1922
function setUp() public {
2023
opbnbMainnetFork = vm.createFork("https://opbnb-testnet-rpc.bnbchain.org");
2124
vm.selectFork(opbnbMainnetFork);
@@ -53,4 +56,48 @@ contract L2StandardBridgeBotTest is Test {
5356
emit WithdrawTo(user, usdt, user, amount, 200000, "");
5457
bot.withdrawTo{value: withdrawFee}(usdt, user, amount, 200000, "");
5558
}
59+
60+
function test_RevertWithdrawFeeNotOwner() public {
61+
vm.prank(user);
62+
vm.expectRevert();
63+
bot.withdrawFee(user);
64+
}
65+
66+
function test_WithdrawFee() public {
67+
vm.prank(deployer);
68+
bot.withdrawFee(user);
69+
}
70+
71+
function test_RevertWithdrawFeeToL1NotOwner() public {
72+
vm.prank(user);
73+
vm.expectRevert();
74+
bot.withdrawFeeToL1(user, 0, "");
75+
}
76+
77+
function test_RevertWithdrawFeeToL1InsufficientBalance() public {
78+
vm.prank(deployer);
79+
vm.expectRevert();
80+
bot.withdrawFeeToL1(user, 0, "");
81+
}
82+
83+
function test_WithdrawFeeToL1() public {
84+
// Ensure the vault has sufficient balance
85+
uint256 prevBalance = address(bot).balance;
86+
87+
vm.prank(user);
88+
uint amount = 0;
89+
uint round = 10;
90+
for (uint i = 0; i < round; i++) {
91+
bot.withdrawTo{value: withdrawFee + amount}(LEGACY_ERC20_ETH, user, amount, 200000, "");
92+
}
93+
94+
uint256 postBalance = address(bot).balance;
95+
assertEq(postBalance, prevBalance + withdrawFee * round);
96+
97+
// WithdrawFeeToL1
98+
vm.prank(deployer);
99+
vm.expectEmit(true, true, true, true);
100+
emit SentMessageExtension1(L2_STANDARD_BRIDGE, postBalance - withdrawFee);
101+
bot.withdrawFeeToL1(user, 0, "");
102+
}
56103
}

0 commit comments

Comments
 (0)