Skip to content

Commit bb96529

Browse files
authored
add L2SystemContract (#114)
1 parent 9e18444 commit bb96529

File tree

2 files changed

+213
-0
lines changed

2 files changed

+213
-0
lines changed

src/L2/L2SystemConfig.sol

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity =0.8.24;
4+
5+
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
6+
7+
contract L2SystemConfig is OwnableUpgradeable {
8+
/**********
9+
* Events *
10+
**********/
11+
12+
/// @notice Emitted when the base fee overhead is updated.
13+
/// @param oldBaseFeeOverhead The old base fee overhead.
14+
/// @param newBaseFeeOverhead The new base fee overhead.
15+
event BaseFeeOverheadUpdated(uint256 oldBaseFeeOverhead, uint256 newBaseFeeOverhead);
16+
17+
/// @notice Emitted when the base fee scalar is updated.
18+
/// @param oldBaseFeeScalar The old base fee scalar.
19+
/// @param newBaseFeeScalar The new base fee scalar.
20+
event BaseFeeScalarUpdated(uint256 oldBaseFeeScalar, uint256 newBaseFeeScalar);
21+
22+
/*************
23+
* Constants *
24+
*************/
25+
26+
uint256 private constant PRECISION = 1e18;
27+
28+
/*********************
29+
* Storage Variables *
30+
*********************/
31+
32+
/// @notice The base fee overhead. This is part of the L2 base fee calculation.
33+
uint256 public baseFeeOverhead;
34+
35+
/// @notice The base fee scalar. This is part of the L2 base fee calculation.
36+
uint256 public baseFeeScalar;
37+
38+
/***************
39+
* Constructor *
40+
***************/
41+
42+
constructor() {
43+
_disableInitializers();
44+
}
45+
46+
function initialize(address _owner) external initializer {
47+
__Ownable_init();
48+
transferOwnership(_owner);
49+
}
50+
51+
/*************************
52+
* Public View Functions *
53+
*************************/
54+
55+
/// @notice Calculates the L2 base fee based on the L1 base fee.
56+
/// @param l1BaseFee The L1 base fee.
57+
/// @return l2BaseFee The L2 base fee.
58+
function getL2BaseFee(uint256 l1BaseFee) public view returns (uint256 l2BaseFee) {
59+
l2BaseFee = (l1BaseFee * baseFeeScalar) / PRECISION + baseFeeOverhead;
60+
}
61+
62+
/************************
63+
* Restricted Functions *
64+
************************/
65+
66+
/// @notice Updates the base fee overhead.
67+
/// @param _baseFeeOverhead The new base fee overhead.
68+
function updateBaseFeeOverhead(uint256 _baseFeeOverhead) external onlyOwner {
69+
uint256 oldBaseFeeOverhead = baseFeeOverhead;
70+
baseFeeOverhead = _baseFeeOverhead;
71+
emit BaseFeeOverheadUpdated(oldBaseFeeOverhead, _baseFeeOverhead);
72+
}
73+
74+
/// @notice Updates the base fee scalar.
75+
/// @param _baseFeeScalar The new base fee scalar.
76+
function updateBaseFeeScalar(uint256 _baseFeeScalar) external onlyOwner {
77+
uint256 oldBaseFeeScalar = baseFeeScalar;
78+
baseFeeScalar = _baseFeeScalar;
79+
emit BaseFeeScalarUpdated(oldBaseFeeScalar, _baseFeeScalar);
80+
}
81+
}

src/test/L2SystemConfig.t.sol

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity =0.8.24;
4+
5+
import {Test} from "forge-std/Test.sol";
6+
7+
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
8+
9+
import {L2SystemConfig} from "../L2/L2SystemConfig.sol";
10+
11+
contract L2SystemConfigTest is Test {
12+
address public admin;
13+
address public owner;
14+
address public nonOwner;
15+
16+
L2SystemConfig public l2SystemConfig;
17+
18+
event BaseFeeOverheadUpdated(uint256 oldBaseFeeOverhead, uint256 newBaseFeeOverhead);
19+
event BaseFeeScalarUpdated(uint256 oldBaseFeeScalar, uint256 newBaseFeeScalar);
20+
21+
function setUp() public {
22+
admin = makeAddr("admin");
23+
owner = makeAddr("owner");
24+
nonOwner = makeAddr("nonOwner");
25+
26+
L2SystemConfig implementation = new L2SystemConfig();
27+
address proxy = address(new TransparentUpgradeableProxy(address(implementation), admin, ""));
28+
l2SystemConfig = L2SystemConfig(proxy);
29+
30+
l2SystemConfig.initialize(owner);
31+
}
32+
33+
function test_Initialize() public {
34+
// Test initialization
35+
assertEq(l2SystemConfig.owner(), owner);
36+
37+
// revert when initialize again
38+
vm.expectRevert("Initializable: contract is already initialized");
39+
l2SystemConfig.initialize(owner);
40+
}
41+
42+
function test_UpdateBaseFeeOverhead(uint256 newBaseFeeOverhead) public {
43+
// Test that only owner can update base fee overhead
44+
vm.prank(nonOwner);
45+
vm.expectRevert("Ownable: caller is not the owner");
46+
l2SystemConfig.updateBaseFeeOverhead(newBaseFeeOverhead);
47+
48+
// Test owner can update base fee overhead
49+
assertEq(l2SystemConfig.baseFeeOverhead(), 0);
50+
vm.prank(owner);
51+
vm.expectEmit(true, true, true, true);
52+
emit BaseFeeOverheadUpdated(0, newBaseFeeOverhead);
53+
l2SystemConfig.updateBaseFeeOverhead(newBaseFeeOverhead);
54+
assertEq(l2SystemConfig.baseFeeOverhead(), newBaseFeeOverhead);
55+
}
56+
57+
function test_UpdateBaseFeeScalar(uint256 newBaseFeeScalar) public {
58+
// Test that only owner can update base fee scalar
59+
vm.prank(nonOwner);
60+
vm.expectRevert("Ownable: caller is not the owner");
61+
l2SystemConfig.updateBaseFeeScalar(newBaseFeeScalar);
62+
63+
// Test owner can update base fee scalar
64+
assertEq(l2SystemConfig.baseFeeScalar(), 0);
65+
vm.prank(owner);
66+
vm.expectEmit(true, true, true, true);
67+
emit BaseFeeScalarUpdated(0, newBaseFeeScalar);
68+
l2SystemConfig.updateBaseFeeScalar(newBaseFeeScalar);
69+
assertEq(l2SystemConfig.baseFeeScalar(), newBaseFeeScalar);
70+
}
71+
72+
function test_GetL2BaseFee(
73+
uint256 l1BaseFee,
74+
uint256 baseFeeScalar,
75+
uint256 baseFeeOverhead
76+
) public {
77+
l1BaseFee = bound(l1BaseFee, 0, type(uint64).max);
78+
baseFeeScalar = bound(baseFeeScalar, 0, type(uint128).max);
79+
baseFeeOverhead = bound(baseFeeOverhead, 0, type(uint128).max);
80+
81+
// Set up the contract state
82+
vm.prank(owner);
83+
l2SystemConfig.updateBaseFeeScalar(baseFeeScalar);
84+
vm.prank(owner);
85+
l2SystemConfig.updateBaseFeeOverhead(baseFeeOverhead);
86+
87+
// Calculate expected L2 base fee
88+
uint256 expectedL2BaseFee = (l1BaseFee * baseFeeScalar) / 1e18 + baseFeeOverhead;
89+
90+
// Test getL2BaseFee function
91+
uint256 actualL2BaseFee = l2SystemConfig.getL2BaseFee(l1BaseFee);
92+
assertEq(actualL2BaseFee, expectedL2BaseFee);
93+
}
94+
95+
function test_GetL2BaseFeeWithZeroL1BaseFee() public {
96+
uint256 l1BaseFee = 0;
97+
uint256 baseFeeScalar = 2000;
98+
uint256 baseFeeOverhead = 1000;
99+
100+
// Set up the contract state
101+
vm.prank(owner);
102+
l2SystemConfig.updateBaseFeeScalar(baseFeeScalar);
103+
vm.prank(owner);
104+
l2SystemConfig.updateBaseFeeOverhead(baseFeeOverhead);
105+
106+
// Calculate expected L2 base fee
107+
uint256 expectedL2BaseFee = baseFeeOverhead; // When L1 base fee is 0, only overhead is added
108+
109+
// Test getL2BaseFee function
110+
uint256 actualL2BaseFee = l2SystemConfig.getL2BaseFee(l1BaseFee);
111+
assertEq(actualL2BaseFee, expectedL2BaseFee);
112+
}
113+
114+
function test_GetL2BaseFeeWithLargeValues() public {
115+
uint256 l1BaseFee = 1e18; // 1 ETH
116+
uint256 baseFeeScalar = 2e18; // 2x multiplier
117+
uint256 baseFeeOverhead = 1e17; // 0.1 ETH
118+
119+
// Set up the contract state
120+
vm.prank(owner);
121+
l2SystemConfig.updateBaseFeeScalar(baseFeeScalar);
122+
vm.prank(owner);
123+
l2SystemConfig.updateBaseFeeOverhead(baseFeeOverhead);
124+
125+
// Calculate expected L2 base fee
126+
uint256 expectedL2BaseFee = (l1BaseFee * baseFeeScalar) / 1e18 + baseFeeOverhead;
127+
128+
// Test getL2BaseFee function
129+
uint256 actualL2BaseFee = l2SystemConfig.getL2BaseFee(l1BaseFee);
130+
assertEq(actualL2BaseFee, expectedL2BaseFee);
131+
}
132+
}

0 commit comments

Comments
 (0)