@arbitrum/nitro-contracts 1.0.0-beta.8 → 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 (37) hide show
  1. package/package.json +10 -2
  2. package/src/bridge/Bridge.sol +39 -30
  3. package/src/bridge/IBridge.sol +56 -29
  4. package/src/bridge/IInbox.sol +130 -15
  5. package/src/bridge/IOutbox.sol +55 -7
  6. package/src/bridge/ISequencerInbox.sol +84 -7
  7. package/src/bridge/Inbox.sol +154 -92
  8. package/src/bridge/Outbox.sol +23 -47
  9. package/src/bridge/SequencerInbox.sol +132 -62
  10. package/src/challenge/ChallengeManager.sol +0 -9
  11. package/src/challenge/IChallengeManager.sol +0 -2
  12. package/src/libraries/AdminFallbackProxy.sol +4 -4
  13. package/src/libraries/Constants.sol +3 -0
  14. package/src/libraries/{SecondaryLogicUUPSUpgradeable.sol → DoubleLogicUUPSUpgradeable.sol} +2 -1
  15. package/src/libraries/Error.sol +12 -0
  16. package/src/libraries/IGasRefunder.sol +11 -5
  17. package/src/libraries/MerkleLib.sol +5 -3
  18. package/src/mocks/BridgeStub.sol +20 -1
  19. package/src/mocks/BridgeUnproxied.sol +17 -0
  20. package/src/mocks/InboxStub.sol +48 -3
  21. package/src/mocks/SequencerInboxStub.sol +13 -3
  22. package/src/mocks/Simple.sol +69 -0
  23. package/src/node-interface/NodeInterface.sol +35 -4
  24. package/src/precompiles/ArbGasInfo.sol +7 -4
  25. package/src/precompiles/ArbOwner.sol +9 -0
  26. package/src/precompiles/ArbOwnerPublic.sol +3 -0
  27. package/src/precompiles/ArbSys.sol +5 -2
  28. package/src/rollup/IRollupCore.sol +2 -0
  29. package/src/rollup/IRollupLogic.sol +10 -0
  30. package/src/rollup/RollupAdminLogic.sol +27 -3
  31. package/src/rollup/RollupCore.sol +3 -0
  32. package/src/rollup/RollupCreator.sol +3 -3
  33. package/src/rollup/RollupEventInbox.sol +3 -6
  34. package/src/{libraries/ArbitrumProxy.sol → rollup/RollupProxy.sol} +3 -3
  35. package/src/rollup/RollupUserLogic.sol +47 -10
  36. package/src/test-helpers/BridgeTester.sol +7 -1
  37. package/src/test-helpers/OutboxWithoutOptTester.sol +8 -8
@@ -11,7 +11,8 @@ import {
11
11
  PathNotMinimal,
12
12
  UnknownRoot,
13
13
  AlreadySpent,
14
- BridgeCallFailed
14
+ BridgeCallFailed,
15
+ HadZeroInit
15
16
  } from "../libraries/Error.sol";
16
17
  import "./IBridge.sol";
17
18
  import "./IOutbox.sol";
@@ -51,6 +52,7 @@ contract Outbox is DelegateCallAware, IOutbox {
51
52
  uint128 public constant OUTBOX_VERSION = 2;
52
53
 
53
54
  function initialize(IBridge _bridge) external onlyDelegated {
55
+ if (address(_bridge) == address(0)) revert HadZeroInit();
54
56
  if (address(bridge) != address(0)) revert AlreadyInit();
55
57
  // address zero is returned if no context is set, but the values used in storage
56
58
  // are non-zero to save users some gas (as storage refunds are usually maxed out)
@@ -66,43 +68,38 @@ contract Outbox is DelegateCallAware, IOutbox {
66
68
  rollup = address(_bridge.rollup());
67
69
  }
68
70
 
69
- function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external override {
71
+ function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external {
70
72
  if (msg.sender != rollup) revert NotRollup(msg.sender, rollup);
71
73
  roots[root] = l2BlockHash;
72
74
  emit SendRootUpdated(root, l2BlockHash);
73
75
  }
74
76
 
75
- /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
76
- /// When the return value is zero, that means this is a system message
77
- /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
78
- function l2ToL1Sender() external view override returns (address) {
77
+ /// @inheritdoc IOutbox
78
+ function l2ToL1Sender() external view returns (address) {
79
79
  address sender = context.sender;
80
80
  // we don't return the default context value to avoid a breaking change in the API
81
81
  if (sender == SENDER_DEFAULT_CONTEXT) return address(0);
82
82
  return sender;
83
83
  }
84
84
 
85
- /// @return l2Block return L2 block when the L2 tx was initiated or zero
86
- /// if no L2 to L1 transaction is active
87
- function l2ToL1Block() external view override returns (uint256) {
85
+ /// @inheritdoc IOutbox
86
+ function l2ToL1Block() external view returns (uint256) {
88
87
  uint128 l2Block = context.l2Block;
89
88
  // we don't return the default context value to avoid a breaking change in the API
90
89
  if (l2Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
91
90
  return uint256(l2Block);
92
91
  }
93
92
 
94
- /// @return l1Block return L1 block when the L2 tx was initiated or zero
95
- /// if no L2 to L1 transaction is active
96
- function l2ToL1EthBlock() external view override returns (uint256) {
93
+ /// @inheritdoc IOutbox
94
+ function l2ToL1EthBlock() external view returns (uint256) {
97
95
  uint128 l1Block = context.l1Block;
98
96
  // we don't return the default context value to avoid a breaking change in the API
99
97
  if (l1Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
100
98
  return uint256(l1Block);
101
99
  }
102
100
 
103
- /// @return timestamp return L2 timestamp when the L2 tx was initiated or zero
104
- /// if no L2 to L1 transaction is active
105
- function l2ToL1Timestamp() external view override returns (uint256) {
101
+ /// @inheritdoc IOutbox
102
+ function l2ToL1Timestamp() external view returns (uint256) {
106
103
  uint128 timestamp = context.timestamp;
107
104
  // we don't return the default context value to avoid a breaking change in the API
108
105
  if (timestamp == TIMESTAMP_DEFAULT_CONTEXT) return uint256(0);
@@ -110,33 +107,19 @@ contract Outbox is DelegateCallAware, IOutbox {
110
107
  }
111
108
 
112
109
  /// @notice batch number is deprecated and now always returns 0
113
- function l2ToL1BatchNum() external pure override returns (uint256) {
110
+ function l2ToL1BatchNum() external pure returns (uint256) {
114
111
  return 0;
115
112
  }
116
113
 
117
- /// @return outputId returns the unique output identifier of the L2 to L1 tx or
118
- /// zero if no L2 to L1 transaction is active
119
- function l2ToL1OutputId() external view override returns (bytes32) {
114
+ /// @inheritdoc IOutbox
115
+ function l2ToL1OutputId() external view returns (bytes32) {
120
116
  bytes32 outputId = context.outputId;
121
117
  // we don't return the default context value to avoid a breaking change in the API
122
118
  if (outputId == OUTPUTID_DEFAULT_CONTEXT) return bytes32(0);
123
119
  return outputId;
124
120
  }
125
121
 
126
- /**
127
- * @notice Executes a messages in an Outbox entry.
128
- * @dev Reverts if dispute period hasn't expired, since the outbox entry
129
- * is only created once the rollup confirms the respective assertion.
130
- * @param proof Merkle proof of message inclusion in send root
131
- * @param index Merkle path to message
132
- * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
133
- * @param to destination address for L1 contract call
134
- * @param l2Block l2 block number at which sendTxToL1 call was made
135
- * @param l1Block l1 block number at which sendTxToL1 call was made
136
- * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
137
- * @param value wei in L1 message
138
- * @param data abi-encoded L1 message data
139
- */
122
+ /// @inheritdoc IOutbox
140
123
  function executeTransaction(
141
124
  bytes32[] calldata proof,
142
125
  uint256 index,
@@ -147,7 +130,7 @@ contract Outbox is DelegateCallAware, IOutbox {
147
130
  uint256 l2Timestamp,
148
131
  uint256 value,
149
132
  bytes calldata data
150
- ) external override {
133
+ ) external {
151
134
  bytes32 userTx = calculateItemHash(
152
135
  l2Sender,
153
136
  to,
@@ -163,15 +146,7 @@ contract Outbox is DelegateCallAware, IOutbox {
163
146
  executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
164
147
  }
165
148
 
166
- /// @dev function used to simulate the result of a particular function call from the outbox
167
- /// it is useful for things such as gas estimates. This function includes all costs except for
168
- /// proof validation (which can be considered offchain as a somewhat of a fixed cost - it's
169
- /// not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation).
170
- /// We can't include the cost of proof validation since this is intended to be used to simulate txs
171
- /// that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend
172
- /// to confirm a pending merkle root, but that would be less pratical for integrating with tooling.
173
- /// It is only possible to trigger it when the msg sender is address zero, which should be impossible
174
- /// unless under simulation in an eth_call or eth_estimateGas
149
+ /// @inheritdoc IOutbox
175
150
  function executeTransactionSimulation(
176
151
  uint256 index,
177
152
  address l2Sender,
@@ -181,7 +156,7 @@ contract Outbox is DelegateCallAware, IOutbox {
181
156
  uint256 l2Timestamp,
182
157
  uint256 value,
183
158
  bytes calldata data
184
- ) external override {
159
+ ) external {
185
160
  if (msg.sender != address(0)) revert SimulationOnlyEntrypoint();
186
161
  executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
187
162
  }
@@ -235,7 +210,8 @@ contract Outbox is DelegateCallAware, IOutbox {
235
210
  return ((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0);
236
211
  }
237
212
 
238
- function isSpent(uint256 index) external view override returns (bool) {
213
+ /// @inheritdoc IOutbox
214
+ function isSpent(uint256 index) external view returns (bool) {
239
215
  (, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
240
216
  return _isSpent(bitOffset, replay);
241
217
  }
@@ -285,7 +261,7 @@ contract Outbox is DelegateCallAware, IOutbox {
285
261
  uint256 l2Timestamp,
286
262
  uint256 value,
287
263
  bytes calldata data
288
- ) public pure override returns (bytes32) {
264
+ ) public pure returns (bytes32) {
289
265
  return
290
266
  keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
291
267
  }
@@ -294,7 +270,7 @@ contract Outbox is DelegateCallAware, IOutbox {
294
270
  bytes32[] memory proof,
295
271
  uint256 path,
296
272
  bytes32 item
297
- ) public pure override returns (bytes32) {
273
+ ) public pure returns (bytes32) {
298
274
  return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
299
275
  }
300
276
  }
@@ -19,7 +19,8 @@ import {
19
19
  BadSequencerNumber,
20
20
  DataNotAuthenticated,
21
21
  AlreadyValidDASKeyset,
22
- NoSuchKeyset
22
+ NoSuchKeyset,
23
+ NotForked
23
24
  } from "../libraries/Error.sol";
24
25
  import "./IBridge.sol";
25
26
  import "./IInbox.sol";
@@ -44,20 +45,16 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
44
45
 
45
46
  IBridge public bridge;
46
47
 
47
- /// @dev The size of the batch header
48
+ /// @inheritdoc ISequencerInbox
48
49
  uint256 public constant HEADER_LENGTH = 40;
49
- /// @dev If the first batch data byte after the header has this bit set,
50
- /// the sequencer inbox has authenticated the data. Currently not used.
50
+
51
+ /// @inheritdoc ISequencerInbox
51
52
  bytes1 public constant DATA_AUTHENTICATED_FLAG = 0x40;
52
53
 
53
54
  IOwnable public rollup;
54
55
  mapping(address => bool) public isBatchPoster;
55
56
  ISequencerInbox.MaxTimeVariation public maxTimeVariation;
56
57
 
57
- struct DasKeySetInfo {
58
- bool isValidKeyset;
59
- uint64 creationBlock;
60
- }
61
58
  mapping(bytes32 => DasKeySetInfo) public dasKeySetInfo;
62
59
 
63
60
  modifier onlyRollupOwner() {
@@ -65,6 +62,12 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
65
62
  _;
66
63
  }
67
64
 
65
+ uint256 internal immutable deployTimeChainId = block.chainid;
66
+
67
+ function _chainIdChanged() internal view returns (bool) {
68
+ return deployTimeChainId != block.chainid;
69
+ }
70
+
68
71
  function initialize(
69
72
  IBridge bridge_,
70
73
  ISequencerInbox.MaxTimeVariation calldata maxTimeVariation_
@@ -89,17 +92,18 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
89
92
  return bounds;
90
93
  }
91
94
 
92
- /// @notice Force messages from the delayed inbox to be included in the chain
93
- /// Callable by any address, but message can only be force-included after maxTimeVariation.delayBlocks and maxTimeVariation.delaySeconds
94
- /// has elapsed. As part of normal behaviour the sequencer will include these messages
95
- /// so it's only necessary to call this if the sequencer is down, or not including
96
- /// any delayed messages.
97
- /// @param _totalDelayedMessagesRead The total number of messages to read up to
98
- /// @param kind The kind of the last message to be included
99
- /// @param l1BlockAndTime The l1 block and the l1 timestamp of the last message to be included
100
- /// @param baseFeeL1 The l1 gas price of the last message to be included
101
- /// @param sender The sender of the last message to be included
102
- /// @param messageDataHash The messageDataHash of the last message to be included
95
+ /// @inheritdoc ISequencerInbox
96
+ function removeDelayAfterFork() external {
97
+ if (!_chainIdChanged()) revert NotForked();
98
+ maxTimeVariation = ISequencerInbox.MaxTimeVariation({
99
+ delayBlocks: 1,
100
+ futureBlocks: 1,
101
+ delaySeconds: 1,
102
+ futureSeconds: 1
103
+ });
104
+ }
105
+
106
+ /// @inheritdoc ISequencerInbox
103
107
  function forceInclusion(
104
108
  uint256 _totalDelayedMessagesRead,
105
109
  uint8 kind,
@@ -137,12 +141,23 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
137
141
  (bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash(
138
142
  _totalDelayedMessagesRead
139
143
  );
144
+ uint256 __totalDelayedMessagesRead = _totalDelayedMessagesRead;
145
+ uint256 prevSeqMsgCount = bridge.sequencerReportedSubMessageCount();
146
+ uint256 newSeqMsgCount = prevSeqMsgCount +
147
+ _totalDelayedMessagesRead -
148
+ totalDelayedMessagesRead;
140
149
  (
141
150
  uint256 seqMessageIndex,
142
151
  bytes32 beforeAcc,
143
152
  bytes32 delayedAcc,
144
153
  bytes32 afterAcc
145
- ) = addSequencerL2BatchImpl(dataHash, _totalDelayedMessagesRead, 0);
154
+ ) = addSequencerL2BatchImpl(
155
+ dataHash,
156
+ __totalDelayedMessagesRead,
157
+ 0,
158
+ prevSeqMsgCount,
159
+ newSeqMsgCount
160
+ );
146
161
  emit SequencerBatchDelivered(
147
162
  seqMessageIndex,
148
163
  beforeAcc,
@@ -154,6 +169,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
154
169
  );
155
170
  }
156
171
 
172
+ /// @dev Deprecated in favor of the variant specifying message counts for consistency
157
173
  function addSequencerL2BatchFromOrigin(
158
174
  uint256 sequenceNumber,
159
175
  bytes calldata data,
@@ -163,6 +179,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
163
179
  // solhint-disable-next-line avoid-tx-origin
164
180
  if (msg.sender != tx.origin) revert NotOrigin();
165
181
  if (!isBatchPoster[msg.sender]) revert NotBatchPoster();
182
+
166
183
  (bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
167
184
  data,
168
185
  afterDelayedMessagesRead
@@ -172,7 +189,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
172
189
  bytes32 beforeAcc,
173
190
  bytes32 delayedAcc,
174
191
  bytes32 afterAcc
175
- ) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, data.length);
192
+ ) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, data.length, 0, 0);
176
193
  if (seqMessageIndex != sequenceNumber)
177
194
  revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
178
195
  emit SequencerBatchDelivered(
@@ -186,38 +203,101 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
186
203
  );
187
204
  }
188
205
 
189
- function addSequencerL2Batch(
206
+ function addSequencerL2BatchFromOrigin(
190
207
  uint256 sequenceNumber,
191
208
  bytes calldata data,
192
209
  uint256 afterDelayedMessagesRead,
193
- IGasRefunder gasRefunder
194
- ) external override refundsGas(gasRefunder) {
195
- if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster();
196
-
210
+ IGasRefunder gasRefunder,
211
+ uint256 prevMessageCount,
212
+ uint256 newMessageCount
213
+ ) external refundsGas(gasRefunder) {
214
+ // solhint-disable-next-line avoid-tx-origin
215
+ if (msg.sender != tx.origin) revert NotOrigin();
216
+ if (!isBatchPoster[msg.sender]) revert NotBatchPoster();
197
217
  (bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
198
218
  data,
199
219
  afterDelayedMessagesRead
200
220
  );
201
- // we set the calldata length posted to 0 here since the caller isn't the origin
202
- // of the tx, so they might have not paid tx input cost for the calldata
221
+ // Reformat the stack to prevent "Stack too deep"
222
+ uint256 sequenceNumber_ = sequenceNumber;
223
+ TimeBounds memory timeBounds_ = timeBounds;
224
+ bytes32 dataHash_ = dataHash;
225
+ uint256 dataLength = data.length;
226
+ uint256 afterDelayedMessagesRead_ = afterDelayedMessagesRead;
227
+ uint256 prevMessageCount_ = prevMessageCount;
228
+ uint256 newMessageCount_ = newMessageCount;
203
229
  (
204
230
  uint256 seqMessageIndex,
205
231
  bytes32 beforeAcc,
206
232
  bytes32 delayedAcc,
207
233
  bytes32 afterAcc
208
- ) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, 0);
209
- if (seqMessageIndex != sequenceNumber)
210
- revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
234
+ ) = addSequencerL2BatchImpl(
235
+ dataHash_,
236
+ afterDelayedMessagesRead_,
237
+ dataLength,
238
+ prevMessageCount_,
239
+ newMessageCount_
240
+ );
241
+ if (seqMessageIndex != sequenceNumber_ && sequenceNumber_ != ~uint256(0))
242
+ revert BadSequencerNumber(seqMessageIndex, sequenceNumber_);
211
243
  emit SequencerBatchDelivered(
212
- sequenceNumber,
244
+ seqMessageIndex,
213
245
  beforeAcc,
214
246
  afterAcc,
215
247
  delayedAcc,
216
- afterDelayedMessagesRead,
217
- timeBounds,
218
- BatchDataLocation.SeparateBatchEvent
248
+ totalDelayedMessagesRead,
249
+ timeBounds_,
250
+ BatchDataLocation.TxInput
251
+ );
252
+ }
253
+
254
+ function addSequencerL2Batch(
255
+ uint256 sequenceNumber,
256
+ bytes calldata data,
257
+ uint256 afterDelayedMessagesRead,
258
+ IGasRefunder gasRefunder,
259
+ uint256 prevMessageCount,
260
+ uint256 newMessageCount
261
+ ) external override refundsGas(gasRefunder) {
262
+ if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster();
263
+ (bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
264
+ data,
265
+ afterDelayedMessagesRead
219
266
  );
220
- emit SequencerBatchData(sequenceNumber, data);
267
+ uint256 seqMessageIndex;
268
+ {
269
+ // Reformat the stack to prevent "Stack too deep"
270
+ uint256 sequenceNumber_ = sequenceNumber;
271
+ TimeBounds memory timeBounds_ = timeBounds;
272
+ bytes32 dataHash_ = dataHash;
273
+ uint256 afterDelayedMessagesRead_ = afterDelayedMessagesRead;
274
+ uint256 prevMessageCount_ = prevMessageCount;
275
+ uint256 newMessageCount_ = newMessageCount;
276
+ // we set the calldata length posted to 0 here since the caller isn't the origin
277
+ // of the tx, so they might have not paid tx input cost for the calldata
278
+ bytes32 beforeAcc;
279
+ bytes32 delayedAcc;
280
+ bytes32 afterAcc;
281
+ (seqMessageIndex, beforeAcc, delayedAcc, afterAcc) = addSequencerL2BatchImpl(
282
+ dataHash_,
283
+ afterDelayedMessagesRead_,
284
+ 0,
285
+ prevMessageCount_,
286
+ newMessageCount_
287
+ );
288
+ if (seqMessageIndex != sequenceNumber_ && sequenceNumber_ != ~uint256(0))
289
+ revert BadSequencerNumber(seqMessageIndex, sequenceNumber_);
290
+ emit SequencerBatchDelivered(
291
+ seqMessageIndex,
292
+ beforeAcc,
293
+ afterAcc,
294
+ delayedAcc,
295
+ totalDelayedMessagesRead,
296
+ timeBounds_,
297
+ BatchDataLocation.SeparateBatchEvent
298
+ );
299
+ }
300
+ emit SequencerBatchData(seqMessageIndex, data);
221
301
  }
222
302
 
223
303
  modifier validateBatchData(bytes calldata data) {
@@ -277,7 +357,9 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
277
357
  function addSequencerL2BatchImpl(
278
358
  bytes32 dataHash,
279
359
  uint256 afterDelayedMessagesRead,
280
- uint256 calldataLengthPosted
360
+ uint256 calldataLengthPosted,
361
+ uint256 prevMessageCount,
362
+ uint256 newMessageCount
281
363
  )
282
364
  internal
283
365
  returns (
@@ -292,7 +374,9 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
292
374
 
293
375
  (seqMessageIndex, beforeAcc, delayedAcc, acc) = bridge.enqueueSequencerMessage(
294
376
  dataHash,
295
- afterDelayedMessagesRead
377
+ afterDelayedMessagesRead,
378
+ prevMessageCount,
379
+ newMessageCount
296
380
  );
297
381
 
298
382
  totalDelayedMessagesRead = afterDelayedMessagesRead;
@@ -317,42 +401,31 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
317
401
  }
318
402
  }
319
403
 
320
- function inboxAccs(uint256 index) external view override returns (bytes32) {
404
+ function inboxAccs(uint256 index) external view returns (bytes32) {
321
405
  return bridge.sequencerInboxAccs(index);
322
406
  }
323
407
 
324
- function batchCount() external view override returns (uint256) {
408
+ function batchCount() external view returns (uint256) {
325
409
  return bridge.sequencerMessageCount();
326
410
  }
327
411
 
328
- /**
329
- * @notice Set max delay for sequencer inbox
330
- * @param maxTimeVariation_ the maximum time variation parameters
331
- */
412
+ /// @inheritdoc ISequencerInbox
332
413
  function setMaxTimeVariation(ISequencerInbox.MaxTimeVariation memory maxTimeVariation_)
333
414
  external
334
- override
335
415
  onlyRollupOwner
336
416
  {
337
417
  maxTimeVariation = maxTimeVariation_;
338
418
  emit OwnerFunctionCalled(0);
339
419
  }
340
420
 
341
- /**
342
- * @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox
343
- * @param addr the address
344
- * @param isBatchPoster_ if the specified address should be authorized as a batch poster
345
- */
346
- function setIsBatchPoster(address addr, bool isBatchPoster_) external override onlyRollupOwner {
421
+ /// @inheritdoc ISequencerInbox
422
+ function setIsBatchPoster(address addr, bool isBatchPoster_) external onlyRollupOwner {
347
423
  isBatchPoster[addr] = isBatchPoster_;
348
424
  emit OwnerFunctionCalled(1);
349
425
  }
350
426
 
351
- /**
352
- * @notice Makes Data Availability Service keyset valid
353
- * @param keysetBytes bytes of the serialized keyset
354
- */
355
- function setValidKeyset(bytes calldata keysetBytes) external override onlyRollupOwner {
427
+ /// @inheritdoc ISequencerInbox
428
+ function setValidKeyset(bytes calldata keysetBytes) external onlyRollupOwner {
356
429
  uint256 ksWord = uint256(keccak256(bytes.concat(hex"fe", keccak256(keysetBytes))));
357
430
  bytes32 ksHash = bytes32(ksWord ^ (1 << 255));
358
431
  require(keysetBytes.length < 64 * 1024, "keyset is too large");
@@ -366,11 +439,8 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
366
439
  emit OwnerFunctionCalled(2);
367
440
  }
368
441
 
369
- /**
370
- * @notice Invalidates a Data Availability Service keyset
371
- * @param ksHash hash of the keyset
372
- */
373
- function invalidateKeysetHash(bytes32 ksHash) external override onlyRollupOwner {
442
+ /// @inheritdoc ISequencerInbox
443
+ function invalidateKeysetHash(bytes32 ksHash) external onlyRollupOwner {
374
444
  if (!dasKeySetInfo[ksHash].isValidKeyset) revert NoSuchKeyset(ksHash);
375
445
  // we don't delete the block creation value since its used to fetch the SetValidKeyset
376
446
  // event efficiently. The event provides the hash preimage of the key.
@@ -384,7 +454,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
384
454
  return dasKeySetInfo[ksHash].isValidKeyset;
385
455
  }
386
456
 
387
- /// @notice the creation block is intended to still be available after a keyset is deleted
457
+ /// @inheritdoc ISequencerInbox
388
458
  function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256) {
389
459
  DasKeySetInfo memory ksInfo = dasKeySetInfo[ksHash];
390
460
  if (ksInfo.creationBlock == 0) revert NoSuchKeyset(ksHash);
@@ -285,15 +285,6 @@ contract ChallengeManager is DelegateCallAware, IChallengeManager {
285
285
  return challenges[challengeIndex].current.addr;
286
286
  }
287
287
 
288
- function currentResponderTimeLeft(uint64 challengeIndex)
289
- public
290
- view
291
- override
292
- returns (uint256)
293
- {
294
- return challenges[challengeIndex].current.timeLeft;
295
- }
296
-
297
288
  function isTimedOut(uint64 challengeIndex) public view override returns (bool) {
298
289
  return challenges[challengeIndex].isTimedOut();
299
290
  }
@@ -67,8 +67,6 @@ interface IChallengeManager {
67
67
 
68
68
  function isTimedOut(uint64 challengeIndex) external view returns (bool);
69
69
 
70
- function currentResponderTimeLeft(uint64 challengeIndex_) external view returns (uint256);
71
-
72
70
  function clearChallenge(uint64 challengeIndex_) external;
73
71
 
74
72
  function timeout(uint64 challengeIndex_) external;
@@ -87,7 +87,7 @@ abstract contract DoubleLogicERC1967Upgrade is ERC1967Upgrade {
87
87
  try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
88
88
  require(
89
89
  slot == _IMPLEMENTATION_SECONDARY_SLOT,
90
- "ERC1967Upgrade: unsupported proxiableUUID"
90
+ "ERC1967Upgrade: unsupported secondary proxiableUUID"
91
91
  );
92
92
  } catch {
93
93
  revert("ERC1967Upgrade: new secondary implementation is not UUPS");
@@ -132,8 +132,8 @@ contract AdminFallbackProxy is Proxy, DoubleLogicERC1967Upgrade {
132
132
  require(msg.data.length >= 4, "NO_FUNC_SIG");
133
133
  // if the sender is the proxy's admin, delegate to admin logic
134
134
  // if the admin is disabled, all calls will be forwarded to user logic
135
- // admin affordances can be disabled by setting to address(1) since
136
- // `ERC1697._setAdmin()` doesn't allow address(0) to be set
135
+ // admin affordances can be disabled by setting to a no-op smart contract
136
+ // since there is a check for contract code before updating the value
137
137
  address target = _getAdmin() != msg.sender
138
138
  ? DoubleLogicERC1967Upgrade._getSecondaryImplementation()
139
139
  : ERC1967Upgrade._getImplementation();
@@ -144,7 +144,7 @@ contract AdminFallbackProxy is Proxy, DoubleLogicERC1967Upgrade {
144
144
 
145
145
  /**
146
146
  * @dev unlike transparent upgradeable proxies, this does allow the admin to fallback to a logic contract
147
- * the admin is expected to interact only with the secondary logic contract, which handles contract
147
+ * the admin is expected to interact only with the primary logic contract, which handles contract
148
148
  * upgrades using the UUPS approach
149
149
  */
150
150
  function _beforeFallback() internal override {
@@ -8,3 +8,6 @@ pragma solidity ^0.8.4;
8
8
  uint256 constant MAX_DATA_SIZE = 117964;
9
9
 
10
10
  uint64 constant NO_CHAL_INDEX = 0;
11
+
12
+ // Expected seconds per block in Ethereum PoS
13
+ uint256 constant ETH_POS_BLOCK_TIME = 12;
@@ -8,8 +8,9 @@ import {DoubleLogicERC1967Upgrade} from "./AdminFallbackProxy.sol";
8
8
  import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
9
9
 
10
10
  /// @notice An extension to OZ's UUPSUpgradeable contract to be used for handling UUPS upgrades with a DoubleLogicERC1967Upgrade proxy
11
+ /// The should be used in the primary implementation slot of the DoubleLogicUUPS proxy
11
12
  /// @dev upgrades should be handles by the primary logic contract in order to pass the `onlyProxy` check
12
- abstract contract SecondaryLogicUUPSUpgradeable is UUPSUpgradeable, DoubleLogicERC1967Upgrade {
13
+ abstract contract DoubleLogicUUPSUpgradeable is UUPSUpgradeable, DoubleLogicERC1967Upgrade {
13
14
  /// @inheritdoc UUPSUpgradeable
14
15
  function proxiableUUID() external view override notDelegated returns (bytes32) {
15
16
  return _IMPLEMENTATION_SLOT;
@@ -96,6 +96,15 @@ error RetryableData(
96
96
  bytes data
97
97
  );
98
98
 
99
+ /// @dev Thrown when a L1 chainId fork is detected
100
+ error L1Forked();
101
+
102
+ /// @dev Thrown when a L1 chainId fork is not detected
103
+ error NotForked();
104
+
105
+ /// @dev The provided gasLimit is larger than uint64
106
+ error GasLimitTooLarge();
107
+
99
108
  // Outbox Errors
100
109
 
101
110
  /// @dev The provided proof was too long
@@ -141,6 +150,9 @@ error NotBatchPoster();
141
150
  /// @dev The sequence number provided to this message was inconsistent with the number of batches already included
142
151
  error BadSequencerNumber(uint256 stored, uint256 received);
143
152
 
153
+ /// @dev The sequence message number provided to this message was inconsistent with the previous one
154
+ error BadSequencerMessageNumber(uint256 stored, uint256 received);
155
+
144
156
  /// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
145
157
  error DataNotAuthenticated();
146
158
 
@@ -21,14 +21,20 @@ abstract contract GasRefundEnabled {
21
21
  uint256 startGasLeft = gasleft();
22
22
  _;
23
23
  if (address(gasRefunder) != address(0)) {
24
- uint256 calldataSize = 0;
24
+ uint256 calldataSize;
25
+ assembly {
26
+ calldataSize := calldatasize()
27
+ }
28
+ uint256 calldataWords = (calldataSize + 31) / 32;
29
+ // account for the CALLDATACOPY cost of the proxy contract, including the memory expansion cost
30
+ startGasLeft += calldataWords * 6 + (calldataWords**2) / 512;
25
31
  // if triggered in a contract call, the spender may be overrefunded by appending dummy data to the call
26
32
  // so we check if it is a top level call, which would mean the sender paid calldata as part of tx.input
27
33
  // solhint-disable-next-line avoid-tx-origin
28
- if (msg.sender == tx.origin) {
29
- assembly {
30
- calldataSize := calldatasize()
31
- }
34
+ if (msg.sender != tx.origin) {
35
+ // We can't be sure if this calldata came from the top level tx,
36
+ // so to be safe we tell the gas refunder there was no calldata.
37
+ calldataSize = 0;
32
38
  }
33
39
  gasRefunder.onGasSpent(payable(msg.sender), startGasLeft - gasleft(), calldataSize);
34
40
  }
@@ -33,9 +33,9 @@ library MerkleLib {
33
33
  uint256 proofItems = nodes.length;
34
34
  if (proofItems > 256) revert MerkleProofTooLong(proofItems, 256);
35
35
  bytes32 h = item;
36
- for (uint256 i = 0; i < proofItems; i++) {
36
+ for (uint256 i = 0; i < proofItems; ) {
37
37
  bytes32 node = nodes[i];
38
- if (route % 2 == 0) {
38
+ if ((route & (1 << i)) == 0) {
39
39
  assembly {
40
40
  mstore(0x00, h)
41
41
  mstore(0x20, node)
@@ -48,7 +48,9 @@ library MerkleLib {
48
48
  h := keccak256(0x00, 0x40)
49
49
  }
50
50
  }
51
- route /= 2;
51
+ unchecked {
52
+ ++i;
53
+ }
52
54
  }
53
55
  return h;
54
56
  }