@arbitrum/nitro-contracts 1.0.0-beta.7 → 1.0.0-beta.8
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +5 -2
- package/src/bridge/Bridge.sol +11 -0
- package/src/bridge/IBridge.sol +4 -18
- package/src/bridge/IDelayedMessageProvider.sol +2 -1
- package/src/bridge/IInbox.sol +4 -36
- package/src/bridge/IOutbox.sol +43 -23
- package/src/bridge/IOwnable.sol +2 -1
- package/src/bridge/ISequencerInbox.sol +3 -32
- package/src/bridge/Inbox.sol +20 -19
- package/src/bridge/Outbox.sol +14 -5
- package/src/bridge/SequencerInbox.sol +21 -1
- package/src/libraries/Error.sol +107 -0
- package/src/libraries/IGasRefunder.sol +2 -1
- package/src/mocks/BridgeStub.sol +2 -0
- package/src/mocks/InboxStub.sol +2 -0
- package/src/node-interface/NodeInterface.sol +35 -4
- package/src/precompiles/ArbGasInfo.sol +9 -0
- package/src/precompiles/ArbOwner.sol +9 -0
- package/src/precompiles/ArbSys.sol +3 -3
- package/src/rollup/RollupAdminLogic.sol +42 -0
- package/src/rollup/RollupCore.sol +5 -2
- package/src/rollup/RollupLib.sol +1 -0
- package/src/state/GlobalState.sol +7 -0
- package/src/test-helpers/BridgeTester.sol +10 -0
- package/src/test-helpers/InterfaceCompatibilityTester.sol +11 -0
- package/src/test-helpers/OutboxWithoutOptTester.sol +29 -3
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@arbitrum/nitro-contracts",
|
3
|
-
"version": "1.0.0-beta.
|
3
|
+
"version": "1.0.0-beta.8",
|
4
4
|
"description": "Layer 2 precompiles and rollup for Arbitrum Nitro",
|
5
5
|
"author": "Offchain Labs, Inc.",
|
6
6
|
"license": "BUSL-1.1",
|
@@ -21,7 +21,10 @@
|
|
21
21
|
"build": "./scripts/build.bash",
|
22
22
|
"solhint": "solhint -f table src/**/*.sol",
|
23
23
|
"prettier:solidity": "prettier --write src/**/*.sol",
|
24
|
-
"hardhat:prod": "hardhat --config hardhat.prod-config.js"
|
24
|
+
"hardhat:prod": "hardhat --config hardhat.prod-config.js",
|
25
|
+
"build:0.6": "INTERFACE_TESTER_SOLC_VERSION=0.6.9 yarn run build",
|
26
|
+
"build:0.7": "INTERFACE_TESTER_SOLC_VERSION=0.7.0 yarn run build",
|
27
|
+
"test:compatibility": "yarn run build:0.6 && yarn run build:0.7"
|
25
28
|
},
|
26
29
|
"dependencies": {
|
27
30
|
"@openzeppelin/contracts": "4.5.0",
|
package/src/bridge/Bridge.sol
CHANGED
@@ -7,6 +7,14 @@ pragma solidity ^0.8.4;
|
|
7
7
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
8
8
|
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
|
9
9
|
|
10
|
+
import {
|
11
|
+
NotContract,
|
12
|
+
NotRollupOrOwner,
|
13
|
+
NotDelayedInbox,
|
14
|
+
NotSequencerInbox,
|
15
|
+
NotOutbox,
|
16
|
+
InvalidOutboxSet
|
17
|
+
} from "../libraries/Error.sol";
|
10
18
|
import "./IBridge.sol";
|
11
19
|
import "./Messages.sol";
|
12
20
|
import "../libraries/DelegateCallAware.sol";
|
@@ -260,4 +268,7 @@ contract Bridge is Initializable, DelegateCallAware, IBridge {
|
|
260
268
|
function sequencerMessageCount() external view override returns (uint256) {
|
261
269
|
return sequencerInboxAccs.length;
|
262
270
|
}
|
271
|
+
|
272
|
+
/// @dev For the classic -> nitro migration. TODO: remove post-migration.
|
273
|
+
function acceptFundsFromOldBridge() external payable {}
|
263
274
|
}
|
package/src/bridge/IBridge.sol
CHANGED
@@ -2,27 +2,11 @@
|
|
2
2
|
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
3
|
// SPDX-License-Identifier: BUSL-1.1
|
4
4
|
|
5
|
-
|
5
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
6
7
|
|
7
|
-
import {NotContract, NotRollupOrOwner} from "../libraries/Error.sol";
|
8
8
|
import "./IOwnable.sol";
|
9
9
|
|
10
|
-
/// @dev Thrown when an un-authorized address tries to access an only-inbox function
|
11
|
-
/// @param sender The un-authorized sender
|
12
|
-
error NotDelayedInbox(address sender);
|
13
|
-
|
14
|
-
/// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
|
15
|
-
/// @param sender The un-authorized sender
|
16
|
-
error NotSequencerInbox(address sender);
|
17
|
-
|
18
|
-
/// @dev Thrown when an un-authorized address tries to access an only-outbox function
|
19
|
-
/// @param sender The un-authorized sender
|
20
|
-
error NotOutbox(address sender);
|
21
|
-
|
22
|
-
/// @dev the provided outbox address isn't valid
|
23
|
-
/// @param outbox address of outbox being set
|
24
|
-
error InvalidOutboxSet(address outbox);
|
25
|
-
|
26
10
|
interface IBridge {
|
27
11
|
event MessageDelivered(
|
28
12
|
uint256 indexed messageIndex,
|
@@ -99,4 +83,6 @@ interface IBridge {
|
|
99
83
|
function sequencerMessageCount() external view returns (uint256);
|
100
84
|
|
101
85
|
function rollup() external view returns (IOwnable);
|
86
|
+
|
87
|
+
function acceptFundsFromOldBridge() external payable;
|
102
88
|
}
|
@@ -2,7 +2,8 @@
|
|
2
2
|
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
3
|
// SPDX-License-Identifier: BUSL-1.1
|
4
4
|
|
5
|
-
|
5
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
6
7
|
|
7
8
|
interface IDelayedMessageProvider {
|
8
9
|
/// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
|
package/src/bridge/IInbox.sol
CHANGED
@@ -2,44 +2,11 @@
|
|
2
2
|
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
3
|
// SPDX-License-Identifier: BUSL-1.1
|
4
4
|
|
5
|
-
|
5
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
6
7
|
|
7
8
|
import "./IBridge.sol";
|
8
9
|
import "./IDelayedMessageProvider.sol";
|
9
|
-
import {AlreadyInit, NotOrigin, DataTooLarge} from "../libraries/Error.sol";
|
10
|
-
|
11
|
-
/// @dev The contract is paused, so cannot be paused
|
12
|
-
error AlreadyPaused();
|
13
|
-
|
14
|
-
/// @dev The contract is unpaused, so cannot be unpaused
|
15
|
-
error AlreadyUnpaused();
|
16
|
-
|
17
|
-
/// @dev The contract is paused
|
18
|
-
error Paused();
|
19
|
-
|
20
|
-
/// @dev msg.value sent to the inbox isn't high enough
|
21
|
-
error InsufficientValue(uint256 expected, uint256 actual);
|
22
|
-
|
23
|
-
/// @dev submission cost provided isn't enough to create retryable ticket
|
24
|
-
error InsufficientSubmissionCost(uint256 expected, uint256 actual);
|
25
|
-
|
26
|
-
/// @dev address not allowed to interact with the given contract
|
27
|
-
error NotAllowedOrigin(address origin);
|
28
|
-
|
29
|
-
/// @dev used to convey retryable tx data in eth calls without requiring a tx trace
|
30
|
-
/// this follows a pattern similar to EIP-3668 where reverts surface call information
|
31
|
-
error RetryableData(
|
32
|
-
address from,
|
33
|
-
address to,
|
34
|
-
uint256 l2CallValue,
|
35
|
-
uint256 deposit,
|
36
|
-
uint256 maxSubmissionCost,
|
37
|
-
address excessFeeRefundAddress,
|
38
|
-
address callValueRefundAddress,
|
39
|
-
uint256 gasLimit,
|
40
|
-
uint256 maxFeePerGas,
|
41
|
-
bytes data
|
42
|
-
);
|
43
10
|
|
44
11
|
interface IInbox is IDelayedMessageProvider {
|
45
12
|
function sendL2Message(bytes calldata messageData) external returns (uint256);
|
@@ -88,7 +55,6 @@ interface IInbox is IDelayedMessageProvider {
|
|
88
55
|
bytes calldata data
|
89
56
|
) external payable returns (uint256);
|
90
57
|
|
91
|
-
/// @notice TEMPORARILY DISABLED as exact mechanics are being worked out
|
92
58
|
/// @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
|
93
59
|
function unsafeCreateRetryableTicket(
|
94
60
|
address to,
|
@@ -107,4 +73,6 @@ interface IInbox is IDelayedMessageProvider {
|
|
107
73
|
function depositEth(uint256 maxSubmissionCost) external payable returns (uint256);
|
108
74
|
|
109
75
|
function bridge() external view returns (IBridge);
|
76
|
+
|
77
|
+
function postUpgradeInit(IBridge _bridge) external;
|
110
78
|
}
|
package/src/bridge/IOutbox.sol
CHANGED
@@ -2,29 +2,8 @@
|
|
2
2
|
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
3
|
// SPDX-License-Identifier: BUSL-1.1
|
4
4
|
|
5
|
-
|
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();
|
5
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
28
7
|
|
29
8
|
interface IOutbox {
|
30
9
|
event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot);
|
@@ -49,4 +28,45 @@ interface IOutbox {
|
|
49
28
|
function l2ToL1OutputId() external view returns (bytes32);
|
50
29
|
|
51
30
|
function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;
|
31
|
+
|
32
|
+
function executeTransaction(
|
33
|
+
bytes32[] calldata proof,
|
34
|
+
uint256 index,
|
35
|
+
address l2Sender,
|
36
|
+
address to,
|
37
|
+
uint256 l2Block,
|
38
|
+
uint256 l1Block,
|
39
|
+
uint256 l2Timestamp,
|
40
|
+
uint256 value,
|
41
|
+
bytes calldata data
|
42
|
+
) external;
|
43
|
+
|
44
|
+
function executeTransactionSimulation(
|
45
|
+
uint256 index,
|
46
|
+
address l2Sender,
|
47
|
+
address to,
|
48
|
+
uint256 l2Block,
|
49
|
+
uint256 l1Block,
|
50
|
+
uint256 l2Timestamp,
|
51
|
+
uint256 value,
|
52
|
+
bytes calldata data
|
53
|
+
) external;
|
54
|
+
|
55
|
+
function isSpent(uint256) external view returns (bool);
|
56
|
+
|
57
|
+
function calculateItemHash(
|
58
|
+
address l2Sender,
|
59
|
+
address to,
|
60
|
+
uint256 l2Block,
|
61
|
+
uint256 l1Block,
|
62
|
+
uint256 l2Timestamp,
|
63
|
+
uint256 value,
|
64
|
+
bytes calldata data
|
65
|
+
) external pure returns (bytes32);
|
66
|
+
|
67
|
+
function calculateMerkleRoot(
|
68
|
+
bytes32[] memory proof,
|
69
|
+
uint256 path,
|
70
|
+
bytes32 item
|
71
|
+
) external pure returns (bytes32);
|
52
72
|
}
|
package/src/bridge/IOwnable.sol
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
3
|
// SPDX-License-Identifier: BUSL-1.1
|
4
4
|
|
5
|
-
|
5
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.4.21 <0.9.0;
|
6
7
|
|
7
8
|
interface IOwnable {
|
8
9
|
function owner() external view returns (address);
|
@@ -2,10 +2,11 @@
|
|
2
2
|
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
3
|
// SPDX-License-Identifier: BUSL-1.1
|
4
4
|
|
5
|
-
|
5
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
7
|
+
pragma experimental ABIEncoderV2;
|
6
8
|
|
7
9
|
import "../libraries/IGasRefunder.sol";
|
8
|
-
import {AlreadyInit, HadZeroInit, NotOrigin, DataTooLarge, NotRollup} from "../libraries/Error.sol";
|
9
10
|
import "./IDelayedMessageProvider.sol";
|
10
11
|
|
11
12
|
interface ISequencerInbox is IDelayedMessageProvider {
|
@@ -50,36 +51,6 @@ interface ISequencerInbox is IDelayedMessageProvider {
|
|
50
51
|
/// @dev a keyset was invalidated
|
51
52
|
event InvalidateKeyset(bytes32 indexed keysetHash);
|
52
53
|
|
53
|
-
/// @dev Thrown when someone attempts to read fewer messages than have already been read
|
54
|
-
error DelayedBackwards();
|
55
|
-
|
56
|
-
/// @dev Thrown when someone attempts to read more messages than exist
|
57
|
-
error DelayedTooFar();
|
58
|
-
|
59
|
-
/// @dev Force include can only read messages more blocks old than the delay period
|
60
|
-
error ForceIncludeBlockTooSoon();
|
61
|
-
|
62
|
-
/// @dev Force include can only read messages more seconds old than the delay period
|
63
|
-
error ForceIncludeTimeTooSoon();
|
64
|
-
|
65
|
-
/// @dev The message provided did not match the hash in the delayed inbox
|
66
|
-
error IncorrectMessagePreimage();
|
67
|
-
|
68
|
-
/// @dev This can only be called by the batch poster
|
69
|
-
error NotBatchPoster();
|
70
|
-
|
71
|
-
/// @dev The sequence number provided to this message was inconsistent with the number of batches already included
|
72
|
-
error BadSequencerNumber(uint256 stored, uint256 received);
|
73
|
-
|
74
|
-
/// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
|
75
|
-
error DataNotAuthenticated();
|
76
|
-
|
77
|
-
/// @dev Tried to create an already valid Data Availability Service keyset
|
78
|
-
error AlreadyValidDASKeyset(bytes32);
|
79
|
-
|
80
|
-
/// @dev Tried to use or invalidate an already invalid Data Availability Service keyset
|
81
|
-
error NoSuchKeyset(bytes32);
|
82
|
-
|
83
54
|
function inboxAccs(uint256 index) external view returns (bytes32);
|
84
55
|
|
85
56
|
function batchCount() external view returns (uint256);
|
package/src/bridge/Inbox.sol
CHANGED
@@ -4,6 +4,19 @@
|
|
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
|
+
} from "../libraries/Error.sol";
|
7
20
|
import "./IInbox.sol";
|
8
21
|
import "./ISequencerInbox.sol";
|
9
22
|
import "./IBridge.sol";
|
@@ -244,14 +257,15 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
244
257
|
* @dev This fee can be paid by funds already in the L2 aliased address or by the current message value
|
245
258
|
* @dev This formula may change in the future, to future proof your code query this method instead of inlining!!
|
246
259
|
* @param dataLength The length of the retryable's calldata, in bytes
|
247
|
-
* @param baseFee The block basefee when the retryable is included in the chain
|
260
|
+
* @param baseFee The block basefee when the retryable is included in the chain, if 0 current block.basefee will be used
|
248
261
|
*/
|
249
262
|
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
|
250
263
|
public
|
251
|
-
|
264
|
+
view
|
252
265
|
returns (uint256)
|
253
266
|
{
|
254
|
-
|
267
|
+
// Use current block basefee if baseFee parameter is 0
|
268
|
+
return (1400 + 6 * dataLength) * (baseFee == 0 ? block.basefee : baseFee);
|
255
269
|
}
|
256
270
|
|
257
271
|
/// @notice deposit eth from L1 to L2
|
@@ -373,7 +387,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
373
387
|
}
|
374
388
|
|
375
389
|
return
|
376
|
-
|
390
|
+
unsafeCreateRetryableTicket(
|
377
391
|
to,
|
378
392
|
l2CallValue,
|
379
393
|
maxSubmissionCost,
|
@@ -402,7 +416,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
402
416
|
* @param data ABI encoded data of L2 message
|
403
417
|
* @return unique id for retryable transaction (keccak256(requestID, uint(0) )
|
404
418
|
*/
|
405
|
-
function
|
419
|
+
function unsafeCreateRetryableTicket(
|
406
420
|
address to,
|
407
421
|
uint256 l2CallValue,
|
408
422
|
uint256 maxSubmissionCost,
|
@@ -411,7 +425,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
411
425
|
uint256 gasLimit,
|
412
426
|
uint256 maxFeePerGas,
|
413
427
|
bytes calldata data
|
414
|
-
)
|
428
|
+
) public payable virtual override whenNotPaused onlyAllowed returns (uint256) {
|
415
429
|
// gas price and limit of 1 should never be a valid input, so instead they are used as
|
416
430
|
// magic values to trigger a revert in eth calls that surface data without requiring a tx trace
|
417
431
|
if (gasLimit == 1 || maxFeePerGas == 1)
|
@@ -451,19 +465,6 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
451
465
|
);
|
452
466
|
}
|
453
467
|
|
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
468
|
function _deliverMessage(
|
468
469
|
uint8 _kind,
|
469
470
|
address _sender,
|
package/src/bridge/Outbox.sol
CHANGED
@@ -4,6 +4,15 @@
|
|
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
|
+
} from "../libraries/Error.sol";
|
7
16
|
import "./IBridge.sol";
|
8
17
|
import "./IOutbox.sol";
|
9
18
|
import "../libraries/MerkleLib.sol";
|
@@ -138,7 +147,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
138
147
|
uint256 l2Timestamp,
|
139
148
|
uint256 value,
|
140
149
|
bytes calldata data
|
141
|
-
) external {
|
150
|
+
) external override {
|
142
151
|
bytes32 userTx = calculateItemHash(
|
143
152
|
l2Sender,
|
144
153
|
to,
|
@@ -172,7 +181,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
172
181
|
uint256 l2Timestamp,
|
173
182
|
uint256 value,
|
174
183
|
bytes calldata data
|
175
|
-
) external {
|
184
|
+
) external override {
|
176
185
|
if (msg.sender != address(0)) revert SimulationOnlyEntrypoint();
|
177
186
|
executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
|
178
187
|
}
|
@@ -226,7 +235,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
226
235
|
return ((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0);
|
227
236
|
}
|
228
237
|
|
229
|
-
function isSpent(uint256 index) external view returns (bool) {
|
238
|
+
function isSpent(uint256 index) external view override returns (bool) {
|
230
239
|
(, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
|
231
240
|
return _isSpent(bitOffset, replay);
|
232
241
|
}
|
@@ -276,7 +285,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
276
285
|
uint256 l2Timestamp,
|
277
286
|
uint256 value,
|
278
287
|
bytes calldata data
|
279
|
-
) public pure returns (bytes32) {
|
288
|
+
) public pure override returns (bytes32) {
|
280
289
|
return
|
281
290
|
keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
|
282
291
|
}
|
@@ -285,7 +294,7 @@ contract Outbox is DelegateCallAware, IOutbox {
|
|
285
294
|
bytes32[] memory proof,
|
286
295
|
uint256 path,
|
287
296
|
bytes32 item
|
288
|
-
) public pure returns (bytes32) {
|
297
|
+
) public pure override returns (bytes32) {
|
289
298
|
return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
|
290
299
|
}
|
291
300
|
}
|
@@ -4,6 +4,23 @@
|
|
4
4
|
|
5
5
|
pragma solidity ^0.8.0;
|
6
6
|
|
7
|
+
import {
|
8
|
+
AlreadyInit,
|
9
|
+
HadZeroInit,
|
10
|
+
NotOrigin,
|
11
|
+
DataTooLarge,
|
12
|
+
NotRollup,
|
13
|
+
DelayedBackwards,
|
14
|
+
DelayedTooFar,
|
15
|
+
ForceIncludeBlockTooSoon,
|
16
|
+
ForceIncludeTimeTooSoon,
|
17
|
+
IncorrectMessagePreimage,
|
18
|
+
NotBatchPoster,
|
19
|
+
BadSequencerNumber,
|
20
|
+
DataNotAuthenticated,
|
21
|
+
AlreadyValidDASKeyset,
|
22
|
+
NoSuchKeyset
|
23
|
+
} from "../libraries/Error.sol";
|
7
24
|
import "./IBridge.sol";
|
8
25
|
import "./IInbox.sol";
|
9
26
|
import "./ISequencerInbox.sol";
|
@@ -336,7 +353,10 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
|
|
336
353
|
* @param keysetBytes bytes of the serialized keyset
|
337
354
|
*/
|
338
355
|
function setValidKeyset(bytes calldata keysetBytes) external override onlyRollupOwner {
|
339
|
-
|
356
|
+
uint256 ksWord = uint256(keccak256(bytes.concat(hex"fe", keccak256(keysetBytes))));
|
357
|
+
bytes32 ksHash = bytes32(ksWord ^ (1 << 255));
|
358
|
+
require(keysetBytes.length < 64 * 1024, "keyset is too large");
|
359
|
+
|
340
360
|
if (dasKeySetInfo[ksHash].isValidKeyset) revert AlreadyValidDASKeyset(ksHash);
|
341
361
|
dasKeySetInfo[ksHash] = DasKeySetInfo({
|
342
362
|
isValidKeyset: true,
|
package/src/libraries/Error.sol
CHANGED
@@ -42,3 +42,110 @@ error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
|
|
42
42
|
/// @param rollup The rollup, which would be authorized
|
43
43
|
/// @param owner The rollup's owner, which would be authorized
|
44
44
|
error NotRollupOrOwner(address sender, address rollup, address owner);
|
45
|
+
|
46
|
+
// Bridge Errors
|
47
|
+
|
48
|
+
/// @dev Thrown when an un-authorized address tries to access an only-inbox function
|
49
|
+
/// @param sender The un-authorized sender
|
50
|
+
error NotDelayedInbox(address sender);
|
51
|
+
|
52
|
+
/// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
|
53
|
+
/// @param sender The un-authorized sender
|
54
|
+
error NotSequencerInbox(address sender);
|
55
|
+
|
56
|
+
/// @dev Thrown when an un-authorized address tries to access an only-outbox function
|
57
|
+
/// @param sender The un-authorized sender
|
58
|
+
error NotOutbox(address sender);
|
59
|
+
|
60
|
+
/// @dev the provided outbox address isn't valid
|
61
|
+
/// @param outbox address of outbox being set
|
62
|
+
error InvalidOutboxSet(address outbox);
|
63
|
+
|
64
|
+
// Inbox Errors
|
65
|
+
|
66
|
+
/// @dev The contract is paused, so cannot be paused
|
67
|
+
error AlreadyPaused();
|
68
|
+
|
69
|
+
/// @dev The contract is unpaused, so cannot be unpaused
|
70
|
+
error AlreadyUnpaused();
|
71
|
+
|
72
|
+
/// @dev The contract is paused
|
73
|
+
error Paused();
|
74
|
+
|
75
|
+
/// @dev msg.value sent to the inbox isn't high enough
|
76
|
+
error InsufficientValue(uint256 expected, uint256 actual);
|
77
|
+
|
78
|
+
/// @dev submission cost provided isn't enough to create retryable ticket
|
79
|
+
error InsufficientSubmissionCost(uint256 expected, uint256 actual);
|
80
|
+
|
81
|
+
/// @dev address not allowed to interact with the given contract
|
82
|
+
error NotAllowedOrigin(address origin);
|
83
|
+
|
84
|
+
/// @dev used to convey retryable tx data in eth calls without requiring a tx trace
|
85
|
+
/// this follows a pattern similar to EIP-3668 where reverts surface call information
|
86
|
+
error RetryableData(
|
87
|
+
address from,
|
88
|
+
address to,
|
89
|
+
uint256 l2CallValue,
|
90
|
+
uint256 deposit,
|
91
|
+
uint256 maxSubmissionCost,
|
92
|
+
address excessFeeRefundAddress,
|
93
|
+
address callValueRefundAddress,
|
94
|
+
uint256 gasLimit,
|
95
|
+
uint256 maxFeePerGas,
|
96
|
+
bytes data
|
97
|
+
);
|
98
|
+
|
99
|
+
// Outbox Errors
|
100
|
+
|
101
|
+
/// @dev The provided proof was too long
|
102
|
+
/// @param proofLength The length of the too-long proof
|
103
|
+
error ProofTooLong(uint256 proofLength);
|
104
|
+
|
105
|
+
/// @dev The output index was greater than the maximum
|
106
|
+
/// @param index The output index
|
107
|
+
/// @param maxIndex The max the index could be
|
108
|
+
error PathNotMinimal(uint256 index, uint256 maxIndex);
|
109
|
+
|
110
|
+
/// @dev The calculated root does not exist
|
111
|
+
/// @param root The calculated root
|
112
|
+
error UnknownRoot(bytes32 root);
|
113
|
+
|
114
|
+
/// @dev The record has already been spent
|
115
|
+
/// @param index The index of the spent record
|
116
|
+
error AlreadySpent(uint256 index);
|
117
|
+
|
118
|
+
/// @dev A call to the bridge failed with no return data
|
119
|
+
error BridgeCallFailed();
|
120
|
+
|
121
|
+
// Sequencer Inbox Errors
|
122
|
+
|
123
|
+
/// @dev Thrown when someone attempts to read fewer messages than have already been read
|
124
|
+
error DelayedBackwards();
|
125
|
+
|
126
|
+
/// @dev Thrown when someone attempts to read more messages than exist
|
127
|
+
error DelayedTooFar();
|
128
|
+
|
129
|
+
/// @dev Force include can only read messages more blocks old than the delay period
|
130
|
+
error ForceIncludeBlockTooSoon();
|
131
|
+
|
132
|
+
/// @dev Force include can only read messages more seconds old than the delay period
|
133
|
+
error ForceIncludeTimeTooSoon();
|
134
|
+
|
135
|
+
/// @dev The message provided did not match the hash in the delayed inbox
|
136
|
+
error IncorrectMessagePreimage();
|
137
|
+
|
138
|
+
/// @dev This can only be called by the batch poster
|
139
|
+
error NotBatchPoster();
|
140
|
+
|
141
|
+
/// @dev The sequence number provided to this message was inconsistent with the number of batches already included
|
142
|
+
error BadSequencerNumber(uint256 stored, uint256 received);
|
143
|
+
|
144
|
+
/// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
|
145
|
+
error DataNotAuthenticated();
|
146
|
+
|
147
|
+
/// @dev Tried to create an already valid Data Availability Service keyset
|
148
|
+
error AlreadyValidDASKeyset(bytes32);
|
149
|
+
|
150
|
+
/// @dev Tried to use or invalidate an already invalid Data Availability Service keyset
|
151
|
+
error NoSuchKeyset(bytes32);
|
@@ -2,7 +2,8 @@
|
|
2
2
|
// For license information, see https://github.com/nitro/blob/master/LICENSE
|
3
3
|
// SPDX-License-Identifier: BUSL-1.1
|
4
4
|
|
5
|
-
|
5
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
6
7
|
|
7
8
|
interface IGasRefunder {
|
8
9
|
function onGasSpent(
|
package/src/mocks/BridgeStub.sol
CHANGED
package/src/mocks/InboxStub.sol
CHANGED
@@ -12,7 +12,7 @@ pragma solidity >=0.4.21 <0.9.0;
|
|
12
12
|
interface NodeInterface {
|
13
13
|
/**
|
14
14
|
* @notice Estimate the cost of putting a message in the L2 inbox that is reexecuted.
|
15
|
-
* Use eth_estimateGas to call.
|
15
|
+
* @dev Use eth_estimateGas to call.
|
16
16
|
* @param sender sender of the L1 and L2 transaction
|
17
17
|
* @param deposit amount to deposit to sender in L2
|
18
18
|
* @param to destination L2 contract address
|
@@ -33,7 +33,7 @@ interface NodeInterface {
|
|
33
33
|
|
34
34
|
/**
|
35
35
|
* @notice Constructs an outbox proof of an l2->l1 send's existence in the outbox accumulator.
|
36
|
-
* Use eth_call to call.
|
36
|
+
* @dev Use eth_call to call.
|
37
37
|
* @param size the number of elements in the accumulator
|
38
38
|
* @param leaf the position of the send in the accumulator
|
39
39
|
* @return send the l2->l1 send's hash
|
@@ -62,14 +62,16 @@ interface NodeInterface {
|
|
62
62
|
* @notice Gets the number of L1 confirmations of the sequencer batch producing the requested L2 block
|
63
63
|
* This gets the number of L1 confirmations for the input message producing the L2 block,
|
64
64
|
* which happens well before the L1 rollup contract confirms the L2 block.
|
65
|
-
* Throws if block doesnt exist in the L2 chain.
|
65
|
+
* Throws if block doesnt exist in the L2 chain.
|
66
|
+
* @dev Use eth_call to call.
|
66
67
|
* @param blockHash The hash of the L2 block being queried
|
67
68
|
* @return confirmations The number of L1 confirmations the sequencer batch has. Returns 0 if block not yet included in an L1 batch.
|
68
69
|
*/
|
69
70
|
function getL1Confirmations(bytes32 blockHash) external view returns (uint64 confirmations);
|
70
71
|
|
71
72
|
/**
|
72
|
-
* @notice Same as native gas estimation, but with additional info on the l1 costs.
|
73
|
+
* @notice Same as native gas estimation, but with additional info on the l1 costs.
|
74
|
+
* @dev Use eth_call to call.
|
73
75
|
* @param data the tx's calldata. Everything else like "From" and "Gas" are copied over
|
74
76
|
* @param to the tx's "To" (ignored when contractCreation is true)
|
75
77
|
* @param contractCreation whether "To" is omitted
|
@@ -91,4 +93,33 @@ interface NodeInterface {
|
|
91
93
|
uint256 baseFee,
|
92
94
|
uint256 l1BaseFeeEstimate
|
93
95
|
);
|
96
|
+
|
97
|
+
/**
|
98
|
+
* @notice Returns the proof necessary to redeem a message
|
99
|
+
* @param batchNum index of outbox entry (i.e., outgoing messages Merkle root) in array of outbox entries
|
100
|
+
* @param index index of outgoing message in outbox entry
|
101
|
+
* @return proof Merkle proof of message inclusion in outbox entry
|
102
|
+
* @return path Merkle path to message
|
103
|
+
* @return l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
|
104
|
+
* @return l1Dest destination address for L1 contract call
|
105
|
+
* @return l2Block l2 block number at which sendTxToL1 call was made
|
106
|
+
* @return l1Block l1 block number at which sendTxToL1 call was made
|
107
|
+
* @return timestamp l2 Timestamp at which sendTxToL1 call was made
|
108
|
+
* @return amount value in L1 message in wei
|
109
|
+
* @return calldataForL1 abi-encoded L1 message data
|
110
|
+
*/
|
111
|
+
function legacyLookupMessageBatchProof(uint256 batchNum, uint64 index)
|
112
|
+
external
|
113
|
+
view
|
114
|
+
returns (
|
115
|
+
bytes32[] memory proof,
|
116
|
+
uint256 path,
|
117
|
+
address l2Sender,
|
118
|
+
address l1Dest,
|
119
|
+
uint256 l2Block,
|
120
|
+
uint256 l1Block,
|
121
|
+
uint256 timestamp,
|
122
|
+
uint256 amount,
|
123
|
+
bytes memory calldataForL1
|
124
|
+
);
|
94
125
|
}
|
@@ -109,4 +109,13 @@ interface ArbGasInfo {
|
|
109
109
|
|
110
110
|
/// @notice Get the forgivable amount of backlogged gas ArbOS will ignore when raising the basefee
|
111
111
|
function getGasBacklogTolerance() external view returns (uint64);
|
112
|
+
|
113
|
+
/// @notice Returns the surplus of funds for L1 batch posting payments (may be negative).
|
114
|
+
function getL1PricingSurplus() external view returns (int256);
|
115
|
+
|
116
|
+
/// @notice Returns the base charge (in L1 gas) attributed to each data batch in the calldata pricer
|
117
|
+
function getPerBatchGasCharge() external view returns (int64);
|
118
|
+
|
119
|
+
/// @notice Returns the cost amortization cap in basis points
|
120
|
+
function getAmortizedCostCapBips() external view returns (uint64);
|
112
121
|
}
|
@@ -66,6 +66,15 @@ interface ArbOwner {
|
|
66
66
|
/// @notice Sets reward amount for L1 price adjustment algorithm, in wei per unit
|
67
67
|
function setL1PricingRewardRate(uint64 weiPerUnit) external;
|
68
68
|
|
69
|
+
/// @notice Set how much ArbOS charges per L1 gas spent on transaction data.
|
70
|
+
function setL1PricePerUnit(uint256 pricePerUnit) external;
|
71
|
+
|
72
|
+
/// @notice Sets the base charge (in L1 gas) attributed to each data batch in the calldata pricer
|
73
|
+
function setPerBatchGasCharge(int64 cost) external;
|
74
|
+
|
75
|
+
/// @notice Sets the cost amortization cap in basis points
|
76
|
+
function setAmortizedCostCapBips(uint64 cap) external;
|
77
|
+
|
69
78
|
// Emitted when a successful call is made to this precompile
|
70
79
|
event OwnerActs(bytes4 indexed method, address indexed owner, bytes data);
|
71
80
|
}
|
@@ -36,13 +36,13 @@ interface ArbSys {
|
|
36
36
|
|
37
37
|
/**
|
38
38
|
* @notice Returns 0 since Nitro has no concept of storage gas
|
39
|
-
* @return
|
39
|
+
* @return uint 0
|
40
40
|
*/
|
41
41
|
function getStorageGasAvailable() external view returns (uint256);
|
42
42
|
|
43
43
|
/**
|
44
|
-
* @notice check if current call is
|
45
|
-
* @return true if
|
44
|
+
* @notice check if current call is top level (meaning it was triggered by an EoA or a L1 contract)
|
45
|
+
* @return true if current execution frame is not a call by another L2 contract
|
46
46
|
*/
|
47
47
|
function isTopLevelCall() external view returns (bool);
|
48
48
|
|
@@ -315,4 +315,46 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
315
315
|
bridge.setSequencerInbox(_sequencerInbox);
|
316
316
|
emit OwnerFunctionCalled(27);
|
317
317
|
}
|
318
|
+
|
319
|
+
/**
|
320
|
+
* @notice sets the rollup's inbox reference. Does not update the bridge's view.
|
321
|
+
* @param newInbox new address of inbox
|
322
|
+
*/
|
323
|
+
function setInbox(IInbox newInbox) external {
|
324
|
+
inbox = newInbox;
|
325
|
+
emit OwnerFunctionCalled(28);
|
326
|
+
}
|
327
|
+
|
328
|
+
function createNitroMigrationGenesis(RollupLib.Assertion calldata assertion)
|
329
|
+
external
|
330
|
+
whenPaused
|
331
|
+
{
|
332
|
+
bytes32 expectedSendRoot = bytes32(0);
|
333
|
+
uint64 expectedInboxCount = 1;
|
334
|
+
|
335
|
+
require(latestNodeCreated() == 0, "NON_GENESIS_NODES_EXIST");
|
336
|
+
require(GlobalStateLib.isEmpty(assertion.beforeState.globalState), "NOT_EMPTY_BEFORE");
|
337
|
+
require(
|
338
|
+
assertion.beforeState.machineStatus == MachineStatus.FINISHED,
|
339
|
+
"BEFORE_MACHINE_NOT_FINISHED"
|
340
|
+
);
|
341
|
+
// accessors such as state.getSendRoot not available for calldata structs, only memory
|
342
|
+
require(
|
343
|
+
assertion.afterState.globalState.bytes32Vals[1] == expectedSendRoot,
|
344
|
+
"NOT_ZERO_SENDROOT"
|
345
|
+
);
|
346
|
+
require(
|
347
|
+
assertion.afterState.globalState.u64Vals[0] == expectedInboxCount,
|
348
|
+
"INBOX_NOT_AT_ONE"
|
349
|
+
);
|
350
|
+
require(assertion.afterState.globalState.u64Vals[1] == 0, "POSITION_IN_MESSAGE_NOT_ZERO");
|
351
|
+
require(
|
352
|
+
assertion.afterState.machineStatus == MachineStatus.FINISHED,
|
353
|
+
"AFTER_MACHINE_NOT_FINISHED"
|
354
|
+
);
|
355
|
+
bytes32 genesisBlockHash = assertion.afterState.globalState.bytes32Vals[0];
|
356
|
+
createNewNode(assertion, 0, expectedInboxCount, bytes32(0));
|
357
|
+
confirmNode(1, genesisBlockHash, expectedSendRoot);
|
358
|
+
emit OwnerFunctionCalled(29);
|
359
|
+
}
|
318
360
|
}
|
@@ -552,7 +552,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
552
552
|
if (afterInboxCount == prevInboxPosition) {
|
553
553
|
require(
|
554
554
|
assertion.afterState.globalState.getPositionInMessage() >=
|
555
|
-
assertion.
|
555
|
+
assertion.beforeState.globalState.getPositionInMessage(),
|
556
556
|
"INBOX_POS_IN_MSG_BACKWARDS"
|
557
557
|
);
|
558
558
|
}
|
@@ -592,7 +592,10 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
592
592
|
memoryFrame.sequencerBatchAcc,
|
593
593
|
wasmModuleRoot
|
594
594
|
);
|
595
|
-
require(
|
595
|
+
require(
|
596
|
+
newNodeHash == expectedNodeHash || expectedNodeHash == bytes32(0),
|
597
|
+
"UNEXPECTED_NODE_HASH"
|
598
|
+
);
|
596
599
|
|
597
600
|
memoryFrame.node = NodeLib.createNode(
|
598
601
|
RollupLib.stateHash(assertion.afterState, memoryFrame.currentInboxSize),
|
package/src/rollup/RollupLib.sol
CHANGED
@@ -41,4 +41,11 @@ library GlobalStateLib {
|
|
41
41
|
function getPositionInMessage(GlobalState memory state) internal pure returns (uint64) {
|
42
42
|
return state.u64Vals[1];
|
43
43
|
}
|
44
|
+
|
45
|
+
function isEmpty(GlobalState calldata state) internal pure returns (bool) {
|
46
|
+
return (state.bytes32Vals[0] == bytes32(0) &&
|
47
|
+
state.bytes32Vals[1] == bytes32(0) &&
|
48
|
+
state.u64Vals[0] == 0 &&
|
49
|
+
state.u64Vals[1] == 0);
|
50
|
+
}
|
44
51
|
}
|
@@ -7,6 +7,14 @@ pragma solidity ^0.8.4;
|
|
7
7
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
8
8
|
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
|
9
9
|
|
10
|
+
import {
|
11
|
+
NotContract,
|
12
|
+
NotRollupOrOwner,
|
13
|
+
NotDelayedInbox,
|
14
|
+
NotSequencerInbox,
|
15
|
+
NotOutbox,
|
16
|
+
InvalidOutboxSet
|
17
|
+
} from "../libraries/Error.sol";
|
10
18
|
import "../bridge/IBridge.sol";
|
11
19
|
import "../bridge/Messages.sol";
|
12
20
|
import "../libraries/DelegateCallAware.sol";
|
@@ -220,4 +228,6 @@ contract BridgeTester is Initializable, DelegateCallAware, IBridge {
|
|
220
228
|
}
|
221
229
|
|
222
230
|
receive() external payable {}
|
231
|
+
|
232
|
+
function acceptFundsFromOldBridge() external payable {}
|
223
233
|
}
|
@@ -0,0 +1,11 @@
|
|
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
|
+
// solhint-disable-next-line compiler-version
|
6
|
+
pragma solidity >=0.6.9 <0.9.0;
|
7
|
+
|
8
|
+
import "../bridge/IBridge.sol";
|
9
|
+
import "../bridge/IOutbox.sol";
|
10
|
+
import "../bridge/IInbox.sol";
|
11
|
+
import "../bridge/ISequencerInbox.sol";
|
@@ -4,6 +4,15 @@
|
|
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
|
+
} from "../libraries/Error.sol";
|
7
16
|
import "../bridge/IBridge.sol";
|
8
17
|
import "../bridge/IOutbox.sol";
|
9
18
|
import "../libraries/MerkleLib.sol";
|
@@ -93,7 +102,7 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
93
102
|
uint256 l2Timestamp,
|
94
103
|
uint256 value,
|
95
104
|
bytes calldata data
|
96
|
-
) external virtual {
|
105
|
+
) external virtual override {
|
97
106
|
bytes32 outputId;
|
98
107
|
{
|
99
108
|
bytes32 userTx = calculateItemHash(
|
@@ -128,6 +137,23 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
128
137
|
context = prevContext;
|
129
138
|
}
|
130
139
|
|
140
|
+
function executeTransactionSimulation(
|
141
|
+
uint256,
|
142
|
+
address,
|
143
|
+
address,
|
144
|
+
uint256,
|
145
|
+
uint256,
|
146
|
+
uint256,
|
147
|
+
uint256,
|
148
|
+
bytes calldata
|
149
|
+
) external pure override {
|
150
|
+
revert("Not implemented");
|
151
|
+
}
|
152
|
+
|
153
|
+
function isSpent(uint256) external pure override returns (bool) {
|
154
|
+
revert("Not implemented");
|
155
|
+
}
|
156
|
+
|
131
157
|
function recordOutputAsSpent(
|
132
158
|
bytes32[] memory proof,
|
133
159
|
uint256 index,
|
@@ -173,7 +199,7 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
173
199
|
uint256 l2Timestamp,
|
174
200
|
uint256 value,
|
175
201
|
bytes calldata data
|
176
|
-
) public pure returns (bytes32) {
|
202
|
+
) public pure override returns (bytes32) {
|
177
203
|
return
|
178
204
|
keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
|
179
205
|
}
|
@@ -182,7 +208,7 @@ contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
|
|
182
208
|
bytes32[] memory proof,
|
183
209
|
uint256 path,
|
184
210
|
bytes32 item
|
185
|
-
) public pure returns (bytes32) {
|
211
|
+
) public pure override returns (bytes32) {
|
186
212
|
return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
|
187
213
|
}
|
188
214
|
}
|