@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.
Files changed (42) hide show
  1. package/package.json +13 -2
  2. package/src/bridge/Bridge.sol +49 -29
  3. package/src/bridge/IBridge.sol +58 -45
  4. package/src/bridge/IDelayedMessageProvider.sol +2 -1
  5. package/src/bridge/IInbox.sol +133 -50
  6. package/src/bridge/IOutbox.sol +95 -27
  7. package/src/bridge/IOwnable.sol +2 -1
  8. package/src/bridge/ISequencerInbox.sol +79 -31
  9. package/src/bridge/Inbox.sol +171 -108
  10. package/src/bridge/Outbox.sol +26 -41
  11. package/src/bridge/SequencerInbox.sol +152 -62
  12. package/src/challenge/ChallengeManager.sol +0 -9
  13. package/src/challenge/IChallengeManager.sol +0 -2
  14. package/src/libraries/AdminFallbackProxy.sol +4 -4
  15. package/src/libraries/Constants.sol +3 -0
  16. package/src/libraries/{SecondaryLogicUUPSUpgradeable.sol → DoubleLogicUUPSUpgradeable.sol} +2 -1
  17. package/src/libraries/Error.sol +119 -0
  18. package/src/libraries/IGasRefunder.sol +13 -6
  19. package/src/libraries/MerkleLib.sol +5 -3
  20. package/src/mocks/BridgeStub.sol +22 -1
  21. package/src/mocks/BridgeUnproxied.sol +17 -0
  22. package/src/mocks/InboxStub.sol +49 -2
  23. package/src/mocks/SequencerInboxStub.sol +13 -3
  24. package/src/mocks/Simple.sol +69 -0
  25. package/src/node-interface/NodeInterface.sol +69 -7
  26. package/src/precompiles/ArbGasInfo.sol +16 -4
  27. package/src/precompiles/ArbOwner.sol +18 -0
  28. package/src/precompiles/ArbOwnerPublic.sol +3 -0
  29. package/src/precompiles/ArbSys.sol +7 -4
  30. package/src/rollup/IRollupCore.sol +2 -0
  31. package/src/rollup/IRollupLogic.sol +10 -0
  32. package/src/rollup/RollupAdminLogic.sol +69 -3
  33. package/src/rollup/RollupCore.sol +8 -2
  34. package/src/rollup/RollupCreator.sol +3 -3
  35. package/src/rollup/RollupEventInbox.sol +3 -6
  36. package/src/rollup/RollupLib.sol +1 -0
  37. package/src/{libraries/ArbitrumProxy.sol → rollup/RollupProxy.sol} +3 -3
  38. package/src/rollup/RollupUserLogic.sol +47 -10
  39. package/src/state/GlobalState.sol +7 -0
  40. package/src/test-helpers/BridgeTester.sol +17 -1
  41. package/src/test-helpers/InterfaceCompatibilityTester.sol +11 -0
  42. package/src/test-helpers/OutboxWithoutOptTester.sol +33 -7
@@ -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 override bridge;
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
- /// @notice pauses all inbox functionality
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
- /// @notice unpauses all inbox functionality
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
- /// @dev function to be called one time during the inbox upgrade process
105
- /// this is used to fix the storage slots
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 virtual override whenNotPaused onlyAllowed returns (uint256) {
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 virtual override whenNotPaused onlyAllowed returns (uint256) {
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 virtual override whenNotPaused onlyAllowed returns (uint256) {
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 virtual override whenNotPaused onlyAllowed returns (uint256) {
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
- * @notice Get the L1 fee for submitting a retryable
244
- * @dev This fee can be paid by funds already in the L2 aliased address or by the current message value
245
- * @dev This formula may change in the future, to future proof your code query this method instead of inlining!!
246
- * @param dataLength The length of the retryable's calldata, in bytes
247
- * @param baseFee The block basefee when the retryable is included in the chain
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
- pure
363
+ view
252
364
  returns (uint256)
253
365
  {
254
- return (1400 + 6 * dataLength) * baseFee;
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
- /// @notice deposit eth from L1 to L2
258
- /// @dev this does not trigger the fallback function when receiving in the L2 side.
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 id for retryable transaction (keccak256(requestID, uint(0) )
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 virtual whenNotPaused onlyAllowed returns (uint256) {
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 virtual override whenNotPaused onlyAllowed returns (uint256) {
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
- unsafeCreateRetryableTicketInternal(
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
- * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
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
- ) internal virtual whenNotPaused onlyAllowed returns (uint256) {
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,
@@ -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 override {
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
- /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
67
- /// When the return value is zero, that means this is a system message
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
- /// @return l2Block return L2 block when the L2 tx was initiated or zero
77
- /// if no L2 to L1 transaction is active
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
- /// @return l1Block return L1 block when the L2 tx was initiated or zero
86
- /// if no L2 to L1 transaction is active
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
- /// @return timestamp return L2 timestamp when the L2 tx was initiated or zero
95
- /// if no L2 to L1 transaction is active
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 override returns (uint256) {
110
+ function l2ToL1BatchNum() external pure returns (uint256) {
105
111
  return 0;
106
112
  }
107
113
 
108
- /// @return outputId returns the unique output identifier of the L2 to L1 tx or
109
- /// zero if no L2 to L1 transaction is active
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
- /// @dev function used to simulate the result of a particular function call from the outbox
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);