Skip to content

Commit

Permalink
Add maxWithdraws to L2TokenBridge (#6)
Browse files Browse the repository at this point in the history
Co-authored-by: telome <>
  • Loading branch information
telome authored Oct 1, 2024
1 parent a01b872 commit d0c8983
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 3 deletions.
12 changes: 11 additions & 1 deletion deploy/L2TokenBridgeSpell.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ interface L2TokenBridgeLike {
function deny(address) external;
function close() external;
function registerToken(address, address) external;
function setMaxWithdraw(address, uint256) external;
}

interface AuthLike {
Expand All @@ -54,6 +55,13 @@ contract L2TokenBridgeSpell {
unchecked { ++i; }
}
}

function setMaxWithdraws(address[] memory l2Tokens, uint256[] memory maxWithdraws) public {
for (uint256 i; i < l2Tokens.length;) {
l2Bridge.setMaxWithdraw(l2Tokens[i], maxWithdraws[i]);
unchecked { ++i; }
}
}

function init(
address l2GovRelay_,
Expand All @@ -62,7 +70,8 @@ contract L2TokenBridgeSpell {
address l1Bridge,
address l2Messenger,
address[] calldata l1Tokens,
address[] calldata l2Tokens
address[] calldata l2Tokens,
uint256[] calldata maxWithdraws
) external {
L2GovRelayLike l2GovRelay = L2GovRelayLike(l2GovRelay_);

Expand All @@ -75,5 +84,6 @@ contract L2TokenBridgeSpell {
require(l2GovRelay.messenger() == l2Messenger, "L2TokenBridgeSpell/l2-gov-relay-messenger-mismatch");

registerTokens(l1Tokens, l2Tokens);
setMaxWithdraws(l2Tokens, maxWithdraws);
}
}
6 changes: 5 additions & 1 deletion deploy/TokenBridgeInit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct BridgesConfig {
address l2Messenger;
address[] l1Tokens;
address[] l2Tokens;
uint256[] maxWithdraws;
uint32 minGasLimit;
bytes32 govRelayCLKey;
bytes32 escrowCLKey;
Expand All @@ -73,6 +74,7 @@ library TokenBridgeInit {
require(l1GovRelay.l2GovernanceRelay() == l2BridgeInstance.govRelay, "TokenBridgeInit/l2-gov-relay-mismatch");
require(l1GovRelay.messenger() == cfg.l1Messenger, "TokenBridgeInit/l1-gov-relay-messenger-mismatch");
require(cfg.l1Tokens.length == cfg.l2Tokens.length, "TokenBridgeInit/token-arrays-mismatch");
require(cfg.maxWithdraws.length == cfg.l2Tokens.length, "TokenBridgeInit/max-withdraws-length-mismatch");
require(cfg.minGasLimit <= 1_000_000_000, "TokenBridgeInit/min-gas-limit-out-of-bounds");

l1Bridge.file("escrow", address(escrow));
Expand All @@ -81,6 +83,7 @@ library TokenBridgeInit {
(address l1Token, address l2Token) = (cfg.l1Tokens[i], cfg.l2Tokens[i]);
require(l1Token != address(0), "TokenBridgeInit/invalid-l1-token");
require(l2Token != address(0), "TokenBridgeInit/invalid-l2-token");
require(cfg.maxWithdraws[i] > 0, "TokenBridgeInit/max-withdraw-not-set");
require(l1Bridge.l1ToL2Token(l1Token) == address(0), "TokenBridgeInit/existing-l1-token");

l1Bridge.registerToken(l1Token, l2Token);
Expand All @@ -96,7 +99,8 @@ library TokenBridgeInit {
address(l1Bridge),
cfg.l2Messenger,
cfg.l1Tokens,
cfg.l2Tokens
cfg.l2Tokens,
cfg.maxWithdraws
)),
minGasLimit: cfg.minGasLimit
});
Expand Down
4 changes: 4 additions & 0 deletions script/Init.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,14 @@ contract Init is Script {
cfg.l2Messenger = deps.readAddress(".l2Messenger");
cfg.l1Tokens = deps.readAddressArray(".l1Tokens");
cfg.l2Tokens = deps.readAddressArray(".l2Tokens");
cfg.maxWithdraws = new uint256[](cfg.l2Tokens.length);
cfg.minGasLimit = 100_000;
cfg.govRelayCLKey = l2Domain.readConfigBytes32FromString("govRelayCLKey");
cfg.escrowCLKey = l2Domain.readConfigBytes32FromString("escrowCLKey");
cfg.l1BridgeCLKey = l2Domain.readConfigBytes32FromString("l1BridgeCLKey");
for (uint256 i; i < cfg.maxWithdraws.length; ++i) {
cfg.maxWithdraws[i] = 10_000_000 ether;
}

L1TokenBridgeInstance memory l1BridgeInstance = L1TokenBridgeInstance({
govRelay: deps.readAddress(".l1GovRelay"),
Expand Down
8 changes: 8 additions & 0 deletions src/L2TokenBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ contract L2TokenBridge {

mapping(address => uint256) public wards;
mapping(address => address) public l1ToL2Token;
mapping(address => uint256) public maxWithdraws;
uint256 public isOpen = 1;

// --- immutables ---
Expand All @@ -45,6 +46,7 @@ contract L2TokenBridge {
event Deny(address indexed usr);
event Closed();
event TokenSet(address indexed l1Token, address indexed l2Token);
event MaxWithdrawSet(address indexed l2Token, uint256 maxWithdraw);
event ERC20BridgeInitiated(
address indexed localToken,
address indexed remoteToken,
Expand Down Expand Up @@ -112,6 +114,11 @@ contract L2TokenBridge {
emit TokenSet(l1Token, l2Token);
}

function setMaxWithdraw(address l2Token, uint256 maxWithdraw) external auth {
maxWithdraws[l2Token] = maxWithdraw;
emit MaxWithdrawSet(l2Token, maxWithdraw);
}

// -- bridging --

function _initiateBridgeERC20(
Expand All @@ -124,6 +131,7 @@ contract L2TokenBridge {
) internal {
require(isOpen == 1, "L2TokenBridge/closed"); // do not allow initiating new xchain messages if bridge is closed
require(_localToken != address(0) && l1ToL2Token[_remoteToken] == _localToken, "L2TokenBridge/invalid-token");
require(_amount <= maxWithdraws[_localToken], "L2TokenBridge/amount-too-large");

TokenLike(_localToken).burn(msg.sender, _amount); // TODO: should l2Tokens allow authed burn?

Expand Down
4 changes: 4 additions & 0 deletions test/Integration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,14 @@ contract IntegrationTest is DssTest {
l1Tokens[0] = address(l1Token);
address[] memory l2Tokens = new address[](1);
l2Tokens[0] = address(l2Token);
uint256[] memory maxWithdraws = new uint256[](1);
maxWithdraws[0] = 10_000_000 ether;
BridgesConfig memory cfg = BridgesConfig({
l1Messenger: L1_MESSENGER,
l2Messenger: L2_MESSENGER,
l1Tokens: l1Tokens,
l2Tokens: l2Tokens,
maxWithdraws: maxWithdraws,
minGasLimit: 1_000_000,
govRelayCLKey: "BASE_GOV_RELAY",
escrowCLKey: "BASE_ESCROW",
Expand All @@ -148,6 +151,7 @@ contract IntegrationTest is DssTest {

// test L2 side of initBridges
assertEq(l2Bridge.l1ToL2Token(address(l1Token)), address(l2Token));
assertEq(l2Bridge.maxWithdraws(address(l2Token)), 10_000_000 ether);
assertEq(l2Token.wards(address(l2Bridge)), 1);
}

Expand Down
18 changes: 17 additions & 1 deletion test/L2TokenBridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { MessengerMock } from "test/mocks/MessengerMock.sol";
contract L2TokenBridgeTest is DssTest {

event TokenSet(address indexed l1Address, address indexed l2Address);
event MaxWithdrawSet(address indexed l2Token, uint256 maxWithdraw);
event Closed();
event ERC20BridgeInitiated(
address indexed localToken,
Expand Down Expand Up @@ -66,6 +67,7 @@ contract L2TokenBridgeTest is DssTest {
l2Token.transfer(address(0xe0a), 500_000 ether);
l2Token.rely(address(bridge));
bridge.registerToken(l1Token, address(l2Token));
bridge.setMaxWithdraw(address(l2Token), 1_000_000 ether);
}

function testConstructor() public {
Expand All @@ -88,7 +90,8 @@ contract L2TokenBridgeTest is DssTest {

checkModifier(address(bridge), string(abi.encodePacked("L2TokenBridge", "/not-authorized")), [
bridge.close.selector,
bridge.registerToken.selector
bridge.registerToken.selector,
bridge.setMaxWithdraw.selector
]);
}

Expand All @@ -102,6 +105,16 @@ contract L2TokenBridgeTest is DssTest {
assertEq(bridge.l1ToL2Token(address(11)), address(22));
}

function testSetmaxWithdraw() public {
assertEq(bridge.maxWithdraws(address(22)), 0);

vm.expectEmit(true, true, true, true);
emit MaxWithdrawSet(address(22), 123);
bridge.setMaxWithdraw(address(22), 123);

assertEq(bridge.maxWithdraws(address(22)), 123);
}

function testClose() public {
assertEq(bridge.isOpen(), 1);

Expand Down Expand Up @@ -132,6 +145,9 @@ contract L2TokenBridgeTest is DssTest {
vm.expectRevert("L2TokenBridge/invalid-token");
vm.prank(address(0xe0a)); bridge.bridgeERC20(address(0), address(0xbad), 100 ether, 1_000_000, "");

vm.expectRevert("L2TokenBridge/amount-too-large");
vm.prank(address(0xe0a)); bridge.bridgeERC20(address(l2Token), l1Token, 1_000_000 ether + 1, 1_000_000, "");

uint256 supplyBefore = l2Token.totalSupply();
uint256 eoaBefore = l2Token.balanceOf(address(0xe0a));
vm.prank(address(0xe0a)); l2Token.approve(address(bridge), type(uint256).max);
Expand Down

0 comments on commit d0c8983

Please sign in to comment.