@arbitrum/nitro-contracts 1.0.2 → 1.1.0-alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|