rocketh 0.14.9 → 0.15.0-testing.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.
@@ -1,6 +1,8 @@
1
1
  import type {Chain} from 'viem/chains';
2
2
  import * as chains from 'viem/chains';
3
3
  import {ResolvedConfig} from '../types.js';
4
+ import {kebabCase} from 'change-case';
5
+ import {ChainInfo} from '../../executor/types.js';
4
6
 
5
7
  export type ChainType = 'zksync' | 'op-stack' | 'celo' | 'default';
6
8
 
@@ -27,10 +29,10 @@ const chainTypesByNames: {[chainExportName: string]: ChainType} = {
27
29
 
28
30
  export const chainTypes: {[chainId: string]: ChainType} = {};
29
31
 
30
- export const chainById: {[chainId: string]: Chain} = {};
31
- const allChains = (chains as any).default || chains;
32
+ export const chainById: {[chainId: string]: ChainInfo} = {};
33
+ export const allChains = (chains as any).default || chains;
32
34
  for (const key of Object.keys(allChains)) {
33
- const chain = (allChains as any)[key] as Chain;
35
+ const chain = (allChains as any)[key] as ChainInfo;
34
36
  const chainId = chain.id.toString();
35
37
  const specificChainType = chainTypesByNames[key];
36
38
  if (specificChainType) {
@@ -39,28 +41,37 @@ for (const key of Object.keys(allChains)) {
39
41
  chainById[chainId] = chain;
40
42
  }
41
43
 
42
- export function getChain(id: string): Chain | undefined {
43
- const chain = chainById[id];
44
+ export const chainByCanonicalName: {[canonicalName: string]: ChainInfo} = {};
45
+ for (const key of Object.keys(allChains)) {
46
+ const chain = (allChains as any)[key] as ChainInfo;
47
+ const canonicalName = kebabCase(chain.name);
48
+ chainByCanonicalName[canonicalName] = chain;
49
+ }
50
+
51
+ export function getChain(id: string | number): ChainInfo | undefined {
52
+ const chain = chainById['' + id];
53
+
54
+ return chain;
55
+ }
44
56
 
57
+ export function getChainByName(name: string): ChainInfo | undefined {
58
+ const chain = chainByCanonicalName[name];
45
59
  return chain;
46
60
  }
47
61
 
48
- export function getChainWithConfig(id: string, config: ResolvedConfig): Chain {
62
+ export function getChainWithConfig(id: string, config: ResolvedConfig): ChainInfo {
49
63
  const chain = getChain(id);
50
64
 
51
65
  if (!chain) {
52
- if (config.network.publicInfo) {
53
- return {
54
- id: parseInt(id),
55
- ...config.network.publicInfo,
56
- };
66
+ if (config.target.chain) {
67
+ return config.target.chain;
57
68
  }
58
- console.error(`network ${config.network.name} has no public info`);
69
+ console.error(`network ${config.target.name} has no public info`);
59
70
  let nodeUrl: string | undefined;
60
- if (!config.network.nodeUrl) {
61
- console.error(`no nodeUrl found either for ${config.network.name}`);
71
+ if (!config.target.nodeUrl) {
72
+ console.error(`no nodeUrl found either for ${config.target.name}`);
62
73
  } else {
63
- nodeUrl = config.network.nodeUrl;
74
+ nodeUrl = config.target.nodeUrl;
64
75
  }
65
76
  return {
66
77
  id: parseInt(id),
@@ -75,6 +86,7 @@ export function getChainWithConfig(id: string, config: ResolvedConfig): Chain {
75
86
  http: nodeUrl ? [nodeUrl] : [],
76
87
  },
77
88
  },
89
+ chainType: 'default',
78
90
  };
79
91
  }
80
92
  return chain;
@@ -9,16 +9,25 @@ import type {
9
9
  Environment,
10
10
  JSONTypePlusBigInt,
11
11
  ResolvedConfig,
12
+ TargetConfig,
12
13
  UnknownDeployments,
13
14
  UnresolvedNetworkSpecificData,
14
15
  UnresolvedUnknownNamedAccounts,
15
16
  } from '../environment/types.js';
16
17
  import {createEnvironment, SignerProtocolFunction} from '../environment/index.js';
17
- import {DeployScriptFunction, DeployScriptModule, EnhancedDeployScriptFunction, EnhancedEnvironment} from './types.js';
18
+ import {
19
+ ChainInfo,
20
+ DeployScriptFunction,
21
+ DeployScriptModule,
22
+ EnhancedDeployScriptFunction,
23
+ EnhancedEnvironment,
24
+ } from './types.js';
18
25
  import {withEnvironment} from '../utils/extensions.js';
19
26
  import {logger, setLogLevel, spin} from '../internal/logging.js';
20
27
  import {getRoughGasPriceEstimate} from '../utils/eth.js';
21
28
  import {traverseMultipleDirectory} from '../utils/fs.js';
29
+ import {getChain, getChainByName} from '../environment/utils/chains.js';
30
+ import {JSONRPCHTTPProvider} from 'eip-1193-jsonrpc-provider';
22
31
 
23
32
  // @ts-ignore
24
33
  const tsImport = (path: string, opts: any) => (typeof Bun !== 'undefined' ? import(path) : tsImport_(path, opts));
@@ -147,7 +156,7 @@ export type UntypedEIP1193Provider = {
147
156
  };
148
157
 
149
158
  export type ConfigOptions<Extra extends Record<string, unknown> = Record<string, unknown>> = {
150
- network?: string | {fork: string};
159
+ target?: string | {fork: string};
151
160
  deployments?: string;
152
161
  scripts?: string | string[];
153
162
  tags?: string;
@@ -181,35 +190,30 @@ export type DeterministicDeploymentInfo =
181
190
  create3?: Create3DeterministicDeploymentInfo;
182
191
  };
183
192
 
184
- type Networks = {
185
- [name: string]: {
186
- rpcUrl?: string;
187
- tags?: string[];
188
- deterministicDeployment?: DeterministicDeploymentInfo;
189
- scripts?: string | string[];
190
- publicInfo?: {
191
- name: string;
192
- nativeCurrency: {
193
- name: string;
194
- symbol: string;
195
- decimals: number;
196
- };
197
- rpcUrls: {
198
- default: {
199
- http: string[];
200
- };
201
- };
202
- chainType?: string;
203
- };
204
- pollingInterval?: number;
205
- properties?: Record<string, JSONTypePlusBigInt>;
206
- };
193
+ export type ChainUserConfig = {
194
+ rpcUrl?: string;
195
+ tags?: string[];
196
+ deterministicDeployment?: DeterministicDeploymentInfo;
197
+ info?: ChainInfo;
198
+ pollingInterval?: number;
199
+ properties?: Record<string, JSONTypePlusBigInt>;
200
+ };
201
+
202
+ export type DeploymentTargetConfig = {
203
+ chainId: number;
204
+ scripts?: string | string[];
205
+ overrides: Omit<ChainUserConfig, 'info'>;
206
+ };
207
+
208
+ export type Chains = {
209
+ [idOrName: number | string]: ChainUserConfig;
207
210
  };
208
211
  export type UserConfig<
209
212
  NamedAccounts extends UnresolvedUnknownNamedAccounts = UnresolvedUnknownNamedAccounts,
210
213
  Data extends UnresolvedNetworkSpecificData = UnresolvedNetworkSpecificData
211
214
  > = {
212
- networks?: Networks;
215
+ targets: {[name: string]: DeploymentTargetConfig};
216
+ chains?: Chains;
213
217
  deployments?: string;
214
218
  scripts?: string | string[];
215
219
  accounts?: NamedAccounts;
@@ -218,11 +222,14 @@ export type UserConfig<
218
222
  defaultPollingInterval?: number;
219
223
  };
220
224
 
221
- export function transformUserConfig<
225
+ export async function transformUserConfig<
222
226
  NamedAccounts extends UnresolvedUnknownNamedAccounts = UnresolvedUnknownNamedAccounts,
223
227
  Data extends UnresolvedNetworkSpecificData = UnresolvedNetworkSpecificData,
224
228
  Extra extends Record<string, unknown> = Record<string, unknown>
225
- >(configFile: UserConfig<NamedAccounts, Data> | undefined, options: ConfigOptions<Extra>): Config<NamedAccounts, Data> {
229
+ >(
230
+ configFile: UserConfig<NamedAccounts, Data> | undefined,
231
+ options: ConfigOptions<Extra>
232
+ ): Promise<Config<NamedAccounts, Data>> {
226
233
  if (configFile) {
227
234
  if (!options.deployments && configFile.deployments) {
228
235
  options.deployments = configFile.deployments;
@@ -232,121 +239,146 @@ export function transformUserConfig<
232
239
  }
233
240
  }
234
241
 
235
- const fromEnv = process.env['ETH_NODE_URI_' + options.network];
236
- const fork = typeof options.network !== 'string';
237
- let networkName = 'memory';
238
- if (options.network) {
239
- if (typeof options.network === 'string') {
240
- networkName = options.network;
241
- } else if ('fork' in options.network) {
242
- networkName = options.network.fork;
242
+ const targetProvided = options.target || (options as any).network; // fallback on network
243
+ const fork = typeof targetProvided !== 'string';
244
+ let targetName = 'memory';
245
+ if (options.target) {
246
+ if (typeof options.target === 'string') {
247
+ targetName = options.target;
248
+ } else if ('fork' in options.target) {
249
+ targetName = options.target.fork;
243
250
  }
244
251
  }
245
252
 
246
- let defaultTags: string[] = [];
253
+ let chainInfo: ChainInfo;
247
254
 
248
- let networkTags: string[] =
249
- (configFile?.networks && (configFile?.networks[networkName]?.tags || configFile?.networks['default']?.tags)) ||
250
- defaultTags;
255
+ let chainId: number;
251
256
 
252
- let networkScripts: string | string[] | undefined =
253
- (configFile?.networks &&
254
- (configFile?.networks[networkName]?.scripts || configFile?.networks['default']?.scripts)) ||
255
- undefined;
257
+ if (configFile?.targets?.[targetName]) {
258
+ chainId = configFile.targets[targetName].chainId;
259
+ } else {
260
+ const chainFound = getChainByName(targetName);
261
+ if (chainFound) {
262
+ chainInfo = chainFound;
263
+ chainId = chainInfo.id;
264
+ } else {
265
+ if (options.provider) {
266
+ const chainIdAsHex = await (options.provider as EIP1193ProviderWithoutEvents).request({method: 'eth_chainId'});
267
+ chainId = Number(chainIdAsHex);
268
+ } else {
269
+ throw new Error(`target ${targetName} is unknown`);
270
+ }
271
+ }
272
+ }
273
+
274
+ const chainConfigFromChainId = configFile?.chains?.[chainId];
275
+ const chainConfigFromChainName = configFile?.chains?.[targetName];
276
+ if (chainConfigFromChainId && chainConfigFromChainName) {
277
+ throw new Error(
278
+ `conflicting config for chain, choose to configure via its chainId (${chainId}) or via its name ${targetName} but not both`
279
+ );
280
+ }
281
+ const chainConfig = chainConfigFromChainId || chainConfigFromChainName;
282
+
283
+ const targetConfig = configFile?.targets?.[targetName];
284
+ const actualChainConfig = targetConfig?.overrides
285
+ ? {
286
+ ...chainConfig,
287
+ ...targetConfig.overrides,
288
+ properties: {
289
+ ...chainConfig?.properties,
290
+ ...targetConfig.overrides.properties,
291
+ },
292
+ }
293
+ : chainConfig;
294
+
295
+ const defaultTags: string[] = [];
296
+
297
+ const chainFound = actualChainConfig?.info || getChain(chainId);
298
+ if (chainFound) {
299
+ chainInfo = chainFound;
300
+ } else {
301
+ throw new Error(`chain with id ${chainId} has no chainInfo associated with it`);
302
+ }
303
+ if (chainInfo.testnet) {
304
+ defaultTags.push('testnet');
305
+ }
306
+
307
+ let targetTags: string[] = actualChainConfig?.tags || defaultTags;
308
+
309
+ let networkScripts: string | string[] | undefined = targetConfig?.scripts;
256
310
 
257
311
  // no default for publicInfo
258
- const publicInfo = configFile?.networks ? configFile?.networks[networkName]?.publicInfo : undefined;
259
312
  const defaultPollingInterval = configFile?.defaultPollingInterval;
260
- const pollingInterval = configFile?.networks?.[networkName]?.pollingInterval;
261
- const deterministicDeployment = configFile?.networks?.[networkName]?.deterministicDeployment;
262
- const properties = configFile?.networks ? configFile?.networks[networkName]?.properties : undefined;
313
+ const pollingInterval = actualChainConfig?.pollingInterval;
314
+ const deterministicDeployment = actualChainConfig?.deterministicDeployment;
315
+ const properties = actualChainConfig?.properties;
316
+
317
+ let resolvedTargetConfig: TargetConfig;
318
+
263
319
  if (!options.provider) {
320
+ let rpcURL = actualChainConfig?.rpcUrl;
321
+ if (!rpcURL) {
322
+ rpcURL = chainInfo.rpcUrls.default.http[0];
323
+ }
324
+
325
+ const fromEnv = process.env['ETH_NODE_URI_' + targetName];
264
326
  let nodeUrl: string;
265
- if (typeof fromEnv === 'string') {
327
+ if (typeof fromEnv === 'string' && fromEnv) {
266
328
  nodeUrl = fromEnv;
267
329
  } else {
268
- if (configFile) {
269
- const network = configFile.networks && configFile.networks[networkName];
270
- if (network && network.rpcUrl) {
271
- nodeUrl = network.rpcUrl;
272
- } else {
273
- if (options?.ignoreMissingRPC) {
274
- nodeUrl = '';
275
- } else {
276
- if (options.network === 'localhost') {
277
- nodeUrl = 'http://127.0.0.1:8545';
278
- } else {
279
- console.error(`network "${options.network}" is not configured. Please add it to the rocketh.js/ts file`);
280
- process.exit(1);
281
- }
282
- }
283
- }
330
+ if (rpcURL) {
331
+ nodeUrl = rpcURL;
332
+ } else if (options?.ignoreMissingRPC) {
333
+ nodeUrl = '';
334
+ } else if (options.target === 'localhost') {
335
+ nodeUrl = 'http://127.0.0.1:8545';
284
336
  } else {
285
- if (options?.ignoreMissingRPC) {
286
- nodeUrl = '';
287
- } else {
288
- if (options.network === 'localhost') {
289
- nodeUrl = 'http://127.0.0.1:8545';
290
- } else {
291
- console.error(`network "${options.network}" is not configured. Please add it to the rocketh.js/ts file`);
292
- process.exit(1);
293
- }
294
- }
337
+ console.error(`network "${options.target}" is not configured. Please add it to the rocketh.js/ts file`);
338
+ process.exit(1);
295
339
  }
296
340
  }
297
341
 
298
- return {
299
- network: {
300
- nodeUrl,
301
- name: networkName,
302
- tags: networkTags,
303
- fork,
304
- deterministicDeployment,
305
- scripts: networkScripts,
306
- publicInfo,
307
- pollingInterval,
308
- properties,
309
- },
310
- deployments: options.deployments,
311
- saveDeployments: options.saveDeployments,
312
- scripts: options.scripts,
313
- data: configFile?.data,
314
- tags: typeof options.tags === 'undefined' ? undefined : options.tags.split(','),
315
- logLevel: options.logLevel,
316
- askBeforeProceeding: options.askBeforeProceeding,
317
- reportGasUse: options.reportGasUse,
318
- accounts: configFile?.accounts,
319
- signerProtocols: configFile?.signerProtocols,
320
- extra: options.extra,
321
- defaultPollingInterval,
342
+ resolvedTargetConfig = {
343
+ nodeUrl,
344
+ name: targetName,
345
+ tags: targetTags,
346
+ fork,
347
+ deterministicDeployment,
348
+ scripts: networkScripts,
349
+ chainInfo,
350
+ pollingInterval,
351
+ properties,
322
352
  };
323
353
  } else {
324
- return {
325
- network: {
326
- provider: options.provider as EIP1193ProviderWithoutEvents,
327
- name: networkName,
328
- tags: networkTags,
329
- fork,
330
- deterministicDeployment,
331
- scripts: networkScripts,
332
- publicInfo,
333
- pollingInterval,
334
- properties,
335
- },
336
- deployments: options.deployments,
337
- saveDeployments: options.saveDeployments,
338
- scripts: options.scripts,
339
- data: configFile?.data,
340
- tags: typeof options.tags === 'undefined' ? undefined : options.tags.split(','),
341
- logLevel: options.logLevel,
342
- askBeforeProceeding: options.askBeforeProceeding,
343
- reportGasUse: options.reportGasUse,
344
- accounts: configFile?.accounts,
345
- signerProtocols: configFile?.signerProtocols,
346
- extra: options.extra,
347
- defaultPollingInterval,
354
+ resolvedTargetConfig = {
355
+ provider: options.provider as EIP1193ProviderWithoutEvents,
356
+ name: targetName,
357
+ tags: targetTags,
358
+ fork,
359
+ deterministicDeployment,
360
+ scripts: networkScripts,
361
+ chainInfo,
362
+ pollingInterval,
363
+ properties,
348
364
  };
349
365
  }
366
+
367
+ return {
368
+ target: resolvedTargetConfig,
369
+ deployments: options.deployments,
370
+ saveDeployments: options.saveDeployments,
371
+ scripts: options.scripts,
372
+ data: configFile?.data,
373
+ tags: typeof options.tags === 'undefined' ? undefined : options.tags.split(','),
374
+ logLevel: options.logLevel,
375
+ askBeforeProceeding: options.askBeforeProceeding,
376
+ reportGasUse: options.reportGasUse,
377
+ accounts: configFile?.accounts,
378
+ signerProtocols: configFile?.signerProtocols,
379
+ extra: options.extra,
380
+ defaultPollingInterval,
381
+ };
350
382
  }
351
383
 
352
384
  export async function readConfig<
@@ -423,26 +455,26 @@ export function resolveConfig<
423
455
  } as const;
424
456
 
425
457
  const defaultPollingInterval = config.defaultPollingInterval || 1;
426
- const networkPollingInterval = config.network.pollingInterval || defaultPollingInterval;
458
+ const networkPollingInterval = config.target.pollingInterval || defaultPollingInterval;
427
459
 
428
460
  let deterministicDeployment: {
429
461
  create2: Create2DeterministicDeploymentInfo;
430
462
  create3: Create3DeterministicDeploymentInfo;
431
463
  } = {
432
464
  create2: (() => {
433
- if (!config.network.deterministicDeployment) return create2Info;
465
+ if (!config.target.deterministicDeployment) return create2Info;
434
466
  if (
435
- !('create3' in config.network.deterministicDeployment) &&
436
- !('create2' in config.network.deterministicDeployment)
467
+ !('create3' in config.target.deterministicDeployment) &&
468
+ !('create2' in config.target.deterministicDeployment)
437
469
  )
438
470
  return create2Info;
439
- return config.network.deterministicDeployment.create2 || create2Info;
471
+ return config.target.deterministicDeployment.create2 || create2Info;
440
472
  })(),
441
473
  create3:
442
- config.network.deterministicDeployment &&
443
- 'create3' in config.network.deterministicDeployment &&
444
- config.network.deterministicDeployment.create3
445
- ? config.network.deterministicDeployment.create3
474
+ config.target.deterministicDeployment &&
475
+ 'create3' in config.target.deterministicDeployment &&
476
+ config.target.deterministicDeployment.create3
477
+ ? config.target.deterministicDeployment.create3
446
478
  : create3Info,
447
479
  };
448
480
 
@@ -455,20 +487,20 @@ export function resolveConfig<
455
487
  }
456
488
  }
457
489
 
458
- if (config.network.scripts) {
459
- if (typeof config.network.scripts === 'string') {
460
- scripts = [config.network.scripts];
490
+ if (config.target.scripts) {
491
+ if (typeof config.target.scripts === 'string') {
492
+ scripts = [config.target.scripts];
461
493
  } else {
462
- scripts = config.network.scripts;
494
+ scripts = config.target.scripts;
463
495
  }
464
496
  }
465
497
  const resolvedConfig: ResolvedConfig<NamedAccounts, Data> = {
466
498
  ...config,
467
- network: {...config.network, deterministicDeployment, pollingInterval: networkPollingInterval},
499
+ target: {...config.target, deterministicDeployment, pollingInterval: networkPollingInterval},
468
500
  deployments: config.deployments || 'deployments',
469
501
  scripts,
470
502
  tags: config.tags || [],
471
- networkTags: config.networkTags || [],
503
+ targetTags: config.targetTags || [],
472
504
  saveDeployments: config.saveDeployments,
473
505
  accounts: config.accounts || ({} as NamedAccounts),
474
506
  data: config.data || ({} as Data),
@@ -1,5 +1,7 @@
1
+ import {Address} from 'abitype';
1
2
  import type {
2
3
  Environment,
4
+ JSONTypePlusBigInt,
3
5
  UnknownDeployments,
4
6
  UnresolvedNetworkSpecificData,
5
7
  UnresolvedUnknownNamedAccounts,
@@ -80,3 +82,95 @@ export type EnhancedDeployScriptFunction<
80
82
  env: EnhancedEnvironment<NamedAccounts, Data, Deployments, Functions, Extra>,
81
83
  args?: ArgumentsTypes
82
84
  ) => Promise<void | boolean>;
85
+
86
+ type ChainBlockExplorer = {
87
+ name: string;
88
+ url: string;
89
+ apiUrl?: string | undefined;
90
+ };
91
+ type ChainContract = {
92
+ address: Address;
93
+ blockCreated?: number | undefined;
94
+ };
95
+
96
+ type ChainNativeCurrency = {
97
+ name: string;
98
+ /** 2-6 characters long */
99
+ symbol: string;
100
+ decimals: number;
101
+ };
102
+
103
+ type ChainRpcUrls = {
104
+ http: readonly string[];
105
+ webSocket?: readonly string[] | undefined;
106
+ };
107
+
108
+ /**
109
+ * @description Combines members of an intersection into a readable type.
110
+ *
111
+ * @see {@link https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg}
112
+ * @example
113
+ * Prettify<{ a: string } & { b: string } & { c: number, d: bigint }>
114
+ * => { a: string, b: string, c: number, d: bigint }
115
+ */
116
+ type Prettify<T> = {
117
+ [K in keyof T]: T[K];
118
+ } & {};
119
+
120
+ export type ChainInfo = {
121
+ /** ID in number form */
122
+ id: number;
123
+ /** Human-readable name */
124
+ name: string;
125
+ /** Collection of block explorers */
126
+ blockExplorers?:
127
+ | {
128
+ [key: string]: ChainBlockExplorer;
129
+ default: ChainBlockExplorer;
130
+ }
131
+ | undefined;
132
+ /** Collection of contracts */
133
+ contracts?:
134
+ | Prettify<
135
+ {
136
+ [key: string]: ChainContract | {[sourceId: number]: ChainContract | undefined} | undefined;
137
+ } & {
138
+ ensRegistry?: ChainContract | undefined;
139
+ ensUniversalResolver?: ChainContract | undefined;
140
+ multicall3?: ChainContract | undefined;
141
+ }
142
+ >
143
+ | undefined;
144
+ /** Currency used by chain */
145
+ nativeCurrency: ChainNativeCurrency;
146
+ /** Collection of RPC endpoints */
147
+ rpcUrls: {
148
+ [key: string]: ChainRpcUrls;
149
+ default: ChainRpcUrls;
150
+ };
151
+ /** Source Chain ID (ie. the L1 chain) */
152
+ sourceId?: number | undefined;
153
+ /** Flag for test networks */
154
+ testnet?: boolean | undefined;
155
+
156
+ chainType: 'zksync' | 'op-stack' | 'celo' | 'default';
157
+
158
+ genesisHash?: string;
159
+
160
+ properties?: Record<string, JSONTypePlusBigInt>;
161
+
162
+ // this will bring in the following when reconstructed from the data above
163
+
164
+ // /** Custom chain data. */
165
+ // custom?: any;
166
+
167
+ // /**
168
+ // * Modifies how chain data structures (ie. Blocks, Transactions, etc)
169
+ // * are formatted & typed.
170
+ // */
171
+ // formatters?: any | undefined;
172
+ // /** Modifies how data (ie. Transactions) is serialized. */
173
+ // serializers?: any | undefined;
174
+ // /** Modifies how fees are derived. */
175
+ // fees?: any | undefined;
176
+ };