@arbitrum/nitro-contracts 1.0.0-beta.5 → 1.0.0-beta.8
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/package.json +6 -2
- package/src/bridge/Bridge.sol +138 -32
- package/src/bridge/IBridge.sol +34 -14
- package/src/bridge/IDelayedMessageProvider.sol +15 -0
- package/src/bridge/IInbox.sol +8 -19
- package/src/bridge/IOutbox.sol +43 -23
- package/src/bridge/IOwnable.sol +10 -0
- package/src/bridge/ISequencerInbox.sol +30 -32
- package/src/bridge/Inbox.sol +133 -35
- package/src/bridge/Outbox.sol +145 -33
- package/src/bridge/SequencerInbox.sol +179 -60
- package/src/challenge/ChallengeLib.sol +0 -2
- package/src/challenge/ChallengeManager.sol +4 -8
- package/src/challenge/IChallengeManager.sol +1 -1
- package/src/libraries/Error.sol +113 -0
- package/src/libraries/IGasRefunder.sol +15 -14
- package/src/libraries/MerkleLib.sol +11 -2
- package/src/libraries/MessageTypes.sol +1 -0
- package/src/mocks/BridgeStub.sol +69 -21
- package/src/mocks/InboxStub.sol +2 -0
- package/src/mocks/SequencerInboxStub.sol +10 -8
- package/src/mocks/Simple.sol +8 -0
- package/src/node-interface/NodeInterface.sol +62 -4
- package/src/osp/IOneStepProver.sol +1 -2
- package/src/osp/OneStepProver0.sol +1 -87
- package/src/osp/OneStepProverHostIo.sol +5 -6
- package/src/osp/OneStepProverMath.sol +37 -27
- package/src/osp/OneStepProverMemory.sol +3 -4
- package/src/precompiles/ArbAggregator.sol +23 -33
- package/src/precompiles/ArbBLS.sol +1 -43
- package/src/precompiles/ArbGasInfo.sol +10 -19
- package/src/precompiles/ArbOwner.sol +21 -15
- package/src/precompiles/ArbRetryableTx.sol +10 -1
- package/src/precompiles/ArbSys.sol +4 -4
- package/src/precompiles/ArbosActs.sol +9 -2
- package/src/rollup/BridgeCreator.sol +23 -28
- package/src/rollup/IRollupCore.sol +3 -3
- package/src/rollup/{IRollupEventBridge.sol → IRollupEventInbox.sol} +2 -2
- package/src/rollup/IRollupLogic.sol +21 -18
- package/src/rollup/RollupAdminLogic.sol +72 -34
- package/src/rollup/RollupCore.sol +20 -9
- package/src/rollup/RollupCreator.sol +21 -11
- package/src/rollup/{RollupEventBridge.sol → RollupEventInbox.sol} +10 -10
- package/src/rollup/RollupLib.sol +21 -5
- package/src/rollup/RollupUserLogic.sol +10 -18
- package/src/rollup/ValidatorWallet.sol +125 -8
- package/src/rollup/ValidatorWalletCreator.sol +11 -6
- package/src/state/Deserialize.sol +3 -22
- package/src/state/GlobalState.sol +7 -0
- package/src/state/Instructions.sol +2 -10
- package/src/state/Machine.sol +0 -4
- package/src/state/ModuleMemory.sol +2 -1
- package/src/state/Value.sol +2 -3
- package/src/test-helpers/BridgeTester.sol +233 -0
- package/src/test-helpers/InterfaceCompatibilityTester.sol +11 -0
- package/src/test-helpers/OutboxWithoutOptTester.sol +214 -0
- package/src/test-helpers/RollupMock.sol +21 -0
- package/src/bridge/IMessageProvider.sol +0 -11
- package/src/state/PcStack.sol +0 -32
@@ -21,16 +21,26 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
21
21
|
onlyProxy
|
22
22
|
initializer
|
23
23
|
{
|
24
|
-
|
25
|
-
|
24
|
+
rollupDeploymentBlock = block.number;
|
25
|
+
bridge = connectedContracts.bridge;
|
26
|
+
sequencerInbox = connectedContracts.sequencerInbox;
|
27
|
+
connectedContracts.bridge.setDelayedInbox(address(connectedContracts.inbox), true);
|
28
|
+
connectedContracts.bridge.setSequencerInbox(address(connectedContracts.sequencerInbox));
|
29
|
+
|
30
|
+
inbox = connectedContracts.inbox;
|
26
31
|
outbox = connectedContracts.outbox;
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
connectedContracts.bridge.setOutbox(address(connectedContracts.outbox), true);
|
33
|
+
rollupEventInbox = connectedContracts.rollupEventInbox;
|
34
|
+
connectedContracts.bridge.setDelayedInbox(
|
35
|
+
address(connectedContracts.rollupEventInbox),
|
36
|
+
true
|
37
|
+
);
|
30
38
|
|
31
|
-
|
32
|
-
|
39
|
+
connectedContracts.rollupEventInbox.rollupInitialized(config.chainId);
|
40
|
+
connectedContracts.sequencerInbox.addSequencerL2Batch(0, "", 1, IGasRefunder(address(0)));
|
33
41
|
|
42
|
+
validatorUtils = connectedContracts.validatorUtils;
|
43
|
+
validatorWalletCreator = connectedContracts.validatorWalletCreator;
|
34
44
|
challengeManager = connectedContracts.challengeManager;
|
35
45
|
|
36
46
|
Node memory node = createInitialNode();
|
@@ -53,8 +63,6 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
53
63
|
|
54
64
|
stakeToken = config.stakeToken;
|
55
65
|
|
56
|
-
sequencerBridge.setMaxTimeVariation(config.sequencerInboxMaxTimeVariation);
|
57
|
-
|
58
66
|
emit RollupInitialized(config.wasmModuleRoot, config.chainId);
|
59
67
|
}
|
60
68
|
|
@@ -86,7 +94,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
86
94
|
*/
|
87
95
|
function setOutbox(IOutbox _outbox) external override {
|
88
96
|
outbox = _outbox;
|
89
|
-
|
97
|
+
bridge.setOutbox(address(_outbox), true);
|
90
98
|
emit OwnerFunctionCalled(0);
|
91
99
|
}
|
92
100
|
|
@@ -96,7 +104,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
96
104
|
*/
|
97
105
|
function removeOldOutbox(address _outbox) external override {
|
98
106
|
require(_outbox != address(outbox), "CUR_OUTBOX");
|
99
|
-
|
107
|
+
bridge.setOutbox(_outbox, false);
|
100
108
|
emit OwnerFunctionCalled(1);
|
101
109
|
}
|
102
110
|
|
@@ -105,8 +113,8 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
105
113
|
* @param _inbox Inbox contract to add or remove
|
106
114
|
* @param _enabled New status of inbox
|
107
115
|
*/
|
108
|
-
function
|
109
|
-
|
116
|
+
function setDelayedInbox(address _inbox, bool _enabled) external override {
|
117
|
+
bridge.setDelayedInbox(address(_inbox), _enabled);
|
110
118
|
emit OwnerFunctionCalled(2);
|
111
119
|
}
|
112
120
|
|
@@ -224,27 +232,6 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
224
232
|
emit OwnerFunctionCalled(13);
|
225
233
|
}
|
226
234
|
|
227
|
-
/**
|
228
|
-
* @notice Set max delay for sequencer inbox
|
229
|
-
* @param maxTimeVariation the maximum time variation parameters
|
230
|
-
*/
|
231
|
-
function setSequencerInboxMaxTimeVariation(
|
232
|
-
ISequencerInbox.MaxTimeVariation calldata maxTimeVariation
|
233
|
-
) external override {
|
234
|
-
sequencerBridge.setMaxTimeVariation(maxTimeVariation);
|
235
|
-
emit OwnerFunctionCalled(14);
|
236
|
-
}
|
237
|
-
|
238
|
-
/**
|
239
|
-
* @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox
|
240
|
-
* @param addr the address
|
241
|
-
* @param isBatchPoster if the specified address should be authorized as a batch poster
|
242
|
-
*/
|
243
|
-
function setIsBatchPoster(address addr, bool isBatchPoster) external override {
|
244
|
-
ISequencerInbox(sequencerBridge).setIsBatchPoster(addr, isBatchPoster);
|
245
|
-
emit OwnerFunctionCalled(19);
|
246
|
-
}
|
247
|
-
|
248
235
|
/**
|
249
236
|
* @notice Upgrades the implementation of a beacon controlled by the rollup
|
250
237
|
* @param beacon address of beacon to be upgraded
|
@@ -319,4 +306,55 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, SecondaryLogicUUPSUpgrade
|
|
319
306
|
wasmModuleRoot = newWasmModuleRoot;
|
320
307
|
emit OwnerFunctionCalled(26);
|
321
308
|
}
|
309
|
+
|
310
|
+
/**
|
311
|
+
* @notice set a new sequencer inbox contract
|
312
|
+
* @param _sequencerInbox new address of sequencer inbox
|
313
|
+
*/
|
314
|
+
function setSequencerInbox(address _sequencerInbox) external override {
|
315
|
+
bridge.setSequencerInbox(_sequencerInbox);
|
316
|
+
emit OwnerFunctionCalled(27);
|
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
|
+
}
|
322
360
|
}
|
@@ -9,7 +9,7 @@ import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
|
9
9
|
import "./Node.sol";
|
10
10
|
import "./IRollupCore.sol";
|
11
11
|
import "./RollupLib.sol";
|
12
|
-
import "./
|
12
|
+
import "./IRollupEventInbox.sol";
|
13
13
|
import "./IRollupCore.sol";
|
14
14
|
|
15
15
|
import "../challenge/IChallengeManager.sol";
|
@@ -31,11 +31,17 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
31
31
|
uint256 public baseStake;
|
32
32
|
bytes32 public wasmModuleRoot;
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
IInbox public inbox;
|
35
|
+
IBridge public bridge;
|
36
36
|
IOutbox public outbox;
|
37
|
-
|
37
|
+
ISequencerInbox public sequencerInbox;
|
38
|
+
IRollupEventInbox public rollupEventInbox;
|
38
39
|
IChallengeManager public override challengeManager;
|
40
|
+
|
41
|
+
// misc useful contracts when interacting with the rollup
|
42
|
+
address public validatorUtils;
|
43
|
+
address public validatorWalletCreator;
|
44
|
+
|
39
45
|
// when a staker loses a challenge, half of their funds get escrowed in this address
|
40
46
|
address public loserStakeEscrow;
|
41
47
|
address public stakeToken;
|
@@ -63,6 +69,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
63
69
|
|
64
70
|
mapping(address => uint256) private _withdrawableFunds;
|
65
71
|
uint256 public totalWithdrawableFunds;
|
72
|
+
uint256 public rollupDeploymentBlock;
|
66
73
|
|
67
74
|
// The node number of the initial node
|
68
75
|
uint64 internal constant GENESIS_NODE = 0;
|
@@ -529,7 +536,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
529
536
|
{
|
530
537
|
// validate data
|
531
538
|
memoryFrame.prevNode = getNode(prevNodeNum);
|
532
|
-
memoryFrame.currentInboxSize =
|
539
|
+
memoryFrame.currentInboxSize = bridge.sequencerMessageCount();
|
533
540
|
|
534
541
|
// Make sure the previous state is correct against the node being built on
|
535
542
|
require(
|
@@ -545,7 +552,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
545
552
|
if (afterInboxCount == prevInboxPosition) {
|
546
553
|
require(
|
547
554
|
assertion.afterState.globalState.getPositionInMessage() >=
|
548
|
-
assertion.
|
555
|
+
assertion.beforeState.globalState.getPositionInMessage(),
|
549
556
|
"INBOX_POS_IN_MSG_BACKWARDS"
|
550
557
|
);
|
551
558
|
}
|
@@ -560,7 +567,7 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
560
567
|
require(afterInboxCount <= memoryFrame.currentInboxSize, "INBOX_PAST_END");
|
561
568
|
// This gives replay protection against the state of the inbox
|
562
569
|
if (afterInboxCount > 0) {
|
563
|
-
memoryFrame.sequencerBatchAcc =
|
570
|
+
memoryFrame.sequencerBatchAcc = bridge.sequencerInboxAccs(afterInboxCount - 1);
|
564
571
|
}
|
565
572
|
}
|
566
573
|
|
@@ -582,9 +589,13 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
582
589
|
memoryFrame.hasSibling,
|
583
590
|
memoryFrame.lastHash,
|
584
591
|
memoryFrame.executionHash,
|
585
|
-
memoryFrame.sequencerBatchAcc
|
592
|
+
memoryFrame.sequencerBatchAcc,
|
593
|
+
wasmModuleRoot
|
594
|
+
);
|
595
|
+
require(
|
596
|
+
newNodeHash == expectedNodeHash || expectedNodeHash == bytes32(0),
|
597
|
+
"UNEXPECTED_NODE_HASH"
|
586
598
|
);
|
587
|
-
require(newNodeHash == expectedNodeHash, "UNEXPECTED_NODE_HASH");
|
588
599
|
|
589
600
|
memoryFrame.node = NodeLib.createNode(
|
590
601
|
RollupLib.stateHash(assertion.afterState, memoryFrame.currentInboxSize),
|
@@ -18,7 +18,7 @@ contract RollupCreator is Ownable {
|
|
18
18
|
address inboxAddress,
|
19
19
|
address adminProxy,
|
20
20
|
address sequencerInbox,
|
21
|
-
address
|
21
|
+
address bridge
|
22
22
|
);
|
23
23
|
event TemplatesUpdated();
|
24
24
|
|
@@ -28,6 +28,9 @@ contract RollupCreator is Ownable {
|
|
28
28
|
IRollupAdmin public rollupAdminLogic;
|
29
29
|
IRollupUser public rollupUserLogic;
|
30
30
|
|
31
|
+
address public validatorUtils;
|
32
|
+
address public validatorWalletCreator;
|
33
|
+
|
31
34
|
constructor() Ownable() {}
|
32
35
|
|
33
36
|
function setTemplates(
|
@@ -35,22 +38,26 @@ contract RollupCreator is Ownable {
|
|
35
38
|
IOneStepProofEntry _osp,
|
36
39
|
IChallengeManager _challengeManagerLogic,
|
37
40
|
IRollupAdmin _rollupAdminLogic,
|
38
|
-
IRollupUser _rollupUserLogic
|
41
|
+
IRollupUser _rollupUserLogic,
|
42
|
+
address _validatorUtils,
|
43
|
+
address _validatorWalletCreator
|
39
44
|
) external onlyOwner {
|
40
45
|
bridgeCreator = _bridgeCreator;
|
41
46
|
osp = _osp;
|
42
47
|
challengeManagerTemplate = _challengeManagerLogic;
|
43
48
|
rollupAdminLogic = _rollupAdminLogic;
|
44
49
|
rollupUserLogic = _rollupUserLogic;
|
50
|
+
validatorUtils = _validatorUtils;
|
51
|
+
validatorWalletCreator = _validatorWalletCreator;
|
45
52
|
emit TemplatesUpdated();
|
46
53
|
}
|
47
54
|
|
48
55
|
struct CreateRollupFrame {
|
49
56
|
ProxyAdmin admin;
|
50
|
-
IBridge
|
57
|
+
IBridge bridge;
|
51
58
|
ISequencerInbox sequencerInbox;
|
52
59
|
IInbox inbox;
|
53
|
-
|
60
|
+
IRollupEventInbox rollupEventInbox;
|
54
61
|
IOutbox outbox;
|
55
62
|
ArbitrumProxy rollup;
|
56
63
|
}
|
@@ -68,10 +75,10 @@ contract RollupCreator is Ownable {
|
|
68
75
|
frame.admin = new ProxyAdmin();
|
69
76
|
|
70
77
|
(
|
71
|
-
frame.
|
78
|
+
frame.bridge,
|
72
79
|
frame.sequencerInbox,
|
73
80
|
frame.inbox,
|
74
|
-
frame.
|
81
|
+
frame.rollupEventInbox,
|
75
82
|
frame.outbox
|
76
83
|
) = bridgeCreator.createBridge(
|
77
84
|
address(frame.admin),
|
@@ -93,20 +100,23 @@ contract RollupCreator is Ownable {
|
|
93
100
|
challengeManager.initialize(
|
94
101
|
IChallengeResultReceiver(expectedRollupAddr),
|
95
102
|
frame.sequencerInbox,
|
96
|
-
frame.
|
103
|
+
frame.bridge,
|
97
104
|
osp
|
98
105
|
);
|
99
106
|
|
100
107
|
frame.rollup = new ArbitrumProxy(
|
101
108
|
config,
|
102
109
|
ContractDependencies({
|
103
|
-
|
110
|
+
bridge: frame.bridge,
|
104
111
|
sequencerInbox: frame.sequencerInbox,
|
112
|
+
inbox: frame.inbox,
|
105
113
|
outbox: frame.outbox,
|
106
|
-
|
114
|
+
rollupEventInbox: frame.rollupEventInbox,
|
107
115
|
challengeManager: challengeManager,
|
108
116
|
rollupAdminLogic: rollupAdminLogic,
|
109
|
-
rollupUserLogic: rollupUserLogic
|
117
|
+
rollupUserLogic: rollupUserLogic,
|
118
|
+
validatorUtils: validatorUtils,
|
119
|
+
validatorWalletCreator: validatorWalletCreator
|
110
120
|
})
|
111
121
|
);
|
112
122
|
require(address(frame.rollup) == expectedRollupAddr, "WRONG_ROLLUP_ADDR");
|
@@ -116,7 +126,7 @@ contract RollupCreator is Ownable {
|
|
116
126
|
address(frame.inbox),
|
117
127
|
address(frame.admin),
|
118
128
|
address(frame.sequencerInbox),
|
119
|
-
address(frame.
|
129
|
+
address(frame.bridge)
|
120
130
|
);
|
121
131
|
return address(frame.rollup);
|
122
132
|
}
|
@@ -4,36 +4,36 @@
|
|
4
4
|
|
5
5
|
pragma solidity ^0.8.0;
|
6
6
|
|
7
|
-
import "./
|
7
|
+
import "./IRollupEventInbox.sol";
|
8
8
|
import "../bridge/IBridge.sol";
|
9
|
-
import "../bridge/
|
9
|
+
import "../bridge/IDelayedMessageProvider.sol";
|
10
10
|
import "../libraries/DelegateCallAware.sol";
|
11
11
|
import {INITIALIZATION_MSG_TYPE} from "../libraries/MessageTypes.sol";
|
12
12
|
|
13
13
|
/**
|
14
14
|
* @title The inbox for rollup protocol events
|
15
15
|
*/
|
16
|
-
contract
|
16
|
+
contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, DelegateCallAware {
|
17
17
|
uint8 internal constant CREATE_NODE_EVENT = 0;
|
18
18
|
uint8 internal constant CONFIRM_NODE_EVENT = 1;
|
19
19
|
uint8 internal constant REJECT_NODE_EVENT = 2;
|
20
20
|
uint8 internal constant STAKE_CREATED_EVENT = 3;
|
21
21
|
|
22
|
-
IBridge public bridge;
|
23
|
-
address public rollup;
|
22
|
+
IBridge public override bridge;
|
23
|
+
address public override rollup;
|
24
24
|
|
25
25
|
modifier onlyRollup() {
|
26
26
|
require(msg.sender == rollup, "ONLY_ROLLUP");
|
27
27
|
_;
|
28
28
|
}
|
29
29
|
|
30
|
-
function initialize(
|
31
|
-
require(
|
32
|
-
bridge =
|
33
|
-
rollup =
|
30
|
+
function initialize(IBridge _bridge) external override onlyDelegated {
|
31
|
+
require(address(bridge) == address(0), "ALREADY_INIT");
|
32
|
+
bridge = _bridge;
|
33
|
+
rollup = address(_bridge.rollup());
|
34
34
|
}
|
35
35
|
|
36
|
-
function rollupInitialized(uint256 chainId) external onlyRollup {
|
36
|
+
function rollupInitialized(uint256 chainId) external override onlyRollup {
|
37
37
|
bytes memory initMsg = abi.encodePacked(chainId);
|
38
38
|
uint256 num = bridge.enqueueDelayedMessage(
|
39
39
|
INITIALIZATION_MSG_TYPE,
|
package/src/rollup/RollupLib.sol
CHANGED
@@ -11,7 +11,8 @@ import "../bridge/ISequencerInbox.sol";
|
|
11
11
|
|
12
12
|
import "../bridge/IBridge.sol";
|
13
13
|
import "../bridge/IOutbox.sol";
|
14
|
-
import "
|
14
|
+
import "../bridge/IInbox.sol";
|
15
|
+
import "./IRollupEventInbox.sol";
|
15
16
|
import "./IRollupLogic.sol";
|
16
17
|
|
17
18
|
struct Config {
|
@@ -23,17 +24,22 @@ struct Config {
|
|
23
24
|
address owner;
|
24
25
|
address loserStakeEscrow;
|
25
26
|
uint256 chainId;
|
27
|
+
uint64 genesisBlockNum;
|
26
28
|
ISequencerInbox.MaxTimeVariation sequencerInboxMaxTimeVariation;
|
27
29
|
}
|
28
30
|
|
29
31
|
struct ContractDependencies {
|
30
|
-
IBridge
|
32
|
+
IBridge bridge;
|
31
33
|
ISequencerInbox sequencerInbox;
|
34
|
+
IInbox inbox;
|
32
35
|
IOutbox outbox;
|
33
|
-
|
36
|
+
IRollupEventInbox rollupEventInbox;
|
34
37
|
IChallengeManager challengeManager;
|
35
38
|
IRollupAdmin rollupAdminLogic;
|
36
39
|
IRollupUser rollupUserLogic;
|
40
|
+
// misc contracts that are useful when interacting with the rollup
|
41
|
+
address validatorUtils;
|
42
|
+
address validatorWalletCreator;
|
37
43
|
}
|
38
44
|
|
39
45
|
library RollupLib {
|
@@ -127,9 +133,19 @@ library RollupLib {
|
|
127
133
|
bool hasSibling,
|
128
134
|
bytes32 lastHash,
|
129
135
|
bytes32 assertionExecHash,
|
130
|
-
bytes32 inboxAcc
|
136
|
+
bytes32 inboxAcc,
|
137
|
+
bytes32 wasmModuleRoot
|
131
138
|
) internal pure returns (bytes32) {
|
132
139
|
uint8 hasSiblingInt = hasSibling ? 1 : 0;
|
133
|
-
return
|
140
|
+
return
|
141
|
+
keccak256(
|
142
|
+
abi.encodePacked(
|
143
|
+
hasSiblingInt,
|
144
|
+
lastHash,
|
145
|
+
assertionExecHash,
|
146
|
+
inboxAcc,
|
147
|
+
wasmModuleRoot
|
148
|
+
)
|
149
|
+
);
|
134
150
|
}
|
135
151
|
}
|
@@ -487,6 +487,10 @@ abstract contract AbsRollupUserLogic is
|
|
487
487
|
return currentRequiredStake(blockNumber, firstUnresolvedNodeNum, latestCreatedNode);
|
488
488
|
}
|
489
489
|
|
490
|
+
function owner() external view returns (address) {
|
491
|
+
return _getAdmin();
|
492
|
+
}
|
493
|
+
|
490
494
|
function currentRequiredStake() public view returns (uint256) {
|
491
495
|
uint64 firstUnresolvedNodeNum = firstUnresolvedNode();
|
492
496
|
|
@@ -615,18 +619,13 @@ contract RollupUserLogic is AbsRollupUserLogic, IRollupUser {
|
|
615
619
|
|
616
620
|
/**
|
617
621
|
* @notice Withdraw uncommitted funds owned by sender from the rollup chain
|
618
|
-
* @param destination Address to transfer the withdrawn funds to
|
619
622
|
*/
|
620
|
-
function withdrawStakerFunds(
|
621
|
-
external
|
622
|
-
override
|
623
|
-
onlyValidator
|
624
|
-
whenNotPaused
|
625
|
-
returns (uint256)
|
626
|
-
{
|
623
|
+
function withdrawStakerFunds() external override onlyValidator whenNotPaused returns (uint256) {
|
627
624
|
uint256 amount = withdrawFunds(msg.sender);
|
628
625
|
// This is safe because it occurs after all checks and effects
|
629
|
-
|
626
|
+
// solhint-disable-next-line avoid-low-level-calls
|
627
|
+
(bool success, ) = msg.sender.call{value: amount}("");
|
628
|
+
require(success, "TRANSFER_FAILED");
|
630
629
|
return amount;
|
631
630
|
}
|
632
631
|
}
|
@@ -692,18 +691,11 @@ contract ERC20RollupUserLogic is AbsRollupUserLogic, IRollupUserERC20 {
|
|
692
691
|
|
693
692
|
/**
|
694
693
|
* @notice Withdraw uncommitted funds owned by sender from the rollup chain
|
695
|
-
* @param destination Address to transfer the withdrawn funds to
|
696
694
|
*/
|
697
|
-
function withdrawStakerFunds(
|
698
|
-
external
|
699
|
-
override
|
700
|
-
onlyValidator
|
701
|
-
whenNotPaused
|
702
|
-
returns (uint256)
|
703
|
-
{
|
695
|
+
function withdrawStakerFunds() external override onlyValidator whenNotPaused returns (uint256) {
|
704
696
|
uint256 amount = withdrawFunds(msg.sender);
|
705
697
|
// This is safe because it occurs after all checks and effects
|
706
|
-
require(IERC20Upgradeable(stakeToken).transfer(
|
698
|
+
require(IERC20Upgradeable(stakeToken).transfer(msg.sender, amount), "TRANSFER_FAILED");
|
707
699
|
return amount;
|
708
700
|
}
|
709
701
|
|
@@ -6,24 +6,117 @@ pragma solidity ^0.8.0;
|
|
6
6
|
|
7
7
|
import "../challenge/IChallengeManager.sol";
|
8
8
|
import "../libraries/DelegateCallAware.sol";
|
9
|
+
import "../libraries/IGasRefunder.sol";
|
9
10
|
import "@openzeppelin/contracts/utils/Address.sol";
|
10
11
|
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
11
12
|
|
12
|
-
|
13
|
+
/// @dev thrown when arrays provided don't have the expected length
|
14
|
+
error BadArrayLength(uint256 expected, uint256 actual);
|
15
|
+
|
16
|
+
/// @dev thrown when a function is called by an address that isn't the owner nor a executor
|
17
|
+
error NotExecutorOrOwner(address actual);
|
18
|
+
|
19
|
+
/// @dev thrown when the particular address can't be called by an executor
|
20
|
+
error OnlyOwnerDestination(address expected, address actual, address destination);
|
21
|
+
|
22
|
+
/// @dev thrown when eth withdrawal tx fails
|
23
|
+
error WithdrawEthFail(address destination);
|
24
|
+
|
25
|
+
contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware, GasRefundEnabled {
|
13
26
|
using Address for address;
|
14
27
|
|
15
|
-
|
28
|
+
/// @dev a executor is allowed to call only certain contracts
|
29
|
+
mapping(address => bool) public executors;
|
30
|
+
|
31
|
+
/// @dev allowed addresses which can be called by an executor
|
32
|
+
mapping(address => bool) public allowedExecutorDestinations;
|
33
|
+
|
34
|
+
modifier onlyExecutorOrOwner() {
|
35
|
+
if (!executors[_msgSender()] && owner() != _msgSender())
|
36
|
+
revert NotExecutorOrOwner(_msgSender());
|
37
|
+
_;
|
38
|
+
}
|
39
|
+
|
40
|
+
event ExecutorUpdated(address indexed executor, bool isExecutor);
|
41
|
+
|
42
|
+
/// @dev updates the executor addresses
|
43
|
+
function setExecutor(address[] calldata newExecutors, bool[] calldata isExecutor)
|
44
|
+
external
|
45
|
+
onlyOwner
|
46
|
+
{
|
47
|
+
if (newExecutors.length != isExecutor.length)
|
48
|
+
revert BadArrayLength(newExecutors.length, isExecutor.length);
|
49
|
+
unchecked {
|
50
|
+
for (uint64 i = 0; i < newExecutors.length; ++i) {
|
51
|
+
executors[newExecutors[i]] = isExecutor[i];
|
52
|
+
emit ExecutorUpdated(newExecutors[i], isExecutor[i]);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
function initialize(
|
58
|
+
address _executor,
|
59
|
+
address _owner,
|
60
|
+
address[] calldata initialExecutorAllowedDests
|
61
|
+
) external initializer onlyDelegated {
|
16
62
|
__Ownable_init();
|
63
|
+
transferOwnership(_owner);
|
64
|
+
|
65
|
+
executors[_executor] = true;
|
66
|
+
emit ExecutorUpdated(_executor, true);
|
67
|
+
|
68
|
+
unchecked {
|
69
|
+
for (uint64 i = 0; i < initialExecutorAllowedDests.length; ++i) {
|
70
|
+
allowedExecutorDestinations[initialExecutorAllowedDests[i]] = true;
|
71
|
+
emit AllowedExecutorDestinationsUpdated(initialExecutorAllowedDests[i], true);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
event AllowedExecutorDestinationsUpdated(address indexed destination, bool isSet);
|
77
|
+
|
78
|
+
/// @notice updates the destination addresses which executors are allowed to call
|
79
|
+
function setAllowedExecutorDestinations(address[] calldata destinations, bool[] calldata isSet)
|
80
|
+
external
|
81
|
+
onlyOwner
|
82
|
+
{
|
83
|
+
if (destinations.length != isSet.length)
|
84
|
+
revert BadArrayLength(destinations.length, isSet.length);
|
85
|
+
unchecked {
|
86
|
+
for (uint256 i = 0; i < destinations.length; ++i) {
|
87
|
+
allowedExecutorDestinations[destinations[i]] = isSet[i];
|
88
|
+
emit AllowedExecutorDestinationsUpdated(destinations[i], isSet[i]);
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
/// @dev reverts if the current function can't be called
|
94
|
+
function validateExecuteTransaction(address destination) public view {
|
95
|
+
if (!allowedExecutorDestinations[destination] && owner() != _msgSender())
|
96
|
+
revert OnlyOwnerDestination(owner(), _msgSender(), destination);
|
17
97
|
}
|
18
98
|
|
19
99
|
function executeTransactions(
|
20
100
|
bytes[] calldata data,
|
21
101
|
address[] calldata destination,
|
22
102
|
uint256[] calldata amount
|
23
|
-
) external payable
|
103
|
+
) external payable {
|
104
|
+
executeTransactionsWithGasRefunder(IGasRefunder(address(0)), data, destination, amount);
|
105
|
+
}
|
106
|
+
|
107
|
+
function executeTransactionsWithGasRefunder(
|
108
|
+
IGasRefunder gasRefunder,
|
109
|
+
bytes[] calldata data,
|
110
|
+
address[] calldata destination,
|
111
|
+
uint256[] calldata amount
|
112
|
+
) public payable onlyExecutorOrOwner refundsGas(gasRefunder) {
|
24
113
|
uint256 numTxes = data.length;
|
114
|
+
if (numTxes != destination.length) revert BadArrayLength(numTxes, destination.length);
|
115
|
+
if (numTxes != amount.length) revert BadArrayLength(numTxes, amount.length);
|
116
|
+
|
25
117
|
for (uint256 i = 0; i < numTxes; i++) {
|
26
118
|
if (data[i].length > 0) require(destination[i].isContract(), "NO_CODE_AT_ADDR");
|
119
|
+
validateExecuteTransaction(destination[i]);
|
27
120
|
// We use a low level call here to allow for contract and non-contract calls
|
28
121
|
// solhint-disable-next-line avoid-low-level-calls
|
29
122
|
(bool success, ) = address(destination[i]).call{value: amount[i]}(data[i]);
|
@@ -42,8 +135,18 @@ contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware {
|
|
42
135
|
bytes calldata data,
|
43
136
|
address destination,
|
44
137
|
uint256 amount
|
45
|
-
) external payable
|
138
|
+
) external payable {
|
139
|
+
executeTransactionWithGasRefunder(IGasRefunder(address(0)), data, destination, amount);
|
140
|
+
}
|
141
|
+
|
142
|
+
function executeTransactionWithGasRefunder(
|
143
|
+
IGasRefunder gasRefunder,
|
144
|
+
bytes calldata data,
|
145
|
+
address destination,
|
146
|
+
uint256 amount
|
147
|
+
) public payable onlyExecutorOrOwner refundsGas(gasRefunder) {
|
46
148
|
if (data.length > 0) require(destination.isContract(), "NO_CODE_AT_ADDR");
|
149
|
+
validateExecuteTransaction(destination);
|
47
150
|
// We use a low level call here to allow for contract and non-contract calls
|
48
151
|
// solhint-disable-next-line avoid-low-level-calls
|
49
152
|
(bool success, ) = destination.call{value: amount}(data);
|
@@ -57,10 +160,15 @@ contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware {
|
|
57
160
|
}
|
58
161
|
}
|
59
162
|
|
60
|
-
function timeoutChallenges(IChallengeManager manager, uint64[] calldata challenges)
|
61
|
-
|
62
|
-
|
63
|
-
|
163
|
+
function timeoutChallenges(IChallengeManager manager, uint64[] calldata challenges) external {
|
164
|
+
timeoutChallengesWithGasRefunder(IGasRefunder(address(0)), manager, challenges);
|
165
|
+
}
|
166
|
+
|
167
|
+
function timeoutChallengesWithGasRefunder(
|
168
|
+
IGasRefunder gasRefunder,
|
169
|
+
IChallengeManager manager,
|
170
|
+
uint64[] calldata challenges
|
171
|
+
) public onlyExecutorOrOwner refundsGas(gasRefunder) {
|
64
172
|
uint256 challengesCount = challenges.length;
|
65
173
|
for (uint256 i = 0; i < challengesCount; i++) {
|
66
174
|
try manager.timeout(challenges[i]) {} catch (bytes memory error) {
|
@@ -72,4 +180,13 @@ contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware {
|
|
72
180
|
}
|
73
181
|
}
|
74
182
|
}
|
183
|
+
|
184
|
+
receive() external payable {}
|
185
|
+
|
186
|
+
/// @dev allows the owner to withdraw eth held by this contract
|
187
|
+
function withdrawEth(uint256 amount, address destination) external onlyOwner {
|
188
|
+
// solhint-disable-next-line avoid-low-level-calls
|
189
|
+
(bool success, ) = destination.call{value: amount}("");
|
190
|
+
if (!success) revert WithdrawEthFail(destination);
|
191
|
+
}
|
75
192
|
}
|