@arbitrum/nitro-contracts 1.0.0-beta.1
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.
- 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
|
+
}
|