-
Notifications
You must be signed in to change notification settings - Fork 20
/
L1GasPriceOracle.sol
267 lines (212 loc) · 9.05 KB
/
L1GasPriceOracle.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
// SPDX-License-Identifier: MIT
pragma solidity =0.8.24;
import {OwnableBase} from "../../libraries/common/OwnableBase.sol";
import {IWhitelist} from "../../libraries/common/IWhitelist.sol";
import {IL1GasPriceOracle} from "./IL1GasPriceOracle.sol";
contract L1GasPriceOracle is OwnableBase, IL1GasPriceOracle {
/**********
* Events *
**********/
/// @notice Emitted when owner updates whitelist contract.
/// @param _oldWhitelist The address of old whitelist contract.
/// @param _newWhitelist The address of new whitelist contract.
event UpdateWhitelist(address _oldWhitelist, address _newWhitelist);
/**********
* Errors *
**********/
/// @dev Thrown when the blob fee scalar exceed `MAX_BLOB_SCALAR`.
error ErrExceedMaxBlobScalar();
/// @dev Thrown when the commit fee scalar exceed `MAX_COMMIT_SCALAR`.
error ErrExceedMaxCommitScalar();
/// @dev Thrown when the l1 fee overhead exceed `MAX_OVERHEAD`.
error ErrExceedMaxOverhead();
/// @dev Thrown when the l1 fee scalar exceed `MAX_SCALAR`.
error ErrExceedMaxScalar();
/// @dev Thrown when the caller is not whitelisted.
error ErrCallerNotWhitelisted();
/// @dev Thrown when we enable Curie fork after Curie fork.
error ErrAlreadyInCurieFork();
/*************
* Constants *
*************/
/// @dev The precision used in the scalar.
uint256 private constant PRECISION = 1e9;
/// @dev The maximum possible l1 fee overhead.
/// Computed based on current l1 block gas limit.
uint256 private constant MAX_OVERHEAD = 30000000 / 16;
/// @dev The maximum possible l1 fee scale before Curie.
/// x1000 should be enough.
uint256 private constant MAX_SCALAR = 1000 * PRECISION;
/// @dev The maximum possible l1 commit fee scalar after Curie.
/// We derive the commit scalar by
/// ```
/// commit_scalar = commit_gas_per_tx * fluctuation_multiplier * 1e9
/// ```
/// So, the value should not exceed 10^9 * 1e9 normally.
uint256 private constant MAX_COMMIT_SCALAR = 10**9 * PRECISION;
/// @dev The maximum possible l1 blob fee scalar after Curie.
/// We derive the blob scalar by
/// ```
/// blob_scalar = fluctuation_multiplier / compression_ratio / blob_util_ratio * 1e9
/// ```
/// So, the value should not exceed 10^9 * 1e9 normally.
uint256 private constant MAX_BLOB_SCALAR = 10**9 * PRECISION;
/*************
* Variables *
*************/
/// @inheritdoc IL1GasPriceOracle
uint256 public l1BaseFee;
/// @inheritdoc IL1GasPriceOracle
uint256 public override overhead;
/// @inheritdoc IL1GasPriceOracle
uint256 public override scalar;
/// @notice The address of whitelist contract.
IWhitelist public whitelist;
/// @inheritdoc IL1GasPriceOracle
uint256 public override l1BlobBaseFee;
/// @inheritdoc IL1GasPriceOracle
uint256 public override commitScalar;
/// @inheritdoc IL1GasPriceOracle
uint256 public override blobScalar;
/// @notice Indicates whether the network has gone through the Curie upgrade.
bool public isCurie;
/*************
* Modifiers *
*************/
modifier onlyWhitelistedSender() {
if (!whitelist.isSenderAllowed(msg.sender)) revert ErrCallerNotWhitelisted();
_;
}
/***************
* Constructor *
***************/
constructor(address _owner) {
_transferOwnership(_owner);
}
/*************************
* Public View Functions *
*************************/
/// @inheritdoc IL1GasPriceOracle
function getL1Fee(bytes memory _data) external view override returns (uint256) {
if (isCurie) {
return _getL1FeeCurie(_data);
} else {
return _getL1FeeBeforeCurie(_data);
}
}
/// @inheritdoc IL1GasPriceOracle
function getL1GasUsed(bytes memory _data) public view override returns (uint256) {
if (isCurie) {
// It is near zero since we put all transactions to blob.
return 0;
} else {
return _getL1GasUsedBeforeCurie(_data);
}
}
/*****************************
* Public Mutating Functions *
*****************************/
/// @inheritdoc IL1GasPriceOracle
function setL1BaseFee(uint256 _l1BaseFee) external override onlyWhitelistedSender {
l1BaseFee = _l1BaseFee;
emit L1BaseFeeUpdated(_l1BaseFee);
}
/// @inheritdoc IL1GasPriceOracle
function setL1BaseFeeAndBlobBaseFee(uint256 _l1BaseFee, uint256 _l1BlobBaseFee)
external
override
onlyWhitelistedSender
{
l1BaseFee = _l1BaseFee;
l1BlobBaseFee = _l1BlobBaseFee;
emit L1BaseFeeUpdated(_l1BaseFee);
emit L1BlobBaseFeeUpdated(_l1BlobBaseFee);
}
/************************
* Restricted Functions *
************************/
/// @notice Allows the owner to modify the overhead.
/// @param _overhead New overhead
function setOverhead(uint256 _overhead) external onlyOwner {
if (_overhead > MAX_OVERHEAD) revert ErrExceedMaxOverhead();
overhead = _overhead;
emit OverheadUpdated(_overhead);
}
/// Allows the owner to modify the scalar.
/// @param _scalar New scalar
function setScalar(uint256 _scalar) external onlyOwner {
if (_scalar > MAX_SCALAR) revert ErrExceedMaxScalar();
scalar = _scalar;
emit ScalarUpdated(_scalar);
}
/// Allows the owner to modify the commit scalar.
/// @param _scalar New scalar
function setCommitScalar(uint256 _scalar) external onlyOwner {
if (_scalar > MAX_COMMIT_SCALAR) revert ErrExceedMaxCommitScalar();
commitScalar = _scalar;
emit CommitScalarUpdated(_scalar);
}
/// Allows the owner to modify the blob scalar.
/// @param _scalar New scalar
function setBlobScalar(uint256 _scalar) external onlyOwner {
if (_scalar > MAX_BLOB_SCALAR) revert ErrExceedMaxBlobScalar();
blobScalar = _scalar;
emit BlobScalarUpdated(_scalar);
}
/// @notice Update whitelist contract.
/// @dev This function can only called by contract owner.
/// @param _newWhitelist The address of new whitelist contract.
function updateWhitelist(address _newWhitelist) external onlyOwner {
address _oldWhitelist = address(whitelist);
whitelist = IWhitelist(_newWhitelist);
emit UpdateWhitelist(_oldWhitelist, _newWhitelist);
}
/// @notice Enable the Curie fork (callable by contract owner).
///
/// @dev Since this is a predeploy contract, we will directly set the slot while hard fork
/// to avoid external owner operations.
/// The reason that we keep this function is for easy unit testing.
function enableCurie() external onlyOwner {
if (isCurie) revert ErrAlreadyInCurieFork();
isCurie = true;
}
/**********************
* Internal Functions *
**********************/
/// @dev Internal function to computes the amount of L1 gas used for a transaction before Curie fork.
/// The `_data` is the RLP-encoded transaction with signature. And we also reserve additional
/// 4 bytes in the non-zero bytes to store the number of bytes in the RLP-encoded transaction.
/// @param _data Signed fully RLP-encoded transaction to get the L1 gas for.
/// @return Amount of L1 gas used to publish the transaction.
function _getL1GasUsedBeforeCurie(bytes memory _data) private view returns (uint256) {
uint256 _total = 0;
uint256 _length = _data.length;
unchecked {
for (uint256 i = 0; i < _length; i++) {
if (_data[i] == 0) {
_total += 4;
} else {
_total += 16;
}
}
return _total + overhead + (4 * 16);
}
}
/// @dev Internal function to compute the L1 portion of the fee based on the size of the rlp encoded input
/// transaction, the current L1 base fee, and the various dynamic parameters, before Curie fork.
/// @param _data Signed fully RLP-encoded transaction to get the L1 fee for.
/// @return L1 fee that should be paid for the tx
function _getL1FeeBeforeCurie(bytes memory _data) private view returns (uint256) {
uint256 _l1GasUsed = _getL1GasUsedBeforeCurie(_data);
uint256 _l1Fee = _l1GasUsed * l1BaseFee;
return (_l1Fee * scalar) / PRECISION;
}
/// @dev Internal function to compute the L1 portion of the fee based on the size of the rlp encoded input
/// transaction, the current L1 base fee, and the various dynamic parameters, after Curie fork.
/// @param _data Signed fully RLP-encoded transaction to get the L1 fee for.
/// @return L1 fee that should be paid for the tx
function _getL1FeeCurie(bytes memory _data) private view returns (uint256) {
// We have bounded the value of `commitScalar` and `blobScalar`, the whole expression won't overflow.
return (commitScalar * l1BaseFee + blobScalar * _data.length * l1BlobBaseFee) / PRECISION;
}
}