@arbitrum/nitro-contracts 1.0.0-beta.1
Sign up to get free protection for your applications and to get access to all the features.
- package/.prettierrc +5 -0
- package/.solhint.json +18 -0
- package/deploy/BridgeStubCreator.js +10 -0
- package/deploy/HashProofHelper.js +13 -0
- package/deploy/InboxStubCreator.js +17 -0
- package/deploy/OneStepProofEntryCreator.js +19 -0
- package/deploy/OneStepProver0Creator.js +14 -0
- package/deploy/OneStepProverHostIoCreator.js +14 -0
- package/deploy/OneStepProverMathCreator.js +14 -0
- package/deploy/OneStepProverMemoryCreator.js +14 -0
- package/deploy/SequencerInboxStubCreator.js +13 -0
- package/deploy/ValueArrayTesterCreator.js +13 -0
- package/hardhat.config.ts +47 -0
- package/hardhat.prod-config.js +18 -0
- package/package.json +49 -0
- package/scripts/build.bash +5 -0
- package/src/bridge/Bridge.sol +168 -0
- package/src/bridge/IBridge.sol +68 -0
- package/src/bridge/IInbox.sol +80 -0
- package/src/bridge/IMessageProvider.sol +11 -0
- package/src/bridge/IOutbox.sol +52 -0
- package/src/bridge/ISequencerInbox.sol +85 -0
- package/src/bridge/Inbox.sol +414 -0
- package/src/bridge/Messages.sol +38 -0
- package/src/bridge/Outbox.sol +188 -0
- package/src/bridge/SequencerInbox.sol +274 -0
- package/src/challenge/ChallengeLib.sol +135 -0
- package/src/challenge/ChallengeManager.sol +367 -0
- package/src/challenge/IChallengeManager.sol +75 -0
- package/src/challenge/IChallengeResultReceiver.sol +13 -0
- package/src/libraries/AddressAliasHelper.sol +29 -0
- package/src/libraries/AdminFallbackProxy.sol +153 -0
- package/src/libraries/ArbitrumProxy.sol +20 -0
- package/src/libraries/Constants.sol +10 -0
- package/src/libraries/CryptographyPrimitives.sol +323 -0
- package/src/libraries/DelegateCallAware.sol +44 -0
- package/src/libraries/Error.sol +38 -0
- package/src/libraries/IGasRefunder.sol +35 -0
- package/src/libraries/MerkleLib.sol +46 -0
- package/src/libraries/MessageTypes.sol +14 -0
- package/src/libraries/SecondaryLogicUUPSUpgradeable.sol +58 -0
- package/src/libraries/UUPSNotUpgradeable.sol +56 -0
- package/src/mocks/BridgeStub.sol +115 -0
- package/src/mocks/Counter.sol +13 -0
- package/src/mocks/ExecutionManager.sol +41 -0
- package/src/mocks/InboxStub.sol +131 -0
- package/src/mocks/MockResultReceiver.sol +59 -0
- package/src/mocks/SequencerInboxStub.sol +42 -0
- package/src/mocks/SimpleProxy.sol +19 -0
- package/src/node-interface/NodeInterface.sol +50 -0
- package/src/osp/HashProofHelper.sol +154 -0
- package/src/osp/IOneStepProofEntry.sol +20 -0
- package/src/osp/IOneStepProver.sol +27 -0
- package/src/osp/OneStepProofEntry.sol +129 -0
- package/src/osp/OneStepProver0.sol +566 -0
- package/src/osp/OneStepProverHostIo.sol +357 -0
- package/src/osp/OneStepProverMath.sol +514 -0
- package/src/osp/OneStepProverMemory.sol +313 -0
- package/src/precompiles/ArbAddressTable.sol +60 -0
- package/src/precompiles/ArbAggregator.sol +62 -0
- package/src/precompiles/ArbBLS.sol +53 -0
- package/src/precompiles/ArbDebug.sol +39 -0
- package/src/precompiles/ArbFunctionTable.sol +29 -0
- package/src/precompiles/ArbGasInfo.sol +121 -0
- package/src/precompiles/ArbInfo.sol +15 -0
- package/src/precompiles/ArbOwner.sol +65 -0
- package/src/precompiles/ArbOwnerPublic.sol +18 -0
- package/src/precompiles/ArbRetryableTx.sol +89 -0
- package/src/precompiles/ArbStatistics.sol +29 -0
- package/src/precompiles/ArbSys.sol +134 -0
- package/src/precompiles/ArbosActs.sol +41 -0
- package/src/precompiles/ArbosTest.sol +14 -0
- package/src/rollup/BridgeCreator.sol +120 -0
- package/src/rollup/IRollupCore.sol +152 -0
- package/src/rollup/IRollupLogic.sol +183 -0
- package/src/rollup/Node.sol +99 -0
- package/src/rollup/RollupAdminLogic.sol +322 -0
- package/src/rollup/RollupCore.sol +627 -0
- package/src/rollup/RollupCreator.sol +133 -0
- package/src/rollup/RollupEventBridge.sol +46 -0
- package/src/rollup/RollupLib.sol +135 -0
- package/src/rollup/RollupUserLogic.sol +712 -0
- package/src/rollup/ValidatorUtils.sol +243 -0
- package/src/rollup/ValidatorWallet.sol +76 -0
- package/src/rollup/ValidatorWalletCreator.sol +43 -0
- package/src/state/Deserialize.sol +321 -0
- package/src/state/GlobalState.sol +44 -0
- package/src/state/Instructions.sol +159 -0
- package/src/state/Machine.sol +65 -0
- package/src/state/MerkleProof.sol +99 -0
- package/src/state/Module.sol +33 -0
- package/src/state/ModuleMemory.sol +42 -0
- package/src/state/PcArray.sol +45 -0
- package/src/state/PcStack.sol +32 -0
- package/src/state/StackFrame.sol +63 -0
- package/src/state/Value.sol +65 -0
- package/src/state/ValueArray.sol +47 -0
- package/src/state/ValueStack.sol +39 -0
- package/src/test-helpers/CryptographyPrimitivesTester.sol +27 -0
- package/src/test-helpers/MessageTester.sol +34 -0
- package/src/test-helpers/ValueArrayTester.sol +34 -0
- package/test/contract/arbRollup.spec.ts +869 -0
- package/test/contract/common/challengeLib.ts +43 -0
- package/test/contract/common/globalStateLib.ts +17 -0
- package/test/contract/common/rolluplib.ts +259 -0
- package/test/contract/cryptographyPrimitives.spec.ts +82 -0
- package/test/contract/sequencerInboxForceInclude.spec.ts +516 -0
- package/test/contract/utils.ts +40 -0
- package/test/prover/hash-proofs.ts +75 -0
- package/test/prover/one-step-proof.ts +93 -0
- package/test/prover/proofs/.gitkeep +0 -0
- package/test/prover/value-arrays.ts +11 -0
- package/tsconfig.json +13 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
// Copyright 2021-2022, Offchain Labs, Inc.
|
2
|
+
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
4
|
+
|
5
|
+
pragma solidity ^0.8.4;
|
6
|
+
|
7
|
+
import {AlreadyInit, NotRollup} from "../libraries/Error.sol";
|
8
|
+
|
9
|
+
/// @dev The provided proof was too long
|
10
|
+
/// @param proofLength The length of the too-long proof
|
11
|
+
error ProofTooLong(uint256 proofLength);
|
12
|
+
|
13
|
+
/// @dev The output index was greater than the maximum
|
14
|
+
/// @param index The output index
|
15
|
+
/// @param maxIndex The max the index could be
|
16
|
+
error PathNotMinimal(uint256 index, uint256 maxIndex);
|
17
|
+
|
18
|
+
/// @dev The calculated root does not exist
|
19
|
+
/// @param root The calculated root
|
20
|
+
error UnknownRoot(bytes32 root);
|
21
|
+
|
22
|
+
/// @dev The record has already been spent
|
23
|
+
/// @param index The index of the spent record
|
24
|
+
error AlreadySpent(uint256 index);
|
25
|
+
|
26
|
+
/// @dev A call to the bridge failed with no return data
|
27
|
+
error BridgeCallFailed();
|
28
|
+
|
29
|
+
interface IOutbox {
|
30
|
+
event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot);
|
31
|
+
event OutBoxTransactionExecuted(
|
32
|
+
address indexed to,
|
33
|
+
address indexed l2Sender,
|
34
|
+
uint256 indexed zero,
|
35
|
+
uint256 transactionIndex
|
36
|
+
);
|
37
|
+
|
38
|
+
function l2ToL1Sender() external view returns (address);
|
39
|
+
|
40
|
+
function l2ToL1Block() external view returns (uint256);
|
41
|
+
|
42
|
+
function l2ToL1EthBlock() external view returns (uint256);
|
43
|
+
|
44
|
+
function l2ToL1Timestamp() external view returns (uint256);
|
45
|
+
|
46
|
+
// @deprecated batch number is now always 0
|
47
|
+
function l2ToL1BatchNum() external view returns (uint256);
|
48
|
+
|
49
|
+
function l2ToL1OutputId() external view returns (bytes32);
|
50
|
+
|
51
|
+
function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;
|
52
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
// Copyright 2021-2022, Offchain Labs, Inc.
|
2
|
+
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
4
|
+
|
5
|
+
pragma solidity ^0.8.0;
|
6
|
+
|
7
|
+
import "../libraries/IGasRefunder.sol";
|
8
|
+
import {AlreadyInit, HadZeroInit, NotOrigin, DataTooLarge, NotRollup} from "../libraries/Error.sol";
|
9
|
+
|
10
|
+
interface ISequencerInbox {
|
11
|
+
struct MaxTimeVariation {
|
12
|
+
uint256 delayBlocks;
|
13
|
+
uint256 futureBlocks;
|
14
|
+
uint256 delaySeconds;
|
15
|
+
uint256 futureSeconds;
|
16
|
+
}
|
17
|
+
|
18
|
+
struct TimeBounds {
|
19
|
+
uint64 minTimestamp;
|
20
|
+
uint64 maxTimestamp;
|
21
|
+
uint64 minBlockNumber;
|
22
|
+
uint64 maxBlockNumber;
|
23
|
+
}
|
24
|
+
|
25
|
+
enum BatchDataLocation {
|
26
|
+
TxInput,
|
27
|
+
SeparateBatchEvent,
|
28
|
+
NoData
|
29
|
+
}
|
30
|
+
|
31
|
+
event SequencerBatchDelivered(
|
32
|
+
uint256 indexed batchSequenceNumber,
|
33
|
+
bytes32 indexed beforeAcc,
|
34
|
+
bytes32 indexed afterAcc,
|
35
|
+
bytes32 delayedAcc,
|
36
|
+
uint256 afterDelayedMessagesRead,
|
37
|
+
TimeBounds timeBounds,
|
38
|
+
BatchDataLocation dataLocation
|
39
|
+
);
|
40
|
+
|
41
|
+
/// @dev a separate event that emits batch data when this isn't easily accessible in the tx.input
|
42
|
+
event SequencerBatchData(uint256 indexed batchSequenceNumber, bytes data);
|
43
|
+
|
44
|
+
/// @dev Thrown when someone attempts to read fewer messages than have already been read
|
45
|
+
error DelayedBackwards();
|
46
|
+
|
47
|
+
/// @dev Thrown when someone attempts to read more messages than exist
|
48
|
+
error DelayedTooFar();
|
49
|
+
|
50
|
+
/// @dev Thrown if the length of the header plus the length of the batch overflows
|
51
|
+
error DataLengthOverflow();
|
52
|
+
|
53
|
+
/// @dev Force include can only read messages more blocks old than the delay period
|
54
|
+
error ForceIncludeBlockTooSoon();
|
55
|
+
|
56
|
+
/// @dev Force include can only read messages more seconds old than the delay period
|
57
|
+
error ForceIncludeTimeTooSoon();
|
58
|
+
|
59
|
+
/// @dev The message provided did not match the hash in the delayed inbox
|
60
|
+
error IncorrectMessagePreimage();
|
61
|
+
|
62
|
+
/// @dev This can only be called by the batch poster
|
63
|
+
error NotBatchPoster();
|
64
|
+
|
65
|
+
/// @dev The sequence number provided to this message was inconsistent with the number of batches already included
|
66
|
+
error BadSequencerNumber();
|
67
|
+
|
68
|
+
/// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
|
69
|
+
error DataNotAuthenticated();
|
70
|
+
|
71
|
+
function inboxAccs(uint256 index) external view returns (bytes32);
|
72
|
+
|
73
|
+
function batchCount() external view returns (uint256);
|
74
|
+
|
75
|
+
function setMaxTimeVariation(MaxTimeVariation memory timeVariation) external;
|
76
|
+
|
77
|
+
function setIsBatchPoster(address addr, bool isBatchPoster_) external;
|
78
|
+
|
79
|
+
function addSequencerL2Batch(
|
80
|
+
uint256 sequenceNumber,
|
81
|
+
bytes calldata data,
|
82
|
+
uint256 afterDelayedMessagesRead,
|
83
|
+
IGasRefunder gasRefunder
|
84
|
+
) external;
|
85
|
+
}
|
@@ -0,0 +1,414 @@
|
|
1
|
+
// Copyright 2021-2022, Offchain Labs, Inc.
|
2
|
+
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
4
|
+
|
5
|
+
pragma solidity ^0.8.4;
|
6
|
+
|
7
|
+
import "./IInbox.sol";
|
8
|
+
import "./IBridge.sol";
|
9
|
+
|
10
|
+
import "./Messages.sol";
|
11
|
+
import "../libraries/AddressAliasHelper.sol";
|
12
|
+
import "../libraries/DelegateCallAware.sol";
|
13
|
+
import {
|
14
|
+
L2_MSG,
|
15
|
+
L1MessageType_L2FundedByL1,
|
16
|
+
L1MessageType_submitRetryableTx,
|
17
|
+
L2MessageType_unsignedEOATx,
|
18
|
+
L2MessageType_unsignedContractTx
|
19
|
+
} from "../libraries/MessageTypes.sol";
|
20
|
+
import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
|
21
|
+
|
22
|
+
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
|
23
|
+
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
24
|
+
import "./Bridge.sol";
|
25
|
+
|
26
|
+
/**
|
27
|
+
* @title Inbox for user and contract originated messages
|
28
|
+
* @notice Messages created via this inbox are enqueued in the delayed accumulator
|
29
|
+
* to await inclusion in the SequencerInbox
|
30
|
+
*/
|
31
|
+
contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
32
|
+
IBridge public override bridge;
|
33
|
+
|
34
|
+
modifier onlyOwner() {
|
35
|
+
// whoevever owns the Bridge, also owns the Inbox. this is usually the rollup contract
|
36
|
+
address bridgeOwner = Bridge(address(bridge)).owner();
|
37
|
+
if (msg.sender != bridgeOwner) revert NotOwner(msg.sender, bridgeOwner);
|
38
|
+
_;
|
39
|
+
}
|
40
|
+
|
41
|
+
/// @notice pauses all inbox functionality
|
42
|
+
function pause() external onlyOwner {
|
43
|
+
_pause();
|
44
|
+
}
|
45
|
+
|
46
|
+
/// @notice unpauses all inbox functionality
|
47
|
+
function unpause() external onlyOwner {
|
48
|
+
_unpause();
|
49
|
+
}
|
50
|
+
|
51
|
+
function initialize(IBridge _bridge) external initializer onlyDelegated {
|
52
|
+
if (address(bridge) != address(0)) revert AlreadyInit();
|
53
|
+
bridge = _bridge;
|
54
|
+
__Pausable_init();
|
55
|
+
}
|
56
|
+
|
57
|
+
/// @dev function to be called one time during the inbox upgrade process
|
58
|
+
/// this is used to fix the storage slots
|
59
|
+
function postUpgradeInit(IBridge _bridge) external onlyDelegated onlyProxyOwner {
|
60
|
+
uint8 slotsToWipe = 3;
|
61
|
+
for (uint8 i = 0; i < slotsToWipe; i++) {
|
62
|
+
assembly {
|
63
|
+
sstore(i, 0)
|
64
|
+
}
|
65
|
+
}
|
66
|
+
bridge = _bridge;
|
67
|
+
}
|
68
|
+
|
69
|
+
/**
|
70
|
+
* @notice Send a generic L2 message to the chain
|
71
|
+
* @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
|
72
|
+
* @param messageData Data of the message being sent
|
73
|
+
*/
|
74
|
+
function sendL2MessageFromOrigin(bytes calldata messageData)
|
75
|
+
external
|
76
|
+
whenNotPaused
|
77
|
+
returns (uint256)
|
78
|
+
{
|
79
|
+
// solhint-disable-next-line avoid-tx-origin
|
80
|
+
if (msg.sender != tx.origin) revert NotOrigin();
|
81
|
+
if (messageData.length > MAX_DATA_SIZE)
|
82
|
+
revert DataTooLarge(messageData.length, MAX_DATA_SIZE);
|
83
|
+
uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData));
|
84
|
+
emit InboxMessageDeliveredFromOrigin(msgNum);
|
85
|
+
return msgNum;
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* @notice Send a generic L2 message to the chain
|
90
|
+
* @dev This method can be used to send any type of message that doesn't require L1 validation
|
91
|
+
* @param messageData Data of the message being sent
|
92
|
+
*/
|
93
|
+
function sendL2Message(bytes calldata messageData)
|
94
|
+
external
|
95
|
+
override
|
96
|
+
whenNotPaused
|
97
|
+
returns (uint256)
|
98
|
+
{
|
99
|
+
if (messageData.length > MAX_DATA_SIZE)
|
100
|
+
revert DataTooLarge(messageData.length, MAX_DATA_SIZE);
|
101
|
+
uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData));
|
102
|
+
emit InboxMessageDelivered(msgNum, messageData);
|
103
|
+
return msgNum;
|
104
|
+
}
|
105
|
+
|
106
|
+
function sendL1FundedUnsignedTransaction(
|
107
|
+
uint256 gasLimit,
|
108
|
+
uint256 maxFeePerGas,
|
109
|
+
uint256 nonce,
|
110
|
+
address to,
|
111
|
+
bytes calldata data
|
112
|
+
) external payable virtual override whenNotPaused returns (uint256) {
|
113
|
+
return
|
114
|
+
_deliverMessage(
|
115
|
+
L1MessageType_L2FundedByL1,
|
116
|
+
msg.sender,
|
117
|
+
abi.encodePacked(
|
118
|
+
L2MessageType_unsignedEOATx,
|
119
|
+
gasLimit,
|
120
|
+
maxFeePerGas,
|
121
|
+
nonce,
|
122
|
+
uint256(uint160(to)),
|
123
|
+
msg.value,
|
124
|
+
data
|
125
|
+
)
|
126
|
+
);
|
127
|
+
}
|
128
|
+
|
129
|
+
function sendL1FundedContractTransaction(
|
130
|
+
uint256 gasLimit,
|
131
|
+
uint256 maxFeePerGas,
|
132
|
+
address to,
|
133
|
+
bytes calldata data
|
134
|
+
) external payable virtual override whenNotPaused returns (uint256) {
|
135
|
+
return
|
136
|
+
_deliverMessage(
|
137
|
+
L1MessageType_L2FundedByL1,
|
138
|
+
msg.sender,
|
139
|
+
abi.encodePacked(
|
140
|
+
L2MessageType_unsignedContractTx,
|
141
|
+
gasLimit,
|
142
|
+
maxFeePerGas,
|
143
|
+
uint256(uint160(to)),
|
144
|
+
msg.value,
|
145
|
+
data
|
146
|
+
)
|
147
|
+
);
|
148
|
+
}
|
149
|
+
|
150
|
+
function sendUnsignedTransaction(
|
151
|
+
uint256 gasLimit,
|
152
|
+
uint256 maxFeePerGas,
|
153
|
+
uint256 nonce,
|
154
|
+
address to,
|
155
|
+
uint256 value,
|
156
|
+
bytes calldata data
|
157
|
+
) external virtual override whenNotPaused returns (uint256) {
|
158
|
+
return
|
159
|
+
_deliverMessage(
|
160
|
+
L2_MSG,
|
161
|
+
msg.sender,
|
162
|
+
abi.encodePacked(
|
163
|
+
L2MessageType_unsignedEOATx,
|
164
|
+
gasLimit,
|
165
|
+
maxFeePerGas,
|
166
|
+
nonce,
|
167
|
+
uint256(uint160(to)),
|
168
|
+
value,
|
169
|
+
data
|
170
|
+
)
|
171
|
+
);
|
172
|
+
}
|
173
|
+
|
174
|
+
function sendContractTransaction(
|
175
|
+
uint256 gasLimit,
|
176
|
+
uint256 maxFeePerGas,
|
177
|
+
address to,
|
178
|
+
uint256 value,
|
179
|
+
bytes calldata data
|
180
|
+
) external virtual override whenNotPaused returns (uint256) {
|
181
|
+
return
|
182
|
+
_deliverMessage(
|
183
|
+
L2_MSG,
|
184
|
+
msg.sender,
|
185
|
+
abi.encodePacked(
|
186
|
+
L2MessageType_unsignedContractTx,
|
187
|
+
gasLimit,
|
188
|
+
maxFeePerGas,
|
189
|
+
uint256(uint160(to)),
|
190
|
+
value,
|
191
|
+
data
|
192
|
+
)
|
193
|
+
);
|
194
|
+
}
|
195
|
+
|
196
|
+
/**
|
197
|
+
* @notice Get the L1 fee for submitting a retryable
|
198
|
+
* @dev This fee can be paid by funds already in the L2 aliased address or by the current message value
|
199
|
+
* @dev This formula may change in the future, to future proof your code query this method instead of inlining!!
|
200
|
+
* @param dataLength The length of the retryable's calldata, in bytes
|
201
|
+
* @param baseFee The block basefee when the retryable is included in the chain
|
202
|
+
*/
|
203
|
+
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
|
204
|
+
public
|
205
|
+
pure
|
206
|
+
returns (uint256)
|
207
|
+
{
|
208
|
+
return (1400 + 6 * dataLength) * baseFee;
|
209
|
+
}
|
210
|
+
|
211
|
+
/// @notice deposit eth from L1 to L2
|
212
|
+
/// @dev this function should not be called inside contract constructors
|
213
|
+
function depositEth(uint256 maxSubmissionCost)
|
214
|
+
external
|
215
|
+
payable
|
216
|
+
virtual
|
217
|
+
override
|
218
|
+
whenNotPaused
|
219
|
+
returns (uint256)
|
220
|
+
{
|
221
|
+
address sender = msg.sender;
|
222
|
+
address destinationAddress = msg.sender;
|
223
|
+
|
224
|
+
uint256 submissionFee = calculateRetryableSubmissionFee(0, block.basefee);
|
225
|
+
require(maxSubmissionCost >= submissionFee, "insufficient submission fee");
|
226
|
+
|
227
|
+
// solhint-disable-next-line avoid-tx-origin
|
228
|
+
if (!AddressUpgradeable.isContract(sender) && tx.origin == msg.sender) {
|
229
|
+
// isContract check fails if this function is called during a contract's constructor.
|
230
|
+
// We don't adjust the address for calls coming from L1 contracts since their addresses get remapped
|
231
|
+
// If the caller is an EOA, we adjust the address.
|
232
|
+
// This is needed because unsigned messages to the L2 (such as retryables)
|
233
|
+
// have the L1 sender address mapped.
|
234
|
+
// Here we preemptively reverse the mapping for EOAs so deposits work as expected
|
235
|
+
sender = AddressAliasHelper.undoL1ToL2Alias(sender);
|
236
|
+
} else {
|
237
|
+
destinationAddress = AddressAliasHelper.applyL1ToL2Alias(destinationAddress);
|
238
|
+
}
|
239
|
+
|
240
|
+
return
|
241
|
+
_deliverMessage(
|
242
|
+
L1MessageType_submitRetryableTx,
|
243
|
+
sender,
|
244
|
+
abi.encodePacked(
|
245
|
+
// the beneficiary and other refund addresses don't get rewritten by arb-os
|
246
|
+
// so we use the original msg.sender value
|
247
|
+
uint256(uint160(bytes20(destinationAddress))),
|
248
|
+
uint256(0),
|
249
|
+
msg.value,
|
250
|
+
maxSubmissionCost,
|
251
|
+
uint256(uint160(bytes20(destinationAddress))),
|
252
|
+
uint256(uint160(bytes20(destinationAddress))),
|
253
|
+
uint256(0),
|
254
|
+
uint256(0),
|
255
|
+
uint256(0),
|
256
|
+
""
|
257
|
+
)
|
258
|
+
);
|
259
|
+
}
|
260
|
+
|
261
|
+
/**
|
262
|
+
* @notice deprecated in favour of unsafeCreateRetryableTicket
|
263
|
+
* @dev deprecated in favour of unsafeCreateRetryableTicket
|
264
|
+
* @param to destination L2 contract address
|
265
|
+
* @param l2CallValue call value for retryable L2 message
|
266
|
+
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
|
267
|
+
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
|
268
|
+
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
|
269
|
+
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution
|
270
|
+
* @param maxFeePerGas price bid for L2 execution
|
271
|
+
* @param data ABI encoded data of L2 message
|
272
|
+
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
273
|
+
*/
|
274
|
+
function createRetryableTicketNoRefundAliasRewrite(
|
275
|
+
address to,
|
276
|
+
uint256 l2CallValue,
|
277
|
+
uint256 maxSubmissionCost,
|
278
|
+
address excessFeeRefundAddress,
|
279
|
+
address callValueRefundAddress,
|
280
|
+
uint256 gasLimit,
|
281
|
+
uint256 maxFeePerGas,
|
282
|
+
bytes calldata data
|
283
|
+
) external payable virtual whenNotPaused returns (uint256) {
|
284
|
+
return
|
285
|
+
unsafeCreateRetryableTicket(
|
286
|
+
to,
|
287
|
+
l2CallValue,
|
288
|
+
maxSubmissionCost,
|
289
|
+
excessFeeRefundAddress,
|
290
|
+
callValueRefundAddress,
|
291
|
+
gasLimit,
|
292
|
+
maxFeePerGas,
|
293
|
+
data
|
294
|
+
);
|
295
|
+
}
|
296
|
+
|
297
|
+
/**
|
298
|
+
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
|
299
|
+
* @dev all msg.value will deposited to callValueRefundAddress on L2
|
300
|
+
* @param to destination L2 contract address
|
301
|
+
* @param l2CallValue call value for retryable L2 message
|
302
|
+
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
|
303
|
+
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
|
304
|
+
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
|
305
|
+
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution
|
306
|
+
* @param maxFeePerGas price bid for L2 execution
|
307
|
+
* @param data ABI encoded data of L2 message
|
308
|
+
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
309
|
+
*/
|
310
|
+
function createRetryableTicket(
|
311
|
+
address to,
|
312
|
+
uint256 l2CallValue,
|
313
|
+
uint256 maxSubmissionCost,
|
314
|
+
address excessFeeRefundAddress,
|
315
|
+
address callValueRefundAddress,
|
316
|
+
uint256 gasLimit,
|
317
|
+
uint256 maxFeePerGas,
|
318
|
+
bytes calldata data
|
319
|
+
) external payable virtual override whenNotPaused returns (uint256) {
|
320
|
+
// ensure the user's deposit alone will make submission succeed
|
321
|
+
require(msg.value >= maxSubmissionCost + l2CallValue, "insufficient value");
|
322
|
+
|
323
|
+
// if a refund address is a contract, we apply the alias to it
|
324
|
+
// so that it can access its funds on the L2
|
325
|
+
// since the beneficiary and other refund addresses don't get rewritten by arb-os
|
326
|
+
if (AddressUpgradeable.isContract(excessFeeRefundAddress)) {
|
327
|
+
excessFeeRefundAddress = AddressAliasHelper.applyL1ToL2Alias(excessFeeRefundAddress);
|
328
|
+
}
|
329
|
+
if (AddressUpgradeable.isContract(callValueRefundAddress)) {
|
330
|
+
// this is the beneficiary. be careful since this is the address that can cancel the retryable in the L2
|
331
|
+
callValueRefundAddress = AddressAliasHelper.applyL1ToL2Alias(callValueRefundAddress);
|
332
|
+
}
|
333
|
+
|
334
|
+
return
|
335
|
+
unsafeCreateRetryableTicket(
|
336
|
+
to,
|
337
|
+
l2CallValue,
|
338
|
+
maxSubmissionCost,
|
339
|
+
excessFeeRefundAddress,
|
340
|
+
callValueRefundAddress,
|
341
|
+
gasLimit,
|
342
|
+
maxFeePerGas,
|
343
|
+
data
|
344
|
+
);
|
345
|
+
}
|
346
|
+
|
347
|
+
/**
|
348
|
+
* @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
|
349
|
+
* @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds
|
350
|
+
* come from the deposit alone, rather than falling back on the user's L2 balance
|
351
|
+
* @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).
|
352
|
+
* createRetryableTicket method is the recommended standard.
|
353
|
+
* @param to destination L2 contract address
|
354
|
+
* @param l2CallValue call value for retryable L2 message
|
355
|
+
* @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
|
356
|
+
* @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
|
357
|
+
* @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
|
358
|
+
* @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution
|
359
|
+
* @param maxFeePerGas price bid for L2 execution
|
360
|
+
* @param data ABI encoded data of L2 message
|
361
|
+
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
362
|
+
*/
|
363
|
+
function unsafeCreateRetryableTicket(
|
364
|
+
address to,
|
365
|
+
uint256 l2CallValue,
|
366
|
+
uint256 maxSubmissionCost,
|
367
|
+
address excessFeeRefundAddress,
|
368
|
+
address callValueRefundAddress,
|
369
|
+
uint256 gasLimit,
|
370
|
+
uint256 maxFeePerGas,
|
371
|
+
bytes calldata data
|
372
|
+
) public payable virtual override whenNotPaused returns (uint256) {
|
373
|
+
uint256 submissionFee = calculateRetryableSubmissionFee(data.length, block.basefee);
|
374
|
+
require(maxSubmissionCost >= submissionFee, "insufficient submission fee");
|
375
|
+
|
376
|
+
return
|
377
|
+
_deliverMessage(
|
378
|
+
L1MessageType_submitRetryableTx,
|
379
|
+
msg.sender,
|
380
|
+
abi.encodePacked(
|
381
|
+
uint256(uint160(to)),
|
382
|
+
l2CallValue,
|
383
|
+
msg.value,
|
384
|
+
maxSubmissionCost,
|
385
|
+
uint256(uint160(excessFeeRefundAddress)),
|
386
|
+
uint256(uint160(callValueRefundAddress)),
|
387
|
+
gasLimit,
|
388
|
+
maxFeePerGas,
|
389
|
+
data.length,
|
390
|
+
data
|
391
|
+
)
|
392
|
+
);
|
393
|
+
}
|
394
|
+
|
395
|
+
function _deliverMessage(
|
396
|
+
uint8 _kind,
|
397
|
+
address _sender,
|
398
|
+
bytes memory _messageData
|
399
|
+
) internal returns (uint256) {
|
400
|
+
if (_messageData.length > MAX_DATA_SIZE)
|
401
|
+
revert DataTooLarge(_messageData.length, MAX_DATA_SIZE);
|
402
|
+
uint256 msgNum = deliverToBridge(_kind, _sender, keccak256(_messageData));
|
403
|
+
emit InboxMessageDelivered(msgNum, _messageData);
|
404
|
+
return msgNum;
|
405
|
+
}
|
406
|
+
|
407
|
+
function deliverToBridge(
|
408
|
+
uint8 kind,
|
409
|
+
address sender,
|
410
|
+
bytes32 messageDataHash
|
411
|
+
) internal returns (uint256) {
|
412
|
+
return bridge.enqueueDelayedMessage{value: msg.value}(kind, sender, messageDataHash);
|
413
|
+
}
|
414
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
// Copyright 2021-2022, Offchain Labs, Inc.
|
2
|
+
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
|
+
// SPDX-License-Identifier: BUSL-1.1
|
4
|
+
|
5
|
+
pragma solidity ^0.8.0;
|
6
|
+
|
7
|
+
library Messages {
|
8
|
+
function messageHash(
|
9
|
+
uint8 kind,
|
10
|
+
address sender,
|
11
|
+
uint64 blockNumber,
|
12
|
+
uint64 timestamp,
|
13
|
+
uint256 inboxSeqNum,
|
14
|
+
uint256 baseFeeL1,
|
15
|
+
bytes32 messageDataHash
|
16
|
+
) internal pure returns (bytes32) {
|
17
|
+
return
|
18
|
+
keccak256(
|
19
|
+
abi.encodePacked(
|
20
|
+
kind,
|
21
|
+
sender,
|
22
|
+
blockNumber,
|
23
|
+
timestamp,
|
24
|
+
inboxSeqNum,
|
25
|
+
baseFeeL1,
|
26
|
+
messageDataHash
|
27
|
+
)
|
28
|
+
);
|
29
|
+
}
|
30
|
+
|
31
|
+
function accumulateInboxMessage(bytes32 prevAcc, bytes32 message)
|
32
|
+
internal
|
33
|
+
pure
|
34
|
+
returns (bytes32)
|
35
|
+
{
|
36
|
+
return keccak256(abi.encodePacked(prevAcc, message));
|
37
|
+
}
|
38
|
+
}
|