@arbitrum/nitro-contracts 1.0.0-beta.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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);