@arbitrum/nitro-contracts 1.0.0-beta.8 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +1 -1
- package/hardhat.prod-config.js +4 -4
- package/package.json +21 -3
- package/src/bridge/Bridge.sol +39 -30
- package/src/bridge/IBridge.sol +56 -29
- package/src/bridge/IInbox.sol +130 -15
- package/src/bridge/IOutbox.sol +55 -7
- package/src/bridge/ISequencerInbox.sol +84 -7
- package/src/bridge/Inbox.sol +233 -93
- package/src/bridge/Outbox.sol +23 -47
- package/src/bridge/SequencerInbox.sol +132 -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 +6 -0
- package/src/libraries/{SecondaryLogicUUPSUpgradeable.sol → DoubleLogicUUPSUpgradeable.sol} +2 -1
- package/src/libraries/Error.sol +12 -0
- package/src/libraries/IGasRefunder.sol +11 -5
- package/src/libraries/MerkleLib.sol +5 -3
- package/src/mocks/BridgeStub.sol +20 -1
- package/src/mocks/BridgeUnproxied.sol +17 -0
- package/src/mocks/InboxStub.sol +48 -3
- package/src/mocks/SequencerInboxStub.sol +13 -3
- package/src/mocks/Simple.sol +69 -0
- package/src/node-interface/NodeInterface.sol +35 -4
- package/src/precompiles/ArbGasInfo.sol +7 -4
- package/src/precompiles/ArbOwner.sol +9 -0
- package/src/precompiles/ArbOwnerPublic.sol +3 -0
- package/src/precompiles/ArbSys.sol +5 -2
- package/src/rollup/IRollupCore.sol +2 -0
- package/src/rollup/IRollupLogic.sol +10 -0
- package/src/rollup/RollupAdminLogic.sol +27 -3
- package/src/rollup/RollupCore.sol +3 -0
- package/src/rollup/RollupCreator.sol +3 -3
- package/src/rollup/RollupEventInbox.sol +3 -6
- package/src/{libraries/ArbitrumProxy.sol → rollup/RollupProxy.sol} +3 -3
- package/src/rollup/RollupUserLogic.sol +47 -10
- package/src/test-helpers/BridgeTester.sol +7 -1
- package/src/test-helpers/OutboxWithoutOptTester.sol +8 -8
@@ -8,6 +8,7 @@ pragma experimental ABIEncoderV2;
|
|
8
8
|
|
9
9
|
import "../libraries/IGasRefunder.sol";
|
10
10
|
import "./IDelayedMessageProvider.sol";
|
11
|
+
import "./IBridge.sol";
|
11
12
|
|
12
13
|
interface ISequencerInbox is IDelayedMessageProvider {
|
13
14
|
struct MaxTimeVariation {
|
@@ -51,33 +52,109 @@ interface ISequencerInbox is IDelayedMessageProvider {
|
|
51
52
|
/// @dev a keyset was invalidated
|
52
53
|
event InvalidateKeyset(bytes32 indexed keysetHash);
|
53
54
|
|
55
|
+
function totalDelayedMessagesRead() external view returns (uint256);
|
56
|
+
|
57
|
+
function bridge() external view returns (IBridge);
|
58
|
+
|
59
|
+
/// @dev The size of the batch header
|
60
|
+
// solhint-disable-next-line func-name-mixedcase
|
61
|
+
function HEADER_LENGTH() external view returns (uint256);
|
62
|
+
|
63
|
+
/// @dev If the first batch data byte after the header has this bit set,
|
64
|
+
/// the sequencer inbox has authenticated the data. Currently not used.
|
65
|
+
// solhint-disable-next-line func-name-mixedcase
|
66
|
+
function DATA_AUTHENTICATED_FLAG() external view returns (bytes1);
|
67
|
+
|
68
|
+
function rollup() external view returns (IOwnable);
|
69
|
+
|
70
|
+
function isBatchPoster(address) external view returns (bool);
|
71
|
+
|
72
|
+
struct DasKeySetInfo {
|
73
|
+
bool isValidKeyset;
|
74
|
+
uint64 creationBlock;
|
75
|
+
}
|
76
|
+
|
77
|
+
// https://github.com/ethereum/solidity/issues/11826
|
78
|
+
// function maxTimeVariation() external view returns (MaxTimeVariation calldata);
|
79
|
+
// function dasKeySetInfo(bytes32) external view returns (DasKeySetInfo calldata);
|
80
|
+
|
81
|
+
/// @notice Remove force inclusion delay after a L1 chainId fork
|
82
|
+
function removeDelayAfterFork() external;
|
83
|
+
|
84
|
+
/// @notice Force messages from the delayed inbox to be included in the chain
|
85
|
+
/// Callable by any address, but message can only be force-included after maxTimeVariation.delayBlocks and
|
86
|
+
/// maxTimeVariation.delaySeconds has elapsed. As part of normal behaviour the sequencer will include these
|
87
|
+
/// messages so it's only necessary to call this if the sequencer is down, or not including any delayed messages.
|
88
|
+
/// @param _totalDelayedMessagesRead The total number of messages to read up to
|
89
|
+
/// @param kind The kind of the last message to be included
|
90
|
+
/// @param l1BlockAndTime The l1 block and the l1 timestamp of the last message to be included
|
91
|
+
/// @param baseFeeL1 The l1 gas price of the last message to be included
|
92
|
+
/// @param sender The sender of the last message to be included
|
93
|
+
/// @param messageDataHash The messageDataHash of the last message to be included
|
94
|
+
function forceInclusion(
|
95
|
+
uint256 _totalDelayedMessagesRead,
|
96
|
+
uint8 kind,
|
97
|
+
uint64[2] calldata l1BlockAndTime,
|
98
|
+
uint256 baseFeeL1,
|
99
|
+
address sender,
|
100
|
+
bytes32 messageDataHash
|
101
|
+
) external;
|
102
|
+
|
54
103
|
function inboxAccs(uint256 index) external view returns (bytes32);
|
55
104
|
|
56
105
|
function batchCount() external view returns (uint256);
|
57
106
|
|
58
|
-
function
|
107
|
+
function isValidKeysetHash(bytes32 ksHash) external view returns (bool);
|
108
|
+
|
109
|
+
/// @notice the creation block is intended to still be available after a keyset is deleted
|
110
|
+
function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256);
|
111
|
+
|
112
|
+
// ---------- BatchPoster functions ----------
|
113
|
+
|
114
|
+
function addSequencerL2BatchFromOrigin(
|
59
115
|
uint256 sequenceNumber,
|
60
116
|
bytes calldata data,
|
61
117
|
uint256 afterDelayedMessagesRead,
|
62
118
|
IGasRefunder gasRefunder
|
63
119
|
) external;
|
64
120
|
|
65
|
-
|
121
|
+
function addSequencerL2Batch(
|
122
|
+
uint256 sequenceNumber,
|
123
|
+
bytes calldata data,
|
124
|
+
uint256 afterDelayedMessagesRead,
|
125
|
+
IGasRefunder gasRefunder,
|
126
|
+
uint256 prevMessageCount,
|
127
|
+
uint256 newMessageCount
|
128
|
+
) external;
|
129
|
+
|
130
|
+
// ---------- onlyRollupOrOwner functions ----------
|
66
131
|
|
67
132
|
/**
|
68
|
-
* @notice Set max
|
69
|
-
* @param
|
133
|
+
* @notice Set max delay for sequencer inbox
|
134
|
+
* @param maxTimeVariation_ the maximum time variation parameters
|
70
135
|
*/
|
71
|
-
function setMaxTimeVariation(MaxTimeVariation memory
|
136
|
+
function setMaxTimeVariation(MaxTimeVariation memory maxTimeVariation_) external;
|
72
137
|
|
73
138
|
/**
|
74
139
|
* @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox
|
75
140
|
* @param addr the address
|
76
|
-
* @param
|
141
|
+
* @param isBatchPoster_ if the specified address should be authorized as a batch poster
|
77
142
|
*/
|
78
|
-
function setIsBatchPoster(address addr, bool
|
143
|
+
function setIsBatchPoster(address addr, bool isBatchPoster_) external;
|
79
144
|
|
145
|
+
/**
|
146
|
+
* @notice Makes Data Availability Service keyset valid
|
147
|
+
* @param keysetBytes bytes of the serialized keyset
|
148
|
+
*/
|
80
149
|
function setValidKeyset(bytes calldata keysetBytes) external;
|
81
150
|
|
151
|
+
/**
|
152
|
+
* @notice Invalidates a Data Availability Service keyset
|
153
|
+
* @param ksHash hash of the keyset
|
154
|
+
*/
|
82
155
|
function invalidateKeysetHash(bytes32 ksHash) external;
|
156
|
+
|
157
|
+
// ---------- initializer ----------
|
158
|
+
|
159
|
+
function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external;
|
83
160
|
}
|
package/src/bridge/Inbox.sol
CHANGED
@@ -15,7 +15,10 @@ import {
|
|
15
15
|
InsufficientSubmissionCost,
|
16
16
|
NotAllowedOrigin,
|
17
17
|
RetryableData,
|
18
|
-
NotRollupOrOwner
|
18
|
+
NotRollupOrOwner,
|
19
|
+
L1Forked,
|
20
|
+
NotForked,
|
21
|
+
GasLimitTooLarge
|
19
22
|
} from "../libraries/Error.sol";
|
20
23
|
import "./IInbox.sol";
|
21
24
|
import "./ISequencerInbox.sol";
|
@@ -32,7 +35,8 @@ import {
|
|
32
35
|
L2MessageType_unsignedEOATx,
|
33
36
|
L2MessageType_unsignedContractTx
|
34
37
|
} from "../libraries/MessageTypes.sol";
|
35
|
-
import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
|
38
|
+
import {MAX_DATA_SIZE, UNISWAP_L1_TIMELOCK, UNISWAP_L2_FACTORY} from "../libraries/Constants.sol";
|
39
|
+
import "../precompiles/ArbSys.sol";
|
36
40
|
|
37
41
|
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
|
38
42
|
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
@@ -43,7 +47,7 @@ import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
|
43
47
|
* to await inclusion in the SequencerInbox
|
44
48
|
*/
|
45
49
|
contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
46
|
-
IBridge public
|
50
|
+
IBridge public bridge;
|
47
51
|
ISequencerInbox public sequencerInbox;
|
48
52
|
|
49
53
|
/// ------------------------------------ allow list start ------------------------------------ ///
|
@@ -92,12 +96,18 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
92
96
|
_;
|
93
97
|
}
|
94
98
|
|
95
|
-
|
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
|
96
106
|
function pause() external onlyRollupOrOwner {
|
97
107
|
_pause();
|
98
108
|
}
|
99
109
|
|
100
|
-
/// @
|
110
|
+
/// @inheritdoc IInbox
|
101
111
|
function unpause() external onlyRollupOrOwner {
|
102
112
|
_unpause();
|
103
113
|
}
|
@@ -107,37 +117,23 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
107
117
|
initializer
|
108
118
|
onlyDelegated
|
109
119
|
{
|
110
|
-
if (address(bridge) != address(0)) revert AlreadyInit();
|
111
120
|
bridge = _bridge;
|
112
121
|
sequencerInbox = _sequencerInbox;
|
113
122
|
allowListEnabled = false;
|
114
123
|
__Pausable_init();
|
115
124
|
}
|
116
125
|
|
117
|
-
/// @
|
118
|
-
|
119
|
-
function postUpgradeInit(IBridge _bridge) external onlyDelegated onlyProxyOwner {
|
120
|
-
uint8 slotsToWipe = 3;
|
121
|
-
for (uint8 i = 0; i < slotsToWipe; i++) {
|
122
|
-
assembly {
|
123
|
-
sstore(i, 0)
|
124
|
-
}
|
125
|
-
}
|
126
|
-
allowListEnabled = false;
|
127
|
-
bridge = _bridge;
|
128
|
-
}
|
126
|
+
/// @inheritdoc IInbox
|
127
|
+
function postUpgradeInit(IBridge) external onlyDelegated onlyProxyOwner {}
|
129
128
|
|
130
|
-
|
131
|
-
* @notice Send a generic L2 message to the chain
|
132
|
-
* @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
|
133
|
-
* @param messageData Data of the message being sent
|
134
|
-
*/
|
129
|
+
/// @inheritdoc IInbox
|
135
130
|
function sendL2MessageFromOrigin(bytes calldata messageData)
|
136
131
|
external
|
137
132
|
whenNotPaused
|
138
133
|
onlyAllowed
|
139
134
|
returns (uint256)
|
140
135
|
{
|
136
|
+
if (_chainIdChanged()) revert L1Forked();
|
141
137
|
// solhint-disable-next-line avoid-tx-origin
|
142
138
|
if (msg.sender != tx.origin) revert NotOrigin();
|
143
139
|
if (messageData.length > MAX_DATA_SIZE)
|
@@ -147,18 +143,14 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
147
143
|
return msgNum;
|
148
144
|
}
|
149
145
|
|
150
|
-
|
151
|
-
* @notice Send a generic L2 message to the chain
|
152
|
-
* @dev This method can be used to send any type of message that doesn't require L1 validation
|
153
|
-
* @param messageData Data of the message being sent
|
154
|
-
*/
|
146
|
+
/// @inheritdoc IInbox
|
155
147
|
function sendL2Message(bytes calldata messageData)
|
156
148
|
external
|
157
|
-
override
|
158
149
|
whenNotPaused
|
159
150
|
onlyAllowed
|
160
151
|
returns (uint256)
|
161
152
|
{
|
153
|
+
if (_chainIdChanged()) revert L1Forked();
|
162
154
|
return _deliverMessage(L2_MSG, msg.sender, messageData);
|
163
155
|
}
|
164
156
|
|
@@ -168,7 +160,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
168
160
|
uint256 nonce,
|
169
161
|
address to,
|
170
162
|
bytes calldata data
|
171
|
-
) 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
|
+
}
|
172
168
|
return
|
173
169
|
_deliverMessage(
|
174
170
|
L1MessageType_L2FundedByL1,
|
@@ -190,7 +186,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
190
186
|
uint256 maxFeePerGas,
|
191
187
|
address to,
|
192
188
|
bytes calldata data
|
193
|
-
) 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
|
+
}
|
194
194
|
return
|
195
195
|
_deliverMessage(
|
196
196
|
L1MessageType_L2FundedByL1,
|
@@ -213,7 +213,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
213
213
|
address to,
|
214
214
|
uint256 value,
|
215
215
|
bytes calldata data
|
216
|
-
) 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
|
+
}
|
217
221
|
return
|
218
222
|
_deliverMessage(
|
219
223
|
L2_MSG,
|
@@ -236,7 +240,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
236
240
|
address to,
|
237
241
|
uint256 value,
|
238
242
|
bytes calldata data
|
239
|
-
) 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
|
+
}
|
240
248
|
return
|
241
249
|
_deliverMessage(
|
242
250
|
L2_MSG,
|
@@ -252,13 +260,104 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
252
260
|
);
|
253
261
|
}
|
254
262
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
|
262
361
|
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
|
263
362
|
public
|
264
363
|
view
|
@@ -268,20 +367,13 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
268
367
|
return (1400 + 6 * dataLength) * (baseFee == 0 ? block.basefee : baseFee);
|
269
368
|
}
|
270
369
|
|
271
|
-
/// @
|
272
|
-
|
273
|
-
/// Look into retryable tickets if you are interested in this functionality.
|
274
|
-
/// @dev this function should not be called inside contract constructors
|
275
|
-
function depositEth() public payable override whenNotPaused onlyAllowed returns (uint256) {
|
370
|
+
/// @inheritdoc IInbox
|
371
|
+
function depositEth() public payable whenNotPaused onlyAllowed returns (uint256) {
|
276
372
|
address dest = msg.sender;
|
277
373
|
|
278
374
|
// solhint-disable-next-line avoid-tx-origin
|
279
375
|
if (AddressUpgradeable.isContract(msg.sender) || tx.origin != msg.sender) {
|
280
376
|
// isContract check fails if this function is called during a contract's constructor.
|
281
|
-
// We don't adjust the address for calls coming from L1 contracts since their addresses get remapped
|
282
|
-
// If the caller is an EOA, we adjust the address.
|
283
|
-
// This is needed because unsigned messages to the L2 (such as retryables)
|
284
|
-
// have the L1 sender address mapped.
|
285
377
|
dest = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
|
286
378
|
}
|
287
379
|
|
@@ -294,15 +386,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
294
386
|
}
|
295
387
|
|
296
388
|
/// @notice deprecated in favour of depositEth with no parameters
|
297
|
-
function depositEth(uint256)
|
298
|
-
external
|
299
|
-
payable
|
300
|
-
virtual
|
301
|
-
override
|
302
|
-
whenNotPaused
|
303
|
-
onlyAllowed
|
304
|
-
returns (uint256)
|
305
|
-
{
|
389
|
+
function depositEth(uint256) external payable whenNotPaused onlyAllowed returns (uint256) {
|
306
390
|
return depositEth();
|
307
391
|
}
|
308
392
|
|
@@ -318,7 +402,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
318
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)
|
319
403
|
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
320
404
|
* @param data ABI encoded data of L2 message
|
321
|
-
* @return unique
|
405
|
+
* @return unique message number of the retryable transaction
|
322
406
|
*/
|
323
407
|
function createRetryableTicketNoRefundAliasRewrite(
|
324
408
|
address to,
|
@@ -329,7 +413,8 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
329
413
|
uint256 gasLimit,
|
330
414
|
uint256 maxFeePerGas,
|
331
415
|
bytes calldata data
|
332
|
-
) external payable
|
416
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
417
|
+
// gas limit is validated to be within uint64 in unsafeCreateRetryableTicket
|
333
418
|
return
|
334
419
|
unsafeCreateRetryableTicket(
|
335
420
|
to,
|
@@ -343,20 +428,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
343
428
|
);
|
344
429
|
}
|
345
430
|
|
346
|
-
|
347
|
-
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
|
348
|
-
* @dev all msg.value will deposited to callValueRefundAddress on L2
|
349
|
-
* @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
|
350
|
-
* @param to destination L2 contract address
|
351
|
-
* @param l2CallValue call value for retryable L2 message
|
352
|
-
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
|
353
|
-
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
|
354
|
-
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
|
355
|
-
* @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)
|
356
|
-
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
357
|
-
* @param data ABI encoded data of L2 message
|
358
|
-
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
359
|
-
*/
|
431
|
+
/// @inheritdoc IInbox
|
360
432
|
function createRetryableTicket(
|
361
433
|
address to,
|
362
434
|
uint256 l2CallValue,
|
@@ -366,7 +438,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
366
438
|
uint256 gasLimit,
|
367
439
|
uint256 maxFeePerGas,
|
368
440
|
bytes calldata data
|
369
|
-
) external payable
|
441
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
370
442
|
// ensure the user's deposit alone will make submission succeed
|
371
443
|
if (msg.value < (maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas)) {
|
372
444
|
revert InsufficientValue(
|
@@ -386,6 +458,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
386
458
|
callValueRefundAddress = AddressAliasHelper.applyL1ToL2Alias(callValueRefundAddress);
|
387
459
|
}
|
388
460
|
|
461
|
+
// gas limit is validated to be within uint64 in unsafeCreateRetryableTicket
|
389
462
|
return
|
390
463
|
unsafeCreateRetryableTicket(
|
391
464
|
to,
|
@@ -399,23 +472,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
399
472
|
);
|
400
473
|
}
|
401
474
|
|
402
|
-
|
403
|
-
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
|
404
|
-
* @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds
|
405
|
-
* come from the deposit alone, rather than falling back on the user's L2 balance
|
406
|
-
* @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).
|
407
|
-
* createRetryableTicket method is the recommended standard.
|
408
|
-
* @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
|
409
|
-
* @param to destination L2 contract address
|
410
|
-
* @param l2CallValue call value for retryable L2 message
|
411
|
-
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
|
412
|
-
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
|
413
|
-
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
|
414
|
-
* @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)
|
415
|
-
* @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
|
416
|
-
* @param data ABI encoded data of L2 message
|
417
|
-
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
418
|
-
*/
|
475
|
+
/// @inheritdoc IInbox
|
419
476
|
function unsafeCreateRetryableTicket(
|
420
477
|
address to,
|
421
478
|
uint256 l2CallValue,
|
@@ -425,7 +482,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
425
482
|
uint256 gasLimit,
|
426
483
|
uint256 maxFeePerGas,
|
427
484
|
bytes calldata data
|
428
|
-
) public payable
|
485
|
+
) public payable whenNotPaused onlyAllowed returns (uint256) {
|
429
486
|
// gas price and limit of 1 should never be a valid input, so instead they are used as
|
430
487
|
// magic values to trigger a revert in eth calls that surface data without requiring a tx trace
|
431
488
|
if (gasLimit == 1 || maxFeePerGas == 1)
|
@@ -442,6 +499,11 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
442
499
|
data
|
443
500
|
);
|
444
501
|
|
502
|
+
// arbos will discard retryable with gas limit too large
|
503
|
+
if (gasLimit > type(uint64).max) {
|
504
|
+
revert GasLimitTooLarge();
|
505
|
+
}
|
506
|
+
|
445
507
|
uint256 submissionFee = calculateRetryableSubmissionFee(data.length, block.basefee);
|
446
508
|
if (maxSubmissionCost < submissionFee)
|
447
509
|
revert InsufficientSubmissionCost(submissionFee, maxSubmissionCost);
|
@@ -465,6 +527,84 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
465
527
|
);
|
466
528
|
}
|
467
529
|
|
530
|
+
/// @notice This is an one-time-exception to resolve a misconfiguration of Uniswap Arbitrum deployment
|
531
|
+
/// Only the Uniswap L1 Timelock may call this function and it is allowed to create a crosschain
|
532
|
+
/// retryable ticket without address aliasing. More info here:
|
533
|
+
/// https://gov.uniswap.org/t/consensus-check-fix-the-cross-chain-messaging-bridge-on-arbitrum/18547
|
534
|
+
/// @dev This function will be removed in future releases
|
535
|
+
function uniswapCreateRetryableTicket(
|
536
|
+
address to,
|
537
|
+
uint256 l2CallValue,
|
538
|
+
uint256 maxSubmissionCost,
|
539
|
+
address excessFeeRefundAddress,
|
540
|
+
address callValueRefundAddress,
|
541
|
+
uint256 gasLimit,
|
542
|
+
uint256 maxFeePerGas,
|
543
|
+
bytes calldata data
|
544
|
+
) external payable whenNotPaused onlyAllowed returns (uint256) {
|
545
|
+
// this can only be called by UNISWAP_L1_TIMELOCK
|
546
|
+
require(msg.sender == UNISWAP_L1_TIMELOCK, "NOT_UNISWAP_L1_TIMELOCK");
|
547
|
+
// the retryable can only call UNISWAP_L2_FACTORY
|
548
|
+
require(to == UNISWAP_L2_FACTORY, "NOT_TO_UNISWAP_L2_FACTORY");
|
549
|
+
|
550
|
+
// ensure the user's deposit alone will make submission succeed
|
551
|
+
if (msg.value < (maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas)) {
|
552
|
+
revert InsufficientValue(
|
553
|
+
maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas,
|
554
|
+
msg.value
|
555
|
+
);
|
556
|
+
}
|
557
|
+
|
558
|
+
// if a refund address is a contract, we apply the alias to it
|
559
|
+
// so that it can access its funds on the L2
|
560
|
+
// since the beneficiary and other refund addresses don't get rewritten by arb-os
|
561
|
+
if (AddressUpgradeable.isContract(excessFeeRefundAddress)) {
|
562
|
+
excessFeeRefundAddress = AddressAliasHelper.applyL1ToL2Alias(excessFeeRefundAddress);
|
563
|
+
}
|
564
|
+
if (AddressUpgradeable.isContract(callValueRefundAddress)) {
|
565
|
+
// this is the beneficiary. be careful since this is the address that can cancel the retryable in the L2
|
566
|
+
callValueRefundAddress = AddressAliasHelper.applyL1ToL2Alias(callValueRefundAddress);
|
567
|
+
}
|
568
|
+
|
569
|
+
// gas price and limit of 1 should never be a valid input, so instead they are used as
|
570
|
+
// magic values to trigger a revert in eth calls that surface data without requiring a tx trace
|
571
|
+
if (gasLimit == 1 || maxFeePerGas == 1)
|
572
|
+
revert RetryableData(
|
573
|
+
msg.sender,
|
574
|
+
to,
|
575
|
+
l2CallValue,
|
576
|
+
msg.value,
|
577
|
+
maxSubmissionCost,
|
578
|
+
excessFeeRefundAddress,
|
579
|
+
callValueRefundAddress,
|
580
|
+
gasLimit,
|
581
|
+
maxFeePerGas,
|
582
|
+
data
|
583
|
+
);
|
584
|
+
|
585
|
+
uint256 submissionFee = calculateRetryableSubmissionFee(data.length, block.basefee);
|
586
|
+
if (maxSubmissionCost < submissionFee)
|
587
|
+
revert InsufficientSubmissionCost(submissionFee, maxSubmissionCost);
|
588
|
+
|
589
|
+
return
|
590
|
+
_deliverMessage(
|
591
|
+
L1MessageType_submitRetryableTx,
|
592
|
+
AddressAliasHelper.undoL1ToL2Alias(msg.sender),
|
593
|
+
abi.encodePacked(
|
594
|
+
uint256(uint160(to)),
|
595
|
+
l2CallValue,
|
596
|
+
msg.value,
|
597
|
+
maxSubmissionCost,
|
598
|
+
uint256(uint160(excessFeeRefundAddress)),
|
599
|
+
uint256(uint160(callValueRefundAddress)),
|
600
|
+
gasLimit,
|
601
|
+
maxFeePerGas,
|
602
|
+
data.length,
|
603
|
+
data
|
604
|
+
)
|
605
|
+
);
|
606
|
+
}
|
607
|
+
|
468
608
|
function _deliverMessage(
|
469
609
|
uint8 _kind,
|
470
610
|
address _sender,
|