@arbitrum/nitro-contracts 1.0.2 → 1.1.0-alpha.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/hardhat.config.ts +164 -0
- package/package.json +4 -3
- package/src/bridge/Bridge.sol +2 -2
- package/src/bridge/ISequencerInbox.sol +10 -0
- package/src/bridge/Inbox.sol +1 -1
- package/src/bridge/SequencerInbox.sol +8 -0
- package/src/libraries/AdminFallbackProxy.sol +2 -2
- package/src/libraries/IGasRefunder.sol +1 -4
- package/src/mocks/BridgeStub.sol +1 -1
- package/src/mocks/Simple.sol +4 -0
- package/src/node-interface/NodeInterface.sol +3 -1
- package/src/precompiles/ArbOwner.sol +3 -0
- package/src/rollup/IRollupCore.sol +9 -0
- package/src/rollup/IRollupEventInbox.sol +1 -1
- package/src/rollup/RollupAdminLogic.sol +1 -1
- package/src/rollup/RollupCore.sol +44 -0
- package/src/rollup/RollupCreator.sol +31 -43
- package/src/rollup/RollupEventInbox.sol +7 -2
- package/src/rollup/RollupLib.sol +1 -0
- package/src/rollup/RollupProxy.sol +23 -9
@@ -0,0 +1,164 @@
|
|
1
|
+
import '@nomiclabs/hardhat-waffle'
|
2
|
+
import 'hardhat-deploy'
|
3
|
+
import '@nomiclabs/hardhat-ethers'
|
4
|
+
import '@nomiclabs/hardhat-etherscan'
|
5
|
+
import '@typechain/hardhat'
|
6
|
+
import 'solidity-coverage'
|
7
|
+
import 'hardhat-gas-reporter'
|
8
|
+
|
9
|
+
const solidity = {
|
10
|
+
compilers: [
|
11
|
+
{
|
12
|
+
version: '0.8.9',
|
13
|
+
settings: {
|
14
|
+
optimizer: {
|
15
|
+
enabled: true,
|
16
|
+
runs: 100,
|
17
|
+
},
|
18
|
+
},
|
19
|
+
},
|
20
|
+
],
|
21
|
+
overrides: {},
|
22
|
+
}
|
23
|
+
|
24
|
+
if (process.env['INTERFACE_TESTER_SOLC_VERSION']) {
|
25
|
+
solidity.compilers.push({
|
26
|
+
version: process.env['INTERFACE_TESTER_SOLC_VERSION'],
|
27
|
+
settings: {
|
28
|
+
optimizer: {
|
29
|
+
enabled: true,
|
30
|
+
runs: 100,
|
31
|
+
},
|
32
|
+
},
|
33
|
+
})
|
34
|
+
solidity.overrides = {
|
35
|
+
'src/test-helpers/InterfaceCompatibilityTester.sol': {
|
36
|
+
version: process.env['INTERFACE_TESTER_SOLC_VERSION'],
|
37
|
+
settings: {
|
38
|
+
optimizer: {
|
39
|
+
enabled: true,
|
40
|
+
runs: 100,
|
41
|
+
},
|
42
|
+
},
|
43
|
+
},
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
* @type import('hardhat/config').HardhatUserConfig
|
49
|
+
*/
|
50
|
+
module.exports = {
|
51
|
+
solidity,
|
52
|
+
paths: {
|
53
|
+
sources: './src',
|
54
|
+
artifacts: 'build/contracts',
|
55
|
+
},
|
56
|
+
namedAccounts: {
|
57
|
+
deployer: {
|
58
|
+
default: 0,
|
59
|
+
},
|
60
|
+
},
|
61
|
+
networks: {
|
62
|
+
hardhat: {
|
63
|
+
chainId: 1338,
|
64
|
+
throwOnTransactionFailures: true,
|
65
|
+
allowUnlimitedContractSize: true,
|
66
|
+
accounts: {
|
67
|
+
accountsBalance: '1000000000000000000000000000',
|
68
|
+
},
|
69
|
+
blockGasLimit: 200000000,
|
70
|
+
// mining: {
|
71
|
+
// auto: false,
|
72
|
+
// interval: 1000,
|
73
|
+
// },
|
74
|
+
forking: {
|
75
|
+
url: 'https://mainnet.infura.io/v3/' + process.env['INFURA_KEY'],
|
76
|
+
enabled: process.env['SHOULD_FORK'] === '1',
|
77
|
+
},
|
78
|
+
},
|
79
|
+
mainnet: {
|
80
|
+
url: 'https://mainnet.infura.io/v3/' + process.env['INFURA_KEY'],
|
81
|
+
accounts: process.env['MAINNET_PRIVKEY']
|
82
|
+
? [process.env['MAINNET_PRIVKEY']]
|
83
|
+
: [],
|
84
|
+
},
|
85
|
+
goerli: {
|
86
|
+
url: 'https://goerli.infura.io/v3/' + process.env['INFURA_KEY'],
|
87
|
+
accounts: process.env['DEVNET_PRIVKEY']
|
88
|
+
? [process.env['DEVNET_PRIVKEY']]
|
89
|
+
: [],
|
90
|
+
},
|
91
|
+
rinkeby: {
|
92
|
+
url: 'https://rinkeby.infura.io/v3/' + process.env['INFURA_KEY'],
|
93
|
+
accounts: process.env['DEVNET_PRIVKEY']
|
94
|
+
? [process.env['DEVNET_PRIVKEY']]
|
95
|
+
: [],
|
96
|
+
},
|
97
|
+
arbRinkeby: {
|
98
|
+
url: 'https://rinkeby.arbitrum.io/rpc',
|
99
|
+
accounts: process.env['DEVNET_PRIVKEY']
|
100
|
+
? [process.env['DEVNET_PRIVKEY']]
|
101
|
+
: [],
|
102
|
+
},
|
103
|
+
arbGoerliRollup: {
|
104
|
+
url: 'https://goerli-rollup.arbitrum.io/rpc',
|
105
|
+
accounts: process.env['DEVNET_PRIVKEY']
|
106
|
+
? [process.env['DEVNET_PRIVKEY']]
|
107
|
+
: [],
|
108
|
+
},
|
109
|
+
arb1: {
|
110
|
+
url: 'https://arb1.arbitrum.io/rpc',
|
111
|
+
accounts: process.env['MAINNET_PRIVKEY']
|
112
|
+
? [process.env['MAINNET_PRIVKEY']]
|
113
|
+
: [],
|
114
|
+
},
|
115
|
+
nova: {
|
116
|
+
url: 'https://nova.arbitrum.io/rpc',
|
117
|
+
accounts: process.env['MAINNET_PRIVKEY']
|
118
|
+
? [process.env['MAINNET_PRIVKEY']]
|
119
|
+
: [],
|
120
|
+
},
|
121
|
+
geth: {
|
122
|
+
url: 'http://localhost:8545',
|
123
|
+
},
|
124
|
+
},
|
125
|
+
etherscan: {
|
126
|
+
apiKey: {
|
127
|
+
mainnet: process.env['ETHERSCAN_API_KEY'],
|
128
|
+
goerli: process.env['ETHERSCAN_API_KEY'],
|
129
|
+
rinkeby: process.env['ETHERSCAN_API_KEY'],
|
130
|
+
arbitrumOne: process.env['ARBISCAN_API_KEY'],
|
131
|
+
arbitrumTestnet: process.env['ARBISCAN_API_KEY'],
|
132
|
+
nova: process.env['NOVA_ARBISCAN_API_KEY'],
|
133
|
+
arbGoerliRollup: process.env['ARBISCAN_API_KEY'],
|
134
|
+
},
|
135
|
+
customChains: [
|
136
|
+
{
|
137
|
+
network: 'nova',
|
138
|
+
chainId: 42170,
|
139
|
+
urls: {
|
140
|
+
apiURL: 'https://api-nova.arbiscan.io/api',
|
141
|
+
browserURL: 'https://nova.arbiscan.io/',
|
142
|
+
},
|
143
|
+
},
|
144
|
+
{
|
145
|
+
network: 'arbGoerliRollup',
|
146
|
+
chainId: 421613,
|
147
|
+
urls: {
|
148
|
+
apiURL: 'https://api-goerli.arbiscan.io/api',
|
149
|
+
browserURL: 'https://goerli.arbiscan.io/',
|
150
|
+
},
|
151
|
+
},
|
152
|
+
],
|
153
|
+
},
|
154
|
+
mocha: {
|
155
|
+
timeout: 0,
|
156
|
+
},
|
157
|
+
gasReporter: {
|
158
|
+
enabled: process.env.DISABLE_GAS_REPORTER ? false : true,
|
159
|
+
},
|
160
|
+
typechain: {
|
161
|
+
outDir: 'build/types',
|
162
|
+
target: 'ethers-v5',
|
163
|
+
},
|
164
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@arbitrum/nitro-contracts",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.1.0-alpha.1",
|
4
4
|
"description": "Layer 2 precompiles and rollup for Arbitrum Nitro",
|
5
5
|
"author": "Offchain Labs, Inc.",
|
6
6
|
"license": "BUSL-1.1",
|
@@ -9,7 +9,8 @@
|
|
9
9
|
"url": "git+https://github.com/offchainlabs/nitro-contracts.git"
|
10
10
|
},
|
11
11
|
"files": [
|
12
|
-
"src/"
|
12
|
+
"src/",
|
13
|
+
"hardhat.config.ts"
|
13
14
|
],
|
14
15
|
"bugs": {
|
15
16
|
"url": "https://github.com/offchainlabs/nitro-contracts/issues"
|
@@ -60,8 +61,8 @@
|
|
60
61
|
"solhint": "^3.3.7",
|
61
62
|
"solhint-plugin-prettier": "^0.0.5",
|
62
63
|
"solidity-coverage": "^0.7.20",
|
63
|
-
"tslint": "^6.1.3",
|
64
64
|
"ts-node": "^10.4.0",
|
65
|
+
"tslint": "^6.1.3",
|
65
66
|
"typechain": "^8.0.0",
|
66
67
|
"typescript": "^4.5.4"
|
67
68
|
},
|
package/src/bridge/Bridge.sol
CHANGED
@@ -230,7 +230,7 @@ contract Bridge is Initializable, DelegateCallAware, IBridge {
|
|
230
230
|
InOutInfo storage info = allowedDelayedInboxesMap[inbox];
|
231
231
|
bool alreadyEnabled = info.allowed;
|
232
232
|
emit InboxToggle(inbox, enabled);
|
233
|
-
if (
|
233
|
+
if (alreadyEnabled == enabled) {
|
234
234
|
return;
|
235
235
|
}
|
236
236
|
if (enabled) {
|
@@ -252,7 +252,7 @@ contract Bridge is Initializable, DelegateCallAware, IBridge {
|
|
252
252
|
InOutInfo storage info = allowedOutboxesMap[outbox];
|
253
253
|
bool alreadyEnabled = info.allowed;
|
254
254
|
emit OutboxToggle(outbox, enabled);
|
255
|
-
if (
|
255
|
+
if (alreadyEnabled == enabled) {
|
256
256
|
return;
|
257
257
|
}
|
258
258
|
if (enabled) {
|
@@ -69,6 +69,8 @@ interface ISequencerInbox is IDelayedMessageProvider {
|
|
69
69
|
|
70
70
|
function isBatchPoster(address) external view returns (bool);
|
71
71
|
|
72
|
+
function isSequencer(address) external view returns (bool);
|
73
|
+
|
72
74
|
struct DasKeySetInfo {
|
73
75
|
bool isValidKeyset;
|
74
76
|
uint64 creationBlock;
|
@@ -154,6 +156,14 @@ interface ISequencerInbox is IDelayedMessageProvider {
|
|
154
156
|
*/
|
155
157
|
function invalidateKeysetHash(bytes32 ksHash) external;
|
156
158
|
|
159
|
+
/**
|
160
|
+
* @notice Updates whether an address is authorized to be a sequencer.
|
161
|
+
* @dev The IsSequencer information is used only off-chain by the nitro node to validate sequencer feed signer.
|
162
|
+
* @param addr the address
|
163
|
+
* @param isSequencer_ if the specified address should be authorized as a sequencer
|
164
|
+
*/
|
165
|
+
function setIsSequencer(address addr, bool isSequencer_) external;
|
166
|
+
|
157
167
|
// ---------- initializer ----------
|
158
168
|
|
159
169
|
function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external;
|
package/src/bridge/Inbox.sol
CHANGED
@@ -352,7 +352,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
|
|
352
352
|
nonce,
|
353
353
|
uint256(uint160(address(100))), // ArbSys address
|
354
354
|
value,
|
355
|
-
abi.
|
355
|
+
abi.encodeWithSelector(ArbSys.withdrawEth.selector, withdrawTo)
|
356
356
|
)
|
357
357
|
);
|
358
358
|
}
|
@@ -64,6 +64,8 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
|
|
64
64
|
|
65
65
|
uint256 internal immutable deployTimeChainId = block.chainid;
|
66
66
|
|
67
|
+
mapping(address => bool) public isSequencer;
|
68
|
+
|
67
69
|
function _chainIdChanged() internal view returns (bool) {
|
68
70
|
return deployTimeChainId != block.chainid;
|
69
71
|
}
|
@@ -450,6 +452,12 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
|
|
450
452
|
emit OwnerFunctionCalled(3);
|
451
453
|
}
|
452
454
|
|
455
|
+
/// @inheritdoc ISequencerInbox
|
456
|
+
function setIsSequencer(address addr, bool isSequencer_) external onlyRollupOwner {
|
457
|
+
isSequencer[addr] = isSequencer_;
|
458
|
+
emit OwnerFunctionCalled(4);
|
459
|
+
}
|
460
|
+
|
453
461
|
function isValidKeysetHash(bytes32 ksHash) external view returns (bool) {
|
454
462
|
return dasKeySetInfo[ksHash].isValidKeyset;
|
455
463
|
}
|
@@ -107,13 +107,13 @@ contract AdminFallbackProxy is Proxy, DoubleLogicERC1967Upgrade {
|
|
107
107
|
* Only the `adminAddr` is able to use the `adminLogic` functions
|
108
108
|
* All other addresses can interact with the `userLogic` functions
|
109
109
|
*/
|
110
|
-
|
110
|
+
function _initialize(
|
111
111
|
address adminLogic,
|
112
112
|
bytes memory adminData,
|
113
113
|
address userLogic,
|
114
114
|
bytes memory userData,
|
115
115
|
address adminAddr
|
116
|
-
)
|
116
|
+
) internal {
|
117
117
|
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
|
118
118
|
assert(
|
119
119
|
_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)
|
@@ -21,10 +21,7 @@ abstract contract GasRefundEnabled {
|
|
21
21
|
uint256 startGasLeft = gasleft();
|
22
22
|
_;
|
23
23
|
if (address(gasRefunder) != address(0)) {
|
24
|
-
uint256 calldataSize;
|
25
|
-
assembly {
|
26
|
-
calldataSize := calldatasize()
|
27
|
-
}
|
24
|
+
uint256 calldataSize = msg.data.length;
|
28
25
|
uint256 calldataWords = (calldataSize + 31) / 32;
|
29
26
|
// account for the CALLDATACOPY cost of the proxy contract, including the memory expansion cost
|
30
27
|
startGasLeft += calldataWords * 6 + (calldataWords**2) / 512;
|
package/src/mocks/BridgeStub.sol
CHANGED
@@ -139,7 +139,7 @@ contract BridgeStub is IBridge {
|
|
139
139
|
InOutInfo storage info = allowedDelayedInboxesMap[inbox];
|
140
140
|
bool alreadyEnabled = info.allowed;
|
141
141
|
emit InboxToggle(inbox, enabled);
|
142
|
-
if (
|
142
|
+
if (alreadyEnabled == enabled) {
|
143
143
|
return;
|
144
144
|
}
|
145
145
|
if (enabled) {
|
package/src/mocks/Simple.sol
CHANGED
@@ -98,8 +98,10 @@ interface NodeInterface {
|
|
98
98
|
/**
|
99
99
|
* @notice Estimates a transaction's l1 costs.
|
100
100
|
* @dev Use eth_call to call.
|
101
|
-
* This method is
|
101
|
+
* This method is similar to gasEstimateComponents, but doesn't include the l2 component
|
102
102
|
* so that the l1 component can be known even when the tx may fail.
|
103
|
+
* This method also doesn't pad the estimate as gas estimation normally does.
|
104
|
+
* If using this value to submit a transaction, we'd recommend first padding it by 10%.
|
103
105
|
* @param data the tx's calldata. Everything else like "From" and "Gas" are copied over
|
104
106
|
* @param to the tx's "To" (ignored when contractCreation is true)
|
105
107
|
* @param contractCreation whether "To" is omitted
|
@@ -84,6 +84,9 @@ interface ArbOwner {
|
|
84
84
|
/// @notice Releases surplus funds from L1PricerFundsPoolAddress for use
|
85
85
|
function releaseL1PricerSurplusFunds(uint256 maxWeiToRelease) external returns (uint256);
|
86
86
|
|
87
|
+
/// @notice Sets serialized chain config in ArbOS state
|
88
|
+
function setChainConfig(string calldata chainConfig) external;
|
89
|
+
|
87
90
|
// Emitted when a successful call is made to this precompile
|
88
91
|
event OwnerActs(bytes4 indexed method, address indexed owner, bytes data);
|
89
92
|
}
|
@@ -84,6 +84,15 @@ interface IRollupCore {
|
|
84
84
|
*/
|
85
85
|
function getNode(uint64 nodeNum) external view returns (Node memory);
|
86
86
|
|
87
|
+
/**
|
88
|
+
* @notice Returns the block in which the given node was created for looking up its creation event.
|
89
|
+
* Unlike the Node's createdAtBlock field, this will be the ArbSys blockNumber if the host chain is an Arbitrum chain.
|
90
|
+
* That means that the block number returned for this is usable for event queries.
|
91
|
+
* This function will revert if the given node number does not exist.
|
92
|
+
* @dev This function is meant for internal use only and has no stability guarantees.
|
93
|
+
*/
|
94
|
+
function getNodeCreationBlockForLogLookup(uint64 nodeNum) external view returns (uint256);
|
95
|
+
|
87
96
|
/**
|
88
97
|
* @notice Check if the specified node has been staked on by the provided staker.
|
89
98
|
* Only accurate at the latest confirmed node and afterwards.
|
@@ -36,7 +36,7 @@ contract RollupAdminLogic is RollupCore, IRollupAdmin, DoubleLogicUUPSUpgradeabl
|
|
36
36
|
true
|
37
37
|
);
|
38
38
|
|
39
|
-
connectedContracts.rollupEventInbox.rollupInitialized(config.chainId);
|
39
|
+
connectedContracts.rollupEventInbox.rollupInitialized(config.chainId, config.chainConfig);
|
40
40
|
connectedContracts.sequencerInbox.addSequencerL2Batch(
|
41
41
|
0,
|
42
42
|
"",
|
@@ -18,6 +18,8 @@ import "../bridge/ISequencerInbox.sol";
|
|
18
18
|
import "../bridge/IBridge.sol";
|
19
19
|
import "../bridge/IOutbox.sol";
|
20
20
|
|
21
|
+
import "../precompiles/ArbSys.sol";
|
22
|
+
|
21
23
|
import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
|
22
24
|
|
23
25
|
abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
@@ -76,6 +78,18 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
76
78
|
|
77
79
|
bool public validatorWhitelistDisabled;
|
78
80
|
|
81
|
+
// If the chain this RollupCore is deployed on is an Arbitrum chain.
|
82
|
+
bool internal immutable _hostChainIsArbitrum;
|
83
|
+
// If the chain RollupCore is deployed on, this will contain the ArbSys.blockNumber() at each node's creation.
|
84
|
+
mapping(uint64 => uint256) internal _nodeCreatedAtArbSysBlock;
|
85
|
+
|
86
|
+
constructor() {
|
87
|
+
(bool ok, bytes memory data) = address(100).staticcall(
|
88
|
+
abi.encodeWithSelector(ArbSys.arbOSVersion.selector)
|
89
|
+
);
|
90
|
+
_hostChainIsArbitrum = ok && data.length == 32;
|
91
|
+
}
|
92
|
+
|
79
93
|
/**
|
80
94
|
* @notice Get a storage reference to the Node for the given node index
|
81
95
|
* @param nodeNum Index of the node
|
@@ -92,6 +106,30 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
92
106
|
return getNodeStorage(nodeNum);
|
93
107
|
}
|
94
108
|
|
109
|
+
/**
|
110
|
+
* @notice Returns the block in which the given node was created for looking up its creation event.
|
111
|
+
* Unlike the Node's createdAtBlock field, this will be the ArbSys blockNumber if the host chain is an Arbitrum chain.
|
112
|
+
* That means that the block number returned for this is usable for event queries.
|
113
|
+
* This function will revert if the given node number does not exist.
|
114
|
+
* @dev This function is meant for internal use only and has no stability guarantees.
|
115
|
+
*/
|
116
|
+
function getNodeCreationBlockForLogLookup(uint64 nodeNum)
|
117
|
+
external
|
118
|
+
view
|
119
|
+
override
|
120
|
+
returns (uint256)
|
121
|
+
{
|
122
|
+
if (_hostChainIsArbitrum) {
|
123
|
+
uint256 blockNum = _nodeCreatedAtArbSysBlock[nodeNum];
|
124
|
+
require(blockNum > 0, "NO_NODE");
|
125
|
+
return blockNum;
|
126
|
+
} else {
|
127
|
+
Node storage node = getNodeStorage(nodeNum);
|
128
|
+
require(node.deadlineBlock != 0, "NO_NODE");
|
129
|
+
return node.createdAtBlock;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
95
133
|
/**
|
96
134
|
* @notice Check if the specified node has been staked on by the provided staker.
|
97
135
|
* Only accurate at the latest confirmed node and afterwards.
|
@@ -250,6 +288,9 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
250
288
|
__Pausable_init();
|
251
289
|
_nodes[GENESIS_NODE] = initialNode;
|
252
290
|
_firstUnresolvedNode = GENESIS_NODE + 1;
|
291
|
+
if (_hostChainIsArbitrum) {
|
292
|
+
_nodeCreatedAtArbSysBlock[GENESIS_NODE] = ArbSys(address(100)).arbBlockNumber();
|
293
|
+
}
|
253
294
|
}
|
254
295
|
|
255
296
|
/**
|
@@ -259,6 +300,9 @@ abstract contract RollupCore is IRollupCore, PausableUpgradeable {
|
|
259
300
|
function nodeCreated(Node memory node) internal {
|
260
301
|
_latestNodeCreated++;
|
261
302
|
_nodes[_latestNodeCreated] = node;
|
303
|
+
if (_hostChainIsArbitrum) {
|
304
|
+
_nodeCreatedAtArbSysBlock[_latestNodeCreated] = ArbSys(address(100)).arbBlockNumber();
|
305
|
+
}
|
262
306
|
}
|
263
307
|
|
264
308
|
/// @notice Reject the next unresolved node
|
@@ -52,66 +52,55 @@ contract RollupCreator is Ownable {
|
|
52
52
|
emit TemplatesUpdated();
|
53
53
|
}
|
54
54
|
|
55
|
-
struct CreateRollupFrame {
|
56
|
-
ProxyAdmin admin;
|
57
|
-
IBridge bridge;
|
58
|
-
ISequencerInbox sequencerInbox;
|
59
|
-
IInbox inbox;
|
60
|
-
IRollupEventInbox rollupEventInbox;
|
61
|
-
IOutbox outbox;
|
62
|
-
RollupProxy rollup;
|
63
|
-
}
|
64
|
-
|
65
55
|
// After this setup:
|
66
56
|
// Rollup should be the owner of bridge
|
67
57
|
// RollupOwner should be the owner of Rollup's ProxyAdmin
|
68
58
|
// RollupOwner should be the owner of Rollup
|
69
59
|
// Bridge should have a single inbox and outbox
|
70
|
-
function createRollup(Config memory config
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
frame.admin = new ProxyAdmin();
|
60
|
+
function createRollup(Config memory config) external returns (address) {
|
61
|
+
ProxyAdmin proxyAdmin = new ProxyAdmin();
|
62
|
+
|
63
|
+
// Create the rollup proxy to figure out the address and initialize it later
|
64
|
+
RollupProxy rollup = new RollupProxy{salt: keccak256(abi.encode(config))}();
|
76
65
|
|
77
66
|
(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
67
|
+
IBridge bridge,
|
68
|
+
ISequencerInbox sequencerInbox,
|
69
|
+
IInbox inbox,
|
70
|
+
IRollupEventInbox rollupEventInbox,
|
71
|
+
IOutbox outbox
|
83
72
|
) = bridgeCreator.createBridge(
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
73
|
+
address(proxyAdmin),
|
74
|
+
address(rollup),
|
75
|
+
config.sequencerInboxMaxTimeVariation
|
76
|
+
);
|
88
77
|
|
89
|
-
|
78
|
+
proxyAdmin.transferOwnership(config.owner);
|
90
79
|
|
91
80
|
IChallengeManager challengeManager = IChallengeManager(
|
92
81
|
address(
|
93
82
|
new TransparentUpgradeableProxy(
|
94
83
|
address(challengeManagerTemplate),
|
95
|
-
address(
|
84
|
+
address(proxyAdmin),
|
96
85
|
""
|
97
86
|
)
|
98
87
|
)
|
99
88
|
);
|
100
89
|
challengeManager.initialize(
|
101
|
-
IChallengeResultReceiver(
|
102
|
-
|
103
|
-
|
90
|
+
IChallengeResultReceiver(address(rollup)),
|
91
|
+
sequencerInbox,
|
92
|
+
bridge,
|
104
93
|
osp
|
105
94
|
);
|
106
95
|
|
107
|
-
|
96
|
+
rollup.initializeProxy(
|
108
97
|
config,
|
109
98
|
ContractDependencies({
|
110
|
-
bridge:
|
111
|
-
sequencerInbox:
|
112
|
-
inbox:
|
113
|
-
outbox:
|
114
|
-
rollupEventInbox:
|
99
|
+
bridge: bridge,
|
100
|
+
sequencerInbox: sequencerInbox,
|
101
|
+
inbox: inbox,
|
102
|
+
outbox: outbox,
|
103
|
+
rollupEventInbox: rollupEventInbox,
|
115
104
|
challengeManager: challengeManager,
|
116
105
|
rollupAdminLogic: rollupAdminLogic,
|
117
106
|
rollupUserLogic: rollupUserLogic,
|
@@ -119,15 +108,14 @@ contract RollupCreator is Ownable {
|
|
119
108
|
validatorWalletCreator: validatorWalletCreator
|
120
109
|
})
|
121
110
|
);
|
122
|
-
require(address(frame.rollup) == expectedRollupAddr, "WRONG_ROLLUP_ADDR");
|
123
111
|
|
124
112
|
emit RollupCreated(
|
125
|
-
address(
|
126
|
-
address(
|
127
|
-
address(
|
128
|
-
address(
|
129
|
-
address(
|
113
|
+
address(rollup),
|
114
|
+
address(inbox),
|
115
|
+
address(proxyAdmin),
|
116
|
+
address(sequencerInbox),
|
117
|
+
address(bridge)
|
130
118
|
);
|
131
|
-
return address(
|
119
|
+
return address(rollup);
|
132
120
|
}
|
133
121
|
}
|
@@ -30,8 +30,13 @@ contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, Delegat
|
|
30
30
|
rollup = address(_bridge.rollup());
|
31
31
|
}
|
32
32
|
|
33
|
-
function rollupInitialized(uint256 chainId
|
34
|
-
|
33
|
+
function rollupInitialized(uint256 chainId, string calldata chainConfig)
|
34
|
+
external
|
35
|
+
override
|
36
|
+
onlyRollup
|
37
|
+
{
|
38
|
+
require(bytes(chainConfig).length > 0, "EMPTY_CHAIN_CONFIG");
|
39
|
+
bytes memory initMsg = abi.encodePacked(chainId, uint8(0), chainConfig);
|
35
40
|
uint256 num = bridge.enqueueDelayedMessage(
|
36
41
|
INITIALIZATION_MSG_TYPE,
|
37
42
|
address(0),
|
package/src/rollup/RollupLib.sol
CHANGED
@@ -8,13 +8,27 @@ import "../libraries/AdminFallbackProxy.sol";
|
|
8
8
|
import "./IRollupLogic.sol";
|
9
9
|
|
10
10
|
contract RollupProxy is AdminFallbackProxy {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
address(
|
16
|
-
|
17
|
-
|
18
|
-
)
|
19
|
-
|
11
|
+
function initializeProxy(Config memory config, ContractDependencies memory connectedContracts)
|
12
|
+
external
|
13
|
+
{
|
14
|
+
if (
|
15
|
+
_getAdmin() == address(0) &&
|
16
|
+
_getImplementation() == address(0) &&
|
17
|
+
_getSecondaryImplementation() == address(0)
|
18
|
+
) {
|
19
|
+
_initialize(
|
20
|
+
address(connectedContracts.rollupAdminLogic),
|
21
|
+
abi.encodeWithSelector(
|
22
|
+
IRollupAdmin.initialize.selector,
|
23
|
+
config,
|
24
|
+
connectedContracts
|
25
|
+
),
|
26
|
+
address(connectedContracts.rollupUserLogic),
|
27
|
+
abi.encodeWithSelector(IRollupUserAbs.initialize.selector, config.stakeToken),
|
28
|
+
config.owner
|
29
|
+
);
|
30
|
+
} else {
|
31
|
+
_fallback();
|
32
|
+
}
|
33
|
+
}
|
20
34
|
}
|