@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.
- 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);
|