@arbitrum/nitro-contracts 1.0.0-beta.7 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -2
- package/src/bridge/Bridge.sol +49 -29
- package/src/bridge/IBridge.sol +58 -45
- package/src/bridge/IDelayedMessageProvider.sol +2 -1
- package/src/bridge/IInbox.sol +133 -50
- package/src/bridge/IOutbox.sol +95 -27
- package/src/bridge/IOwnable.sol +2 -1
- package/src/bridge/ISequencerInbox.sol +79 -31
- package/src/bridge/Inbox.sol +171 -108
- package/src/bridge/Outbox.sol +26 -41
- package/src/bridge/SequencerInbox.sol +152 -62
- package/src/challenge/ChallengeManager.sol +0 -9
- package/src/challenge/IChallengeManager.sol +0 -2
- package/src/libraries/AdminFallbackProxy.sol +4 -4
- package/src/libraries/Constants.sol +3 -0
- package/src/libraries/{SecondaryLogicUUPSUpgradeable.sol → DoubleLogicUUPSUpgradeable.sol} +2 -1
- package/src/libraries/Error.sol +119 -0
- package/src/libraries/IGasRefunder.sol +13 -6
- package/src/libraries/MerkleLib.sol +5 -3
- package/src/mocks/BridgeStub.sol +22 -1
- package/src/mocks/BridgeUnproxied.sol +17 -0
- package/src/mocks/InboxStub.sol +49 -2
- package/src/mocks/SequencerInboxStub.sol +13 -3
- package/src/mocks/Simple.sol +69 -0
- package/src/node-interface/NodeInterface.sol +69 -7
- package/src/precompiles/ArbGasInfo.sol +16 -4
- package/src/precompiles/ArbOwner.sol +18 -0
- package/src/precompiles/ArbOwnerPublic.sol +3 -0
- package/src/precompiles/ArbSys.sol +7 -4
- package/src/rollup/IRollupCore.sol +2 -0
- package/src/rollup/IRollupLogic.sol +10 -0
- package/src/rollup/RollupAdminLogic.sol +69 -3
- package/src/rollup/RollupCore.sol +8 -2
- package/src/rollup/RollupCreator.sol +3 -3
- package/src/rollup/RollupEventInbox.sol +3 -6
- package/src/rollup/RollupLib.sol +1 -0
- package/src/{libraries/ArbitrumProxy.sol → rollup/RollupProxy.sol} +3 -3
- package/src/rollup/RollupUserLogic.sol +47 -10
- package/src/state/GlobalState.sol +7 -0
- package/src/test-helpers/BridgeTester.sol +17 -1
- package/src/test-helpers/InterfaceCompatibilityTester.sol +11 -0
- package/src/test-helpers/OutboxWithoutOptTester.sol +33 -7
package/src/bridge/Inbox.sol
CHANGED
@@ -4,6 +4,22 @@
|
|
4
4
|
|
5
5
|
pragma solidity ^0.8.4;
|
6
6
|
|
7
|
+
import {
|
8
|
+
AlreadyInit,
|
9
|
+
NotOrigin,
|
10
|
+
DataTooLarge,
|
11
|
+
AlreadyPaused,
|
12
|
+
AlreadyUnpaused,
|
13
|
+
Paused,
|
14
|
+
InsufficientValue,
|
15
|
+
InsufficientSubmissionCost,
|
16
|
+
NotAllowedOrigin,
|
17
|
+
RetryableData,
|
18
|
+
NotRollupOrOwner,
|
19
|
+
L1Forked,
|
20
|
+
NotForked,
|
21
|
+
GasLimitTooLarge
|
22
|
+
} from "../libraries/Error.sol";
|
7
23
|
import "./IInbox.sol";
|
8
24
|
import "./ISequencerInbox.sol";
|
9
25
|
import "./IBridge.sol";
|
@@ -20,6 +36,7 @@ import {
|
|
20
36
|
L2MessageType_unsignedContractTx
|
21
37
|
} from "../libraries/MessageTypes.sol";
|
22
38
|
import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
|
39
|
+
import "../precompiles/ArbSys.sol";
|
23
40
|
|
24
41
|
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
|
25
42
|
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
@@ -30,7 +47,7 @@ import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
|
30
47
|
* to await inclusion in the SequencerInbox
|
31
48
|
*/
|
32
49
|
contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
33
|
-
IBridge public
|
50
|
+
IBridge public bridge;
|
34
51
|
ISequencerInbox public sequencerInbox;
|
35
52
|
|
36
53
|
/// ------------------------------------ allow list start ------------------------------------ ///
|
@@ -79,12 +96,18 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
79
96
|
_;
|
80
97
|
}
|
81
98
|
|
82
|
-
|
99
|
+
uint256 internal immutable deployTimeChainId = block.chainid;
|
100
|
+
|
101
|
+
function _chainIdChanged() internal view returns (bool) {
|
102
|
+
return deployTimeChainId != block.chainid;
|
103
|
+
}
|
104
|
+
|
105
|
+
/// @inheritdoc IInbox
|
83
106
|
function pause() external onlyRollupOrOwner {
|
84
107
|
_pause();
|
85
108
|
}
|
86
109
|
|
87
|
-
/// @
|
110
|
+
/// @inheritdoc IInbox
|
88
111
|
function unpause() external onlyRollupOrOwner {
|
89
112
|
_unpause();
|
90
113
|
}
|
@@ -94,37 +117,23 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
94
117
|
initializer
|
95
118
|
onlyDelegated
|
96
119
|
{
|
97
|
-
if (address(bridge) != address(0)) revert AlreadyInit();
|
98
120
|
bridge = _bridge;
|
99
121
|
sequencerInbox = _sequencerInbox;
|
100
122
|
allowListEnabled = false;
|
101
123
|
__Pausable_init();
|
102
124
|
}
|
103
125
|
|
104
|
-
/// @
|
105
|
-
|
106
|
-
function postUpgradeInit(IBridge _bridge) external onlyDelegated onlyProxyOwner {
|
107
|
-
uint8 slotsToWipe = 3;
|
108
|
-
for (uint8 i = 0; i < slotsToWipe; i++) {
|
109
|
-
assembly {
|
110
|
-
sstore(i, 0)
|
111
|
-
}
|
112
|
-
}
|
113
|
-
allowListEnabled = false;
|
114
|
-
bridge = _bridge;
|
115
|
-
}
|
126
|
+
/// @inheritdoc IInbox
|
127
|
+
function postUpgradeInit(IBridge) external onlyDelegated onlyProxyOwner {}
|
116
128
|
|
117
|
-
|
118
|
-
* @notice Send a generic L2 message to the chain
|
119
|
-
* @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input
|
120
|
-
* @param messageData Data of the message being sent
|
121
|
-
*/
|
129
|
+
/// @inheritdoc IInbox
|
122
130
|
function sendL2MessageFromOrigin(bytes calldata messageData)
|
123
131
|
external
|
124
132
|
whenNotPaused
|
125
133
|
onlyAllowed
|
126
134
|
returns (uint256)
|
127
135
|
{
|
136
|
+
if (_chainIdChanged()) revert L1Forked();
|
128
137
|
// solhint-disable-next-line avoid-tx-origin
|
129
138
|
if (msg.sender != tx.origin) revert NotOrigin();
|
130
139
|
if (messageData.length > MAX_DATA_SIZE)
|
@@ -134,18 +143,14 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
134
143
|
return msgNum;
|
135
144
|
}
|
136
145
|
|
137
|
-
|
138
|
-
* @notice Send a generic L2 message to the chain
|
139
|
-
* @dev This method can be used to send any type of message that doesn't require L1 validation
|
140
|
-
* @param messageData Data of the message being sent
|
141
|
-
*/
|
146
|
+
/// @inheritdoc IInbox
|
142
147
|
function sendL2Message(bytes calldata messageData)
|
143
148
|
external
|
144
|
-
override
|
145
149
|
whenNotPaused
|
146
150
|
onlyAllowed
|
147
151
|
returns (uint256)
|
148
152
|
{
|
153
|
+
if (_chainIdChanged()) revert L1Forked();
|
149
154
|
return _deliverMessage(L2_MSG, msg.sender, messageData);
|
150
155
|
}
|
151
156
|
|
@@ -155,7 +160,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
155
160
|
uint256 nonce,
|
156
161
|
address to,
|
157
162
|
bytes calldata data
|
158
|
-
) external payable
|
163
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
164
|
+
// arbos will discard unsigned tx with gas limit too large
|
165
|
+
if (gasLimit > type(uint64).max) {
|
166
|
+
revert GasLimitTooLarge();
|
167
|
+
}
|
159
168
|
return
|
160
169
|
_deliverMessage(
|
161
170
|
L1MessageType_L2FundedByL1,
|
@@ -177,7 +186,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
177
186
|
uint256 maxFeePerGas,
|
178
187
|
address to,
|
179
188
|
bytes calldata data
|
180
|
-
) external payable
|
189
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
190
|
+
// arbos will discard unsigned tx with gas limit too large
|
191
|
+
if (gasLimit > type(uint64).max) {
|
192
|
+
revert GasLimitTooLarge();
|
193
|
+
}
|
181
194
|
return
|
182
195
|
_deliverMessage(
|
183
196
|
L1MessageType_L2FundedByL1,
|
@@ -200,7 +213,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
200
213
|
address to,
|
201
214
|
uint256 value,
|
202
215
|
bytes calldata data
|
203
|
-
) external
|
216
|
+
) external whenNotPaused onlyAllowed returns (uint256) {
|
217
|
+
// arbos will discard unsigned tx with gas limit too large
|
218
|
+
if (gasLimit > type(uint64).max) {
|
219
|
+
revert GasLimitTooLarge();
|
220
|
+
}
|
204
221
|
return
|
205
222
|
_deliverMessage(
|
206
223
|
L2_MSG,
|
@@ -223,7 +240,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
223
240
|
address to,
|
224
241
|
uint256 value,
|
225
242
|
bytes calldata data
|
226
|
-
) external
|
243
|
+
) external whenNotPaused onlyAllowed returns (uint256) {
|
244
|
+
// arbos will discard unsigned tx with gas limit too large
|
245
|
+
if (gasLimit > type(uint64).max) {
|
246
|
+
revert GasLimitTooLarge();
|
247
|
+
}
|
227
248
|
return
|
228
249
|
_deliverMessage(
|
229
250
|
L2_MSG,
|
@@ -239,35 +260,120 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
239
260
|
);
|
240
261
|
}
|
241
262
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
263
|
+
/// @inheritdoc IInbox
|
264
|
+
function sendL1FundedUnsignedTransactionToFork(
|
265
|
+
uint256 gasLimit,
|
266
|
+
uint256 maxFeePerGas,
|
267
|
+
uint256 nonce,
|
268
|
+
address to,
|
269
|
+
bytes calldata data
|
270
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
271
|
+
if (!_chainIdChanged()) revert NotForked();
|
272
|
+
// solhint-disable-next-line avoid-tx-origin
|
273
|
+
if (msg.sender != tx.origin) revert NotOrigin();
|
274
|
+
// arbos will discard unsigned tx with gas limit too large
|
275
|
+
if (gasLimit > type(uint64).max) {
|
276
|
+
revert GasLimitTooLarge();
|
277
|
+
}
|
278
|
+
return
|
279
|
+
_deliverMessage(
|
280
|
+
L1MessageType_L2FundedByL1,
|
281
|
+
// undoing sender alias here to cancel out the aliasing
|
282
|
+
AddressAliasHelper.undoL1ToL2Alias(msg.sender),
|
283
|
+
abi.encodePacked(
|
284
|
+
L2MessageType_unsignedEOATx,
|
285
|
+
gasLimit,
|
286
|
+
maxFeePerGas,
|
287
|
+
nonce,
|
288
|
+
uint256(uint160(to)),
|
289
|
+
msg.value,
|
290
|
+
data
|
291
|
+
)
|
292
|
+
);
|
293
|
+
}
|
294
|
+
|
295
|
+
/// @inheritdoc IInbox
|
296
|
+
function sendUnsignedTransactionToFork(
|
297
|
+
uint256 gasLimit,
|
298
|
+
uint256 maxFeePerGas,
|
299
|
+
uint256 nonce,
|
300
|
+
address to,
|
301
|
+
uint256 value,
|
302
|
+
bytes calldata data
|
303
|
+
) external whenNotPaused onlyAllowed returns (uint256) {
|
304
|
+
if (!_chainIdChanged()) revert NotForked();
|
305
|
+
// solhint-disable-next-line avoid-tx-origin
|
306
|
+
if (msg.sender != tx.origin) revert NotOrigin();
|
307
|
+
// arbos will discard unsigned tx with gas limit too large
|
308
|
+
if (gasLimit > type(uint64).max) {
|
309
|
+
revert GasLimitTooLarge();
|
310
|
+
}
|
311
|
+
return
|
312
|
+
_deliverMessage(
|
313
|
+
L2_MSG,
|
314
|
+
// undoing sender alias here to cancel out the aliasing
|
315
|
+
AddressAliasHelper.undoL1ToL2Alias(msg.sender),
|
316
|
+
abi.encodePacked(
|
317
|
+
L2MessageType_unsignedEOATx,
|
318
|
+
gasLimit,
|
319
|
+
maxFeePerGas,
|
320
|
+
nonce,
|
321
|
+
uint256(uint160(to)),
|
322
|
+
value,
|
323
|
+
data
|
324
|
+
)
|
325
|
+
);
|
326
|
+
}
|
327
|
+
|
328
|
+
/// @inheritdoc IInbox
|
329
|
+
function sendWithdrawEthToFork(
|
330
|
+
uint256 gasLimit,
|
331
|
+
uint256 maxFeePerGas,
|
332
|
+
uint256 nonce,
|
333
|
+
uint256 value,
|
334
|
+
address withdrawTo
|
335
|
+
) external whenNotPaused onlyAllowed returns (uint256) {
|
336
|
+
if (!_chainIdChanged()) revert NotForked();
|
337
|
+
// solhint-disable-next-line avoid-tx-origin
|
338
|
+
if (msg.sender != tx.origin) revert NotOrigin();
|
339
|
+
// arbos will discard unsigned tx with gas limit too large
|
340
|
+
if (gasLimit > type(uint64).max) {
|
341
|
+
revert GasLimitTooLarge();
|
342
|
+
}
|
343
|
+
return
|
344
|
+
_deliverMessage(
|
345
|
+
L2_MSG,
|
346
|
+
// undoing sender alias here to cancel out the aliasing
|
347
|
+
AddressAliasHelper.undoL1ToL2Alias(msg.sender),
|
348
|
+
abi.encodePacked(
|
349
|
+
L2MessageType_unsignedEOATx,
|
350
|
+
gasLimit,
|
351
|
+
maxFeePerGas,
|
352
|
+
nonce,
|
353
|
+
uint256(uint160(address(100))), // ArbSys address
|
354
|
+
value,
|
355
|
+
abi.encode(ArbSys.withdrawEth.selector, withdrawTo)
|
356
|
+
)
|
357
|
+
);
|
358
|
+
}
|
359
|
+
|
360
|
+
/// @inheritdoc IInbox
|
249
361
|
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
|
250
362
|
public
|
251
|
-
|
363
|
+
view
|
252
364
|
returns (uint256)
|
253
365
|
{
|
254
|
-
|
366
|
+
// Use current block basefee if baseFee parameter is 0
|
367
|
+
return (1400 + 6 * dataLength) * (baseFee == 0 ? block.basefee : baseFee);
|
255
368
|
}
|
256
369
|
|
257
|
-
/// @
|
258
|
-
|
259
|
-
/// Look into retryable tickets if you are interested in this functionality.
|
260
|
-
/// @dev this function should not be called inside contract constructors
|
261
|
-
function depositEth() public payable override whenNotPaused onlyAllowed returns (uint256) {
|
370
|
+
/// @inheritdoc IInbox
|
371
|
+
function depositEth() public payable whenNotPaused onlyAllowed returns (uint256) {
|
262
372
|
address dest = msg.sender;
|
263
373
|
|
264
374
|
// solhint-disable-next-line avoid-tx-origin
|
265
375
|
if (AddressUpgradeable.isContract(msg.sender) || tx.origin != msg.sender) {
|
266
376
|
// isContract check fails if this function is called during a contract's constructor.
|
267
|
-
// We don't adjust the address for calls coming from L1 contracts since their addresses get remapped
|
268
|
-
// If the caller is an EOA, we adjust the address.
|
269
|
-
// This is needed because unsigned messages to the L2 (such as retryables)
|
270
|
-
// have the L1 sender address mapped.
|
271
377
|
dest = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
|
272
378
|
}
|
273
379
|
|
@@ -280,15 +386,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
280
386
|
}
|
281
387
|
|
282
388
|
/// @notice deprecated in favour of depositEth with no parameters
|
283
|
-
function depositEth(uint256)
|
284
|
-
external
|
285
|
-
payable
|
286
|
-
virtual
|
287
|
-
override
|
288
|
-
whenNotPaused
|
289
|
-
onlyAllowed
|
290
|
-
returns (uint256)
|
291
|
-
{
|
389
|
+
function depositEth(uint256) external payable whenNotPaused onlyAllowed returns (uint256) {
|
292
390
|
return depositEth();
|
293
391
|
}
|
294
392
|
|
@@ -304,7 +402,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
304
402
|
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
305
403
|
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
306
404
|
* @param data ABI encoded data of L2 message
|
307
|
-
* @return unique
|
405
|
+
* @return unique message number of the retryable transaction
|
308
406
|
*/
|
309
407
|
function createRetryableTicketNoRefundAliasRewrite(
|
310
408
|
address to,
|
@@ -315,7 +413,8 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
315
413
|
uint256 gasLimit,
|
316
414
|
uint256 maxFeePerGas,
|
317
415
|
bytes calldata data
|
318
|
-
) external payable
|
416
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
417
|
+
// gas limit is validated to be within uint64 in unsafeCreateRetryableTicket
|
319
418
|
return
|
320
419
|
unsafeCreateRetryableTicket(
|
321
420
|
to,
|
@@ -329,20 +428,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
329
428
|
);
|
330
429
|
}
|
331
430
|
|
332
|
-
|
333
|
-
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
|
334
|
-
* @dev all msg.value will deposited to callValueRefundAddress on L2
|
335
|
-
* @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
|
336
|
-
* @param to destination L2 contract address
|
337
|
-
* @param l2CallValue call value for retryable L2 message
|
338
|
-
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
|
339
|
-
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
|
340
|
-
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
|
341
|
-
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
342
|
-
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
343
|
-
* @param data ABI encoded data of L2 message
|
344
|
-
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
345
|
-
*/
|
431
|
+
/// @inheritdoc IInbox
|
346
432
|
function createRetryableTicket(
|
347
433
|
address to,
|
348
434
|
uint256 l2CallValue,
|
@@ -352,7 +438,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
352
438
|
uint256 gasLimit,
|
353
439
|
uint256 maxFeePerGas,
|
354
440
|
bytes calldata data
|
355
|
-
) external payable
|
441
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
356
442
|
// ensure the user's deposit alone will make submission succeed
|
357
443
|
if (msg.value < (maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas)) {
|
358
444
|
revert InsufficientValue(
|
@@ -372,8 +458,9 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
372
458
|
callValueRefundAddress = AddressAliasHelper.applyL1ToL2Alias(callValueRefundAddress);
|
373
459
|
}
|
374
460
|
|
461
|
+
// gas limit is validated to be within uint64 in unsafeCreateRetryableTicket
|
375
462
|
return
|
376
|
-
|
463
|
+
unsafeCreateRetryableTicket(
|
377
464
|
to,
|
378
465
|
l2CallValue,
|
379
466
|
maxSubmissionCost,
|
@@ -385,24 +472,8 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
385
472
|
);
|
386
473
|
}
|
387
474
|
|
388
|
-
|
389
|
-
|
390
|
-
* @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds
|
391
|
-
* come from the deposit alone, rather than falling back on the user's L2 balance
|
392
|
-
* @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).
|
393
|
-
* createRetryableTicket method is the recommended standard.
|
394
|
-
* @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
|
395
|
-
* @param to destination L2 contract address
|
396
|
-
* @param l2CallValue call value for retryable L2 message
|
397
|
-
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
|
398
|
-
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
|
399
|
-
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
|
400
|
-
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
401
|
-
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
402
|
-
* @param data ABI encoded data of L2 message
|
403
|
-
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
404
|
-
*/
|
405
|
-
function unsafeCreateRetryableTicketInternal(
|
475
|
+
/// @inheritdoc IInbox
|
476
|
+
function unsafeCreateRetryableTicket(
|
406
477
|
address to,
|
407
478
|
uint256 l2CallValue,
|
408
479
|
uint256 maxSubmissionCost,
|
@@ -411,7 +482,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
411
482
|
uint256 gasLimit,
|
412
483
|
uint256 maxFeePerGas,
|
413
484
|
bytes calldata data
|
414
|
-
)
|
485
|
+
) public payable whenNotPaused onlyAllowed returns (uint256) {
|
415
486
|
// gas price and limit of 1 should never be a valid input, so instead they are used as
|
416
487
|
// magic values to trigger a revert in eth calls that surface data without requiring a tx trace
|
417
488
|
if (gasLimit == 1 || maxFeePerGas == 1)
|
@@ -428,6 +499,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
428
499
|
data
|
429
500
|
);
|
430
501
|
|
502
|
+
// arbos will discard retryable with gas limit too large
|
503
|
+
if (gasLimit > type(uint64).max) {
|
504
|
+
revert GasLimitTooLarge();
|
505
|
+
}
|
506
|
+
|
431
507
|
uint256 submissionFee = calculateRetryableSubmissionFee(data.length, block.basefee);
|
432
508
|
if (maxSubmissionCost < submissionFee)
|
433
509
|
revert InsufficientSubmissionCost(submissionFee, maxSubmissionCost);
|
@@ -451,19 +527,6 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
451
527
|
);
|
452
528
|
}
|
453
529
|
|
454
|
-
function unsafeCreateRetryableTicket(
|
455
|
-
address,
|
456
|
-
uint256,
|
457
|
-
uint256,
|
458
|
-
address,
|
459
|
-
address,
|
460
|
-
uint256,
|
461
|
-
uint256,
|
462
|
-
bytes calldata
|
463
|
-
) public payable override returns (uint256) {
|
464
|
-
revert("UNSAFE_RETRYABLES_TEMPORARILY_DISABLED");
|
465
|
-
}
|
466
|
-
|
467
530
|
function _deliverMessage(
|
468
531
|
uint8 _kind,
|
469
532
|
address _sender,
|
package/src/bridge/Outbox.sol
CHANGED
@@ -4,6 +4,16 @@
|
|
4
4
|
|
5
5
|
pragma solidity ^0.8.4;
|
6
6
|
|
7
|
+
import {
|
8
|
+
AlreadyInit,
|
9
|
+
NotRollup,
|
10
|
+
ProofTooLong,
|
11
|
+
PathNotMinimal,
|
12
|
+
UnknownRoot,
|
13
|
+
AlreadySpent,
|
14
|
+
BridgeCallFailed,
|
15
|
+
HadZeroInit
|
16
|
+
} from "../libraries/Error.sol";
|
7
17
|
import "./IBridge.sol";
|
8
18
|
import "./IOutbox.sol";
|
9
19
|
import "../libraries/MerkleLib.sol";
|
@@ -42,6 +52,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
42
52
|
uint128 public constant OUTBOX_VERSION = 2;
|
43
53
|
|
44
54
|
function initialize(IBridge _bridge) external onlyDelegated {
|
55
|
+
if (address(_bridge) == address(0)) revert HadZeroInit();
|
45
56
|
if (address(bridge) != address(0)) revert AlreadyInit();
|
46
57
|
// address zero is returned if no context is set, but the values used in storage
|
47
58
|
// are non-zero to save users some gas (as storage refunds are usually maxed out)
|
@@ -57,43 +68,38 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
57
68
|
rollup = address(_bridge.rollup());
|
58
69
|
}
|
59
70
|
|
60
|
-
function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external
|
71
|
+
function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external {
|
61
72
|
if (msg.sender != rollup) revert NotRollup(msg.sender, rollup);
|
62
73
|
roots[root] = l2BlockHash;
|
63
74
|
emit SendRootUpdated(root, l2BlockHash);
|
64
75
|
}
|
65
76
|
|
66
|
-
/// @
|
67
|
-
|
68
|
-
/// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
|
69
|
-
function l2ToL1Sender() external view override returns (address) {
|
77
|
+
/// @inheritdoc IOutbox
|
78
|
+
function l2ToL1Sender() external view returns (address) {
|
70
79
|
address sender = context.sender;
|
71
80
|
// we don't return the default context value to avoid a breaking change in the API
|
72
81
|
if (sender == SENDER_DEFAULT_CONTEXT) return address(0);
|
73
82
|
return sender;
|
74
83
|
}
|
75
84
|
|
76
|
-
/// @
|
77
|
-
|
78
|
-
function l2ToL1Block() external view override returns (uint256) {
|
85
|
+
/// @inheritdoc IOutbox
|
86
|
+
function l2ToL1Block() external view returns (uint256) {
|
79
87
|
uint128 l2Block = context.l2Block;
|
80
88
|
// we don't return the default context value to avoid a breaking change in the API
|
81
89
|
if (l2Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
|
82
90
|
return uint256(l2Block);
|
83
91
|
}
|
84
92
|
|
85
|
-
/// @
|
86
|
-
|
87
|
-
function l2ToL1EthBlock() external view override returns (uint256) {
|
93
|
+
/// @inheritdoc IOutbox
|
94
|
+
function l2ToL1EthBlock() external view returns (uint256) {
|
88
95
|
uint128 l1Block = context.l1Block;
|
89
96
|
// we don't return the default context value to avoid a breaking change in the API
|
90
97
|
if (l1Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
|
91
98
|
return uint256(l1Block);
|
92
99
|
}
|
93
100
|
|
94
|
-
/// @
|
95
|
-
|
96
|
-
function l2ToL1Timestamp() external view override returns (uint256) {
|
101
|
+
/// @inheritdoc IOutbox
|
102
|
+
function l2ToL1Timestamp() external view returns (uint256) {
|
97
103
|
uint128 timestamp = context.timestamp;
|
98
104
|
// we don't return the default context value to avoid a breaking change in the API
|
99
105
|
if (timestamp == TIMESTAMP_DEFAULT_CONTEXT) return uint256(0);
|
@@ -101,33 +107,19 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
101
107
|
}
|
102
108
|
|
103
109
|
/// @notice batch number is deprecated and now always returns 0
|
104
|
-
function l2ToL1BatchNum() external pure
|
110
|
+
function l2ToL1BatchNum() external pure returns (uint256) {
|
105
111
|
return 0;
|
106
112
|
}
|
107
113
|
|
108
|
-
/// @
|
109
|
-
|
110
|
-
function l2ToL1OutputId() external view override returns (bytes32) {
|
114
|
+
/// @inheritdoc IOutbox
|
115
|
+
function l2ToL1OutputId() external view returns (bytes32) {
|
111
116
|
bytes32 outputId = context.outputId;
|
112
117
|
// we don't return the default context value to avoid a breaking change in the API
|
113
118
|
if (outputId == OUTPUTID_DEFAULT_CONTEXT) return bytes32(0);
|
114
119
|
return outputId;
|
115
120
|
}
|
116
121
|
|
117
|
-
|
118
|
-
* @notice Executes a messages in an Outbox entry.
|
119
|
-
* @dev Reverts if dispute period hasn't expired, since the outbox entry
|
120
|
-
* is only created once the rollup confirms the respective assertion.
|
121
|
-
* @param proof Merkle proof of message inclusion in send root
|
122
|
-
* @param index Merkle path to message
|
123
|
-
* @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
|
124
|
-
* @param to destination address for L1 contract call
|
125
|
-
* @param l2Block l2 block number at which sendTxToL1 call was made
|
126
|
-
* @param l1Block l1 block number at which sendTxToL1 call was made
|
127
|
-
* @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
|
128
|
-
* @param value wei in L1 message
|
129
|
-
* @param data abi-encoded L1 message data
|
130
|
-
*/
|
122
|
+
/// @inheritdoc IOutbox
|
131
123
|
function executeTransaction(
|
132
124
|
bytes32[] calldata proof,
|
133
125
|
uint256 index,
|
@@ -154,15 +146,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
154
146
|
executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
|
155
147
|
}
|
156
148
|
|
157
|
-
/// @
|
158
|
-
/// it is useful for things such as gas estimates. This function includes all costs except for
|
159
|
-
/// proof validation (which can be considered offchain as a somewhat of a fixed cost - it's
|
160
|
-
/// not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation).
|
161
|
-
/// We can't include the cost of proof validation since this is intended to be used to simulate txs
|
162
|
-
/// that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend
|
163
|
-
/// to confirm a pending merkle root, but that would be less pratical for integrating with tooling.
|
164
|
-
/// It is only possible to trigger it when the msg sender is address zero, which should be impossible
|
165
|
-
/// unless under simulation in an eth_call or eth_estimateGas
|
149
|
+
/// @inheritdoc IOutbox
|
166
150
|
function executeTransactionSimulation(
|
167
151
|
uint256 index,
|
168
152
|
address l2Sender,
|
@@ -226,6 +210,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
226
210
|
return ((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0);
|
227
211
|
}
|
228
212
|
|
213
|
+
/// @inheritdoc IOutbox
|
229
214
|
function isSpent(uint256 index) external view returns (bool) {
|
230
215
|
(, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
|
231
216
|
return _isSpent(bitOffset, replay);
|