Skip to content

Commit

Permalink
Merge pull request #9 from bnb-chain/contracts-withdraw-fee-to-l1
Browse files Browse the repository at this point in the history
contracts: add function "withdrawFeeToL1"
  • Loading branch information
bendanzhentan authored Nov 24, 2023
2 parents b97601d + 798a563 commit 8f95ec2
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
19 changes: 18 additions & 1 deletion contracts/src/L2StandardBridgeBot.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity 0.8.20;
import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

// See also https://github.com/bnb-chain/opbnb/blob/9505ae88d0ec8f593ee036284c9a13672526a232/packages/contracts-bedrock/contracts/L2/L2StandardBridge.sol#L20
interface IL2StandardBridge {
function withdrawTo(
address _l2Token,
Expand Down Expand Up @@ -51,6 +52,7 @@ contract L2StandardBridgeBot is Ownable {
require(approveSuccess, "BEP20 withdrawal: approve failed");
bool transferSuccess = l2Token.transferFrom(msg.sender, address(this), _amount);
require(transferSuccess, "BEP20 withdrawal: transferFrom failed");

L2_STANDARD_BRIDGE.withdrawTo{value: 0}(_l2Token, _to, _amount, _minGasLimit, _extraData);
}

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

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

// withdrawFeeToL1 withdraw the delegation fee vault to _recipient address on L1, only owner can call this function.
function withdrawFeeToL1(address _recipient, uint32 _minGasLimit, bytes calldata _extraData) external onlyOwner {
uint256 _balance = address(this).balance;
require(_balance > delegationFee, "fee vault balance is insufficient to pay the required delegation fee");

uint256 _amount = _balance - delegationFee;
this.withdrawTo{ value: _balance }(
LEGACY_ERC20_ETH,
_recipient,
_amount,
_minGasLimit,
_extraData
);
}

// setDelegationFee set the delegation fee, only owner can call this function.
function setDelegationFee(uint256 _delegationFee) external onlyOwner {
delegationFee = _delegationFee;
Expand Down
47 changes: 47 additions & 0 deletions contracts/test/L2StandardBridgeBot.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ contract L2StandardBridgeBotTest is Test {
address user = 0x3977f9B1F4912a783B44aBa813dA388AC73a1428;
uint withdrawFee = 10000;
address constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000;
address constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;

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

event SentMessageExtension1(address indexed sender , uint256 value);

function setUp() public {
opbnbMainnetFork = vm.createFork("https://opbnb-testnet-rpc.bnbchain.org");
vm.selectFork(opbnbMainnetFork);
Expand Down Expand Up @@ -53,4 +56,48 @@ contract L2StandardBridgeBotTest is Test {
emit WithdrawTo(user, usdt, user, amount, 200000, "");
bot.withdrawTo{value: withdrawFee}(usdt, user, amount, 200000, "");
}

function test_RevertWithdrawFeeNotOwner() public {
vm.prank(user);
vm.expectRevert();
bot.withdrawFee(user);
}

function test_WithdrawFee() public {
vm.prank(deployer);
bot.withdrawFee(user);
}

function test_RevertWithdrawFeeToL1NotOwner() public {
vm.prank(user);
vm.expectRevert();
bot.withdrawFeeToL1(user, 0, "");
}

function test_RevertWithdrawFeeToL1InsufficientBalance() public {
vm.prank(deployer);
vm.expectRevert();
bot.withdrawFeeToL1(user, 0, "");
}

function test_WithdrawFeeToL1() public {
// Ensure the vault has sufficient balance
uint256 prevBalance = address(bot).balance;

vm.prank(user);
uint amount = 0;
uint round = 10;
for (uint i = 0; i < round; i++) {
bot.withdrawTo{value: withdrawFee + amount}(LEGACY_ERC20_ETH, user, amount, 200000, "");
}

uint256 postBalance = address(bot).balance;
assertEq(postBalance, prevBalance + withdrawFee * round);

// WithdrawFeeToL1
vm.prank(deployer);
vm.expectEmit(true, true, true, true);
emit SentMessageExtension1(L2_STANDARD_BRIDGE, postBalance - withdrawFee);
bot.withdrawFeeToL1(user, 0, "");
}
}

0 comments on commit 8f95ec2

Please sign in to comment.