1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
import { ethers } from 'ethers'
/**
* Core required deployment configuration.
*/
interface RequiredDeployConfig {
/**
* Number of confirmations to wait when deploying contracts.
*/
numDeployConfirmations?: number
/**
* Address that will own the entire system on L1 when the deploy is complete.
*/
finalSystemOwner?: string
/**
* Address that will own the entire system on L1 during the deployment process. This address will
* not own the system after the deployment is complete, ownership will be transferred to the
* final system owner.
*/
controller?: string
/**
* The L2 genesis script uses this to fill the storage of the L1Block info predeploy. The rollup
* config script uses this to fill the L1 genesis info for the rollup. The Output oracle deploy
* script may use it if the L2 starting timestamp is undefined, assuming the L2 genesis is set up
* with this.
*/
l1StartingBlockTag: string
/**
* Chain ID for the L1 network.
*/
l1ChainID: number
/**
* Chain ID for the L2 network.
*/
l2ChainID: number
/**
* Number of seconds in between each L2 block.
*/
l2BlockTime: number
/**
* Sequencer batches may not be more than maxSequencerDrift seconds after the L1 timestamp of the
* end of the sequencing window end.
*/
maxSequencerDrift: number
/**
* Number of L1 blocks per sequencing window.
*/
sequencerWindowSize: number
/**
* Number of L1 blocks that a frame stays valid when included in L1.
*/
channelTimeout: number
/**
* Address of the key the sequencer uses to sign blocks on the P2P layer.
*/
p2pSequencerAddress: string
/**
* L1 address that batches are sent to.
*/
batchInboxAddress: string
/**
* Acceptable batch-sender address, to filter transactions going into the batchInboxAddress on L1 for data.
* Warning: this address is hardcoded now, but is intended to become governed via L1.
*/
batchSenderAddress: string
/**
* Output Oracle submission interval in L2 blocks.
*/
l2OutputOracleSubmissionInterval: number
/**
* Starting block number for the output oracle.
* Must be greater than or equal to the first Bedrock block. The first L2 output will correspond
* to this value plus the submission interval.
*/
l2OutputOracleStartingBlockNumber?: number
/**
* Starting timestamp for the output oracle.
* MUST be the same as the timestamp of the L2OO start block.
*/
l2OutputOracleStartingTimestamp?: number
/**
* Address of the L2 output oracle proposer.
*/
l2OutputOracleProposer: string
/**
* Address of the L2 output oracle challenger.
*/
l2OutputOracleChallenger: string
/**
* ERC20 symbol used for the L2 GovernanceToken.
*/
governanceTokenSymbol: string
/**
* ERC20 name used for the L2 GovernanceToken.
*/
governanceTokenName: string
/**
* Owner of the L2 GovernanceToken. Has mint/burn capability.
*/
governanceTokenOwner: string
/**
* Output finalization period in seconds.
*/
finalizationPeriodSeconds: number
}
/**
* Optional deployment configuration when spinning up an L1 network as part of the deployment.
*/
interface OptionalL1DeployConfig {
cliqueSignerAddress: string
l1BlockTime: number
l1GenesisBlockNonce: string
l1GenesisBlockGasLimit: string
l1GenesisBlockDifficulty: string
l1GenesisBlockMixHash: string
l1GenesisBlockCoinbase: string
l1GenesisBlockNumber: string
l1GenesisBlockGasUsed: string
l1GenesisBlockParentHash: string
l1GenesisBlockBaseFeePerGas: string
}
/**
* Optional deployment configuration when spinning up an L2 network as part of the deployment.
*/
interface OptionalL2DeployConfig {
l2GenesisBlockNonce: string
l2GenesisBlockGasLimit: string
l2GenesisBlockDifficulty: string
l2GenesisBlockMixHash: string
l2GenesisBlockNumber: string
l2GenesisBlockGasUsed: string
l2GenesisBlockParentHash: string
l2GenesisBlockBaseFeePerGas: string
gasPriceOracleOverhead: number
gasPriceOracleScalar: number
}
/**
* Full deployment configuration.
*/
export type DeployConfig = RequiredDeployConfig &
Partial<OptionalL1DeployConfig> &
Partial<OptionalL2DeployConfig>
/**
* Deployment configuration specification for the hardhat plugin.
*/
export const deployConfigSpec: {
[K in keyof DeployConfig]: {
type: 'string' | 'number' | 'boolean' | 'address'
default?: any
}
} = {
numDeployConfirmations: {
type: 'number',
default: 1,
},
finalSystemOwner: {
type: 'address',
},
controller: {
type: 'address',
},
l1StartingBlockTag: {
type: 'string',
},
l1ChainID: {
type: 'number',
},
l2ChainID: {
type: 'number',
},
l2BlockTime: {
type: 'number',
},
maxSequencerDrift: {
type: 'number',
},
sequencerWindowSize: {
type: 'number',
},
channelTimeout: {
type: 'number',
},
p2pSequencerAddress: {
type: 'address',
},
batchInboxAddress: {
type: 'address',
},
batchSenderAddress: {
type: 'address',
},
l2OutputOracleSubmissionInterval: {
type: 'number',
},
l2OutputOracleStartingBlockNumber: {
type: 'number',
default: 0,
},
l2OutputOracleStartingTimestamp: {
type: 'number',
},
l2OutputOracleProposer: {
type: 'address',
},
l2OutputOracleChallenger: {
type: 'address',
},
finalizationPeriodSeconds: {
type: 'number',
default: 2,
},
cliqueSignerAddress: {
type: 'address',
default: ethers.constants.AddressZero,
},
l1BlockTime: {
type: 'number',
default: 15,
},
l1GenesisBlockNonce: {
type: 'string', // uint64
default: '0x0',
},
l1GenesisBlockGasLimit: {
type: 'string',
default: ethers.BigNumber.from(15_000_000).toHexString(),
},
l1GenesisBlockDifficulty: {
type: 'string', // uint256
default: '0x1',
},
l1GenesisBlockMixHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l1GenesisBlockCoinbase: {
type: 'address',
default: ethers.constants.AddressZero,
},
l1GenesisBlockNumber: {
type: 'string', // uint64
default: '0x0',
},
l1GenesisBlockGasUsed: {
type: 'string', // uint64
default: '0x0',
},
l1GenesisBlockParentHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l1GenesisBlockBaseFeePerGas: {
type: 'string', // uint256
default: ethers.BigNumber.from(1000_000_000).toHexString(), // 1 gwei
},
l2GenesisBlockNonce: {
type: 'string', // uint64
default: '0x0',
},
l2GenesisBlockGasLimit: {
type: 'string',
default: ethers.BigNumber.from(15_000_000).toHexString(),
},
l2GenesisBlockDifficulty: {
type: 'string', // uint256
default: '0x1',
},
l2GenesisBlockMixHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l2GenesisBlockNumber: {
type: 'string', // uint64
default: '0x0',
},
l2GenesisBlockGasUsed: {
type: 'string', // uint64
default: '0x0',
},
l2GenesisBlockParentHash: {
type: 'string', // bytes32
default: ethers.constants.HashZero,
},
l2GenesisBlockBaseFeePerGas: {
type: 'string', // uint256
default: ethers.BigNumber.from(1000_000_000).toHexString(), // 1 gwei
},
gasPriceOracleOverhead: {
type: 'number',
default: 2100,
},
gasPriceOracleScalar: {
type: 'number',
default: 1_000_000,
},
governanceTokenSymbol: {
type: 'string',
default: 'OP',
},
governanceTokenName: {
type: 'string',
default: 'Optimism',
},
governanceTokenOwner: {
type: 'string',
},
}