rocketh 0.17.13 → 0.17.15
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/README.md +340 -1
- package/dist/environment/chains.d.ts +7 -1
- package/dist/environment/chains.d.ts.map +1 -1
- package/dist/environment/chains.js +6 -3
- package/dist/environment/chains.js.map +1 -1
- package/dist/environment/index.js.map +1 -1
- package/dist/executor/index.d.ts.map +1 -1
- package/dist/executor/index.js +6 -3
- package/dist/executor/index.js.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
- package/src/environment/chains.ts +240 -0
- package/src/environment/index.ts +833 -0
- package/src/executor/index.ts +540 -0
- package/src/index.ts +20 -0
- package/src/internal/logging.ts +35 -0
- package/src/internal/types.ts +4 -0
- package/src/types.ts +3 -0
- package/src/utils/eth.ts +120 -0
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import {EIP1193ProviderWithoutEvents} from 'eip-1193';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
Environment,
|
|
5
|
+
ExecutionParams,
|
|
6
|
+
ResolvedExecutionParams,
|
|
7
|
+
UnknownDeployments,
|
|
8
|
+
UnresolvedNetworkSpecificData,
|
|
9
|
+
UnresolvedUnknownNamedAccounts,
|
|
10
|
+
DeployScriptModule,
|
|
11
|
+
EnhancedDeployScriptFunction,
|
|
12
|
+
EnhancedEnvironment,
|
|
13
|
+
ResolvedUserConfig,
|
|
14
|
+
ConfigOverrides,
|
|
15
|
+
UserConfig,
|
|
16
|
+
PromptExecutor,
|
|
17
|
+
DeploymentStore,
|
|
18
|
+
ModuleObject,
|
|
19
|
+
} from '@rocketh/core/types';
|
|
20
|
+
import {withEnvironment} from '@rocketh/core/environment';
|
|
21
|
+
import {
|
|
22
|
+
getChainConfigFromUserConfigAndDefaultChainInfo,
|
|
23
|
+
getDefaultChainInfoByName,
|
|
24
|
+
getDefaultChainInfoFromChainId,
|
|
25
|
+
} from '../environment/chains.js';
|
|
26
|
+
import {JSONRPCHTTPProvider} from 'eip-1193-jsonrpc-provider';
|
|
27
|
+
import {createEnvironment} from '../environment/index.js';
|
|
28
|
+
import {getRoughGasPriceEstimate} from '../utils/eth.js';
|
|
29
|
+
import {formatEther} from 'viem';
|
|
30
|
+
import {logger, spin} from '../internal/logging.js';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Setup function that creates the execute function for deploy scripts. It allow to specify a set of functions that will be available in the environment.
|
|
34
|
+
*
|
|
35
|
+
* @param functions - An object of utility functions that expect Environment as their first parameter
|
|
36
|
+
* @returns An execute function that provides an enhanced environment with curried functions
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const functions = {
|
|
41
|
+
* deploy: (env: Environment) => ((contractName: string, args: any[]) => Promise<void>),
|
|
42
|
+
* verify: (env: Environment) => ((address: string) => Promise<boolean>)
|
|
43
|
+
* };
|
|
44
|
+
*
|
|
45
|
+
* const {deployScript} = setup(functions);
|
|
46
|
+
*
|
|
47
|
+
* export default deployScript(async (env, args) => {
|
|
48
|
+
* // env now includes both the original environment AND the curried functions
|
|
49
|
+
* await env.deploy('MyContract', []); // No need to pass env
|
|
50
|
+
* await env.verify('0x123...'); // No need to pass env
|
|
51
|
+
*
|
|
52
|
+
* // Original environment properties are still available
|
|
53
|
+
* console.log(env.network.name);
|
|
54
|
+
* const deployment = env.get('MyContract');
|
|
55
|
+
* }, { tags: ['deploy'] });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function setupDeployScripts<
|
|
59
|
+
Extensions extends Record<string, (env: Environment<any, any, any>) => any> = {},
|
|
60
|
+
NamedAccounts extends UnresolvedUnknownNamedAccounts = UnresolvedUnknownNamedAccounts,
|
|
61
|
+
Data extends UnresolvedNetworkSpecificData = UnresolvedNetworkSpecificData,
|
|
62
|
+
Deployments extends UnknownDeployments = UnknownDeployments,
|
|
63
|
+
Extra extends Record<string, unknown> = Record<string, unknown>,
|
|
64
|
+
>(
|
|
65
|
+
extensions: Extensions,
|
|
66
|
+
): {
|
|
67
|
+
deployScript<ArgumentsType = undefined>(
|
|
68
|
+
callback: EnhancedDeployScriptFunction<NamedAccounts, Data, ArgumentsType, Deployments, Extensions>,
|
|
69
|
+
options: {tags?: string[]; dependencies?: string[]; id?: string; runAtTheEnd?: boolean},
|
|
70
|
+
): DeployScriptModule<NamedAccounts, Data, ArgumentsType, Deployments, Extra>;
|
|
71
|
+
} {
|
|
72
|
+
function enhancedExecute<ArgumentsType = undefined>(
|
|
73
|
+
callback: EnhancedDeployScriptFunction<NamedAccounts, Data, ArgumentsType, Deployments, Extensions>,
|
|
74
|
+
options: {tags?: string[]; dependencies?: string[]; id?: string; runAtTheEnd?: boolean},
|
|
75
|
+
): DeployScriptModule<NamedAccounts, Data, ArgumentsType, Deployments, Extra> {
|
|
76
|
+
const scriptModule: DeployScriptModule<NamedAccounts, Data, ArgumentsType, Deployments, Extra> = (
|
|
77
|
+
env: Environment<NamedAccounts, Data, Deployments, Extra>,
|
|
78
|
+
args?: ArgumentsType,
|
|
79
|
+
) => {
|
|
80
|
+
// Create the enhanced environment by combining the original environment with extensions
|
|
81
|
+
const curriedFunctions = withEnvironment(env, extensions);
|
|
82
|
+
const enhancedEnv = Object.assign(
|
|
83
|
+
Object.create(Object.getPrototypeOf(env)),
|
|
84
|
+
env,
|
|
85
|
+
curriedFunctions,
|
|
86
|
+
) as EnhancedEnvironment<NamedAccounts, Data, Deployments, Extensions, Extra>;
|
|
87
|
+
|
|
88
|
+
return callback(enhancedEnv, args);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
scriptModule.tags = options.tags;
|
|
92
|
+
scriptModule.dependencies = options.dependencies;
|
|
93
|
+
scriptModule.id = options.id;
|
|
94
|
+
scriptModule.runAtTheEnd = options.runAtTheEnd;
|
|
95
|
+
|
|
96
|
+
return scriptModule;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
deployScript: enhancedExecute,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function resolveConfig<
|
|
105
|
+
NamedAccounts extends UnresolvedUnknownNamedAccounts = UnresolvedUnknownNamedAccounts,
|
|
106
|
+
Data extends UnresolvedNetworkSpecificData = UnresolvedNetworkSpecificData,
|
|
107
|
+
>(configFile: UserConfig, overrides?: ConfigOverrides): ResolvedUserConfig<NamedAccounts, Data> {
|
|
108
|
+
const config = {
|
|
109
|
+
deployments: 'deployments',
|
|
110
|
+
defaultPollingInterval: 1,
|
|
111
|
+
...configFile,
|
|
112
|
+
scripts: configFile?.scripts
|
|
113
|
+
? typeof configFile.scripts === 'string'
|
|
114
|
+
? [configFile.scripts]
|
|
115
|
+
: configFile.scripts.length == 0
|
|
116
|
+
? ['deploy']
|
|
117
|
+
: configFile.scripts
|
|
118
|
+
: ['deploy'],
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (overrides) {
|
|
122
|
+
for (const key of Object.keys(overrides)) {
|
|
123
|
+
if ((overrides as any)[key] !== undefined) {
|
|
124
|
+
(config as any)[key] = (overrides as any)[key];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return config;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function getChainIdForEnvironment(
|
|
133
|
+
config: ResolvedUserConfig,
|
|
134
|
+
environmentName: string,
|
|
135
|
+
provider?: EIP1193ProviderWithoutEvents,
|
|
136
|
+
) {
|
|
137
|
+
let chainId: number;
|
|
138
|
+
const chainIdFromProvider = provider ? Number(await provider.request({method: 'eth_chainId'})) : undefined;
|
|
139
|
+
if (config?.environments?.[environmentName]?.chain) {
|
|
140
|
+
const chainAsNumber =
|
|
141
|
+
typeof config.environments[environmentName].chain === 'number'
|
|
142
|
+
? config.environments[environmentName].chain
|
|
143
|
+
: parseInt(config.environments[environmentName].chain);
|
|
144
|
+
if (!isNaN(chainAsNumber)) {
|
|
145
|
+
chainId = chainAsNumber;
|
|
146
|
+
} else {
|
|
147
|
+
const chainFound = getDefaultChainInfoByName(config.environments[environmentName].chain as string);
|
|
148
|
+
if (chainFound) {
|
|
149
|
+
chainId = chainFound.id;
|
|
150
|
+
} else {
|
|
151
|
+
throw new Error(`environment ${environmentName} chain id cannot be found, specify it in the rocketh config`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
const chainFound = getDefaultChainInfoByName(environmentName);
|
|
156
|
+
if (chainFound) {
|
|
157
|
+
chainId = chainFound.id;
|
|
158
|
+
} else {
|
|
159
|
+
if (chainIdFromProvider) {
|
|
160
|
+
chainId = chainIdFromProvider;
|
|
161
|
+
} else {
|
|
162
|
+
throw new Error(`environment ${environmentName} chain id cannot be found, specify it in the rocketh config`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (chainIdFromProvider && chainIdFromProvider != chainId) {
|
|
167
|
+
console.warn(
|
|
168
|
+
`provider give a different chainId (${chainIdFromProvider}) than the one expected for environment named "${environmentName}" (${chainId})`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return chainIdFromProvider || chainId;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function getEnvironmentName(executionParams: ExecutionParams): {name: string; fork: boolean} {
|
|
175
|
+
const environmentProvided = executionParams.environment || (executionParams as any).network;
|
|
176
|
+
let environmentName = 'memory';
|
|
177
|
+
if (environmentProvided) {
|
|
178
|
+
if (typeof environmentProvided === 'string') {
|
|
179
|
+
environmentName = environmentProvided;
|
|
180
|
+
} else if ('fork' in environmentProvided) {
|
|
181
|
+
environmentName = environmentProvided.fork;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const fork = typeof environmentProvided !== 'string';
|
|
185
|
+
return {name: environmentName, fork};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function resolveExecutionParams<Extra extends Record<string, unknown> = Record<string, unknown>>(
|
|
189
|
+
config: ResolvedUserConfig,
|
|
190
|
+
executionParameters: ExecutionParams<Extra>,
|
|
191
|
+
chainId: number,
|
|
192
|
+
): ResolvedExecutionParams<Extra> {
|
|
193
|
+
const {name: environmentName, fork} = getEnvironmentName(executionParameters);
|
|
194
|
+
|
|
195
|
+
// TODO fork chainId resolution option to keep the network being used
|
|
196
|
+
const idToFetch = fork ? 31337 : chainId;
|
|
197
|
+
let chainInfoFound = getDefaultChainInfoByName(environmentName);
|
|
198
|
+
if (!chainInfoFound) {
|
|
199
|
+
const result = getDefaultChainInfoFromChainId(idToFetch);
|
|
200
|
+
chainInfoFound = result.success ? result.chainInfo : undefined;
|
|
201
|
+
if (!result.success && result.error) {
|
|
202
|
+
// logger.warn(`could not find chainInfo by name = "${environmentName}"\n ${result.error}`);
|
|
203
|
+
}
|
|
204
|
+
if (!chainInfoFound) {
|
|
205
|
+
// console.log(`could not find chainInfo by chainId = "${idToFetch}"`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const defaultChainInfo = chainInfoFound;
|
|
210
|
+
const chainConfig = getChainConfigFromUserConfigAndDefaultChainInfo(config, {
|
|
211
|
+
id: idToFetch,
|
|
212
|
+
chainInfo: defaultChainInfo,
|
|
213
|
+
canonicalName: environmentName,
|
|
214
|
+
doNotRequireRpcURL: !!executionParameters.provider,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
let chainInfo = chainConfig.info;
|
|
218
|
+
const environmentConfig = config?.environments?.[environmentName];
|
|
219
|
+
const actualChainConfig = environmentConfig?.overrides
|
|
220
|
+
? {
|
|
221
|
+
...chainConfig,
|
|
222
|
+
...environmentConfig.overrides,
|
|
223
|
+
properties: {
|
|
224
|
+
...chainConfig?.properties,
|
|
225
|
+
...environmentConfig.overrides.properties,
|
|
226
|
+
},
|
|
227
|
+
}
|
|
228
|
+
: chainConfig;
|
|
229
|
+
|
|
230
|
+
if (actualChainConfig?.properties) {
|
|
231
|
+
chainInfo = {...chainInfo, properties: actualChainConfig.properties};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// let environmentTags: string[] = actualChainConfig.tags.concat(environmentConfig?.tags); // TODO
|
|
235
|
+
const environmentTags = actualChainConfig.tags;
|
|
236
|
+
|
|
237
|
+
let scripts = ['deploy'];
|
|
238
|
+
if (config.scripts) {
|
|
239
|
+
if (typeof config.scripts === 'string') {
|
|
240
|
+
scripts = [config.scripts];
|
|
241
|
+
} else {
|
|
242
|
+
scripts = [...config.scripts];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (environmentConfig?.scripts) {
|
|
247
|
+
if (typeof environmentConfig.scripts === 'string') {
|
|
248
|
+
scripts = [environmentConfig.scripts];
|
|
249
|
+
} else {
|
|
250
|
+
scripts = [...environmentConfig.scripts];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// here we force type actualChainConfig.rpcUrl! as string
|
|
255
|
+
// as if provider was not available
|
|
256
|
+
// getChainConfigFromUserConfigAndDefaultChainInfo would throw
|
|
257
|
+
const provider =
|
|
258
|
+
executionParameters.provider ||
|
|
259
|
+
(new JSONRPCHTTPProvider(actualChainConfig.rpcUrl!) as EIP1193ProviderWithoutEvents);
|
|
260
|
+
|
|
261
|
+
let saveDeployments = executionParameters.saveDeployments;
|
|
262
|
+
|
|
263
|
+
if (saveDeployments === undefined) {
|
|
264
|
+
if (!executionParameters.provider) {
|
|
265
|
+
saveDeployments = true;
|
|
266
|
+
} else {
|
|
267
|
+
if (environmentName === 'memory' || environmentName === 'hardhat' || environmentName === 'default') {
|
|
268
|
+
// networkTags['memory'] = true;
|
|
269
|
+
saveDeployments = false;
|
|
270
|
+
} else {
|
|
271
|
+
saveDeployments = true;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
askBeforeProceeding: executionParameters.askBeforeProceeding || false,
|
|
278
|
+
chain: chainInfo,
|
|
279
|
+
pollingInterval: actualChainConfig.pollingInterval,
|
|
280
|
+
reportGasUse: executionParameters.reportGasUse || false,
|
|
281
|
+
saveDeployments,
|
|
282
|
+
tags: executionParameters.tags || [],
|
|
283
|
+
environment: {
|
|
284
|
+
name: environmentName,
|
|
285
|
+
tags: environmentTags,
|
|
286
|
+
fork,
|
|
287
|
+
deterministicDeployment: actualChainConfig.deterministicDeployment,
|
|
288
|
+
},
|
|
289
|
+
extra: executionParameters.extra,
|
|
290
|
+
provider,
|
|
291
|
+
scripts,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export async function loadEnvironment<
|
|
296
|
+
NamedAccounts extends UnresolvedUnknownNamedAccounts = UnresolvedUnknownNamedAccounts,
|
|
297
|
+
Data extends UnresolvedNetworkSpecificData = UnresolvedNetworkSpecificData,
|
|
298
|
+
Extra extends Record<string, unknown> = Record<string, unknown>,
|
|
299
|
+
>(
|
|
300
|
+
config: UserConfig<NamedAccounts, Data>,
|
|
301
|
+
executionParams: ExecutionParams<Extra>,
|
|
302
|
+
deploymentStore: DeploymentStore,
|
|
303
|
+
): Promise<Environment<NamedAccounts, Data, UnknownDeployments>> {
|
|
304
|
+
const userConfig = resolveConfig<NamedAccounts, Data>(config, executionParams.config);
|
|
305
|
+
const {name: environmentName, fork} = getEnvironmentName(executionParams);
|
|
306
|
+
const chainId = await getChainIdForEnvironment(userConfig, environmentName, executionParams.provider);
|
|
307
|
+
const resolvedExecutionParams = resolveExecutionParams(userConfig, executionParams, chainId);
|
|
308
|
+
// console.log(JSON.stringify(resolvedConfig, null, 2));
|
|
309
|
+
const {external, internal} = await createEnvironment<NamedAccounts, Data, UnknownDeployments>(
|
|
310
|
+
userConfig,
|
|
311
|
+
resolvedExecutionParams,
|
|
312
|
+
deploymentStore,
|
|
313
|
+
);
|
|
314
|
+
return external;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export function createExecutor(deploymentStore: DeploymentStore, promptExecutor: PromptExecutor) {
|
|
318
|
+
async function resolveConfigAndExecuteDeployScriptModules<
|
|
319
|
+
NamedAccounts extends UnresolvedUnknownNamedAccounts = UnresolvedUnknownNamedAccounts,
|
|
320
|
+
Data extends UnresolvedNetworkSpecificData = UnresolvedNetworkSpecificData,
|
|
321
|
+
ArgumentsType = undefined,
|
|
322
|
+
Extra extends Record<string, unknown> = Record<string, unknown>,
|
|
323
|
+
>(
|
|
324
|
+
moduleObjects: ModuleObject<NamedAccounts, Data, ArgumentsType>[],
|
|
325
|
+
userConfig: UserConfig,
|
|
326
|
+
executionParams?: ExecutionParams<Extra>,
|
|
327
|
+
args?: ArgumentsType,
|
|
328
|
+
): Promise<Environment<NamedAccounts, Data, UnknownDeployments>> {
|
|
329
|
+
executionParams = executionParams || {};
|
|
330
|
+
const resolveduserConfig = resolveConfig<NamedAccounts, Data>(userConfig, executionParams.config);
|
|
331
|
+
const {name: environmentName, fork} = getEnvironmentName(executionParams);
|
|
332
|
+
const chainId = await getChainIdForEnvironment(resolveduserConfig, environmentName, executionParams.provider);
|
|
333
|
+
const resolvedExecutionParams = resolveExecutionParams(resolveduserConfig, executionParams, chainId);
|
|
334
|
+
return executeDeployScriptModules<NamedAccounts, Data, ArgumentsType>(
|
|
335
|
+
moduleObjects,
|
|
336
|
+
resolveduserConfig,
|
|
337
|
+
resolvedExecutionParams,
|
|
338
|
+
args,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function executeDeployScriptModules<
|
|
343
|
+
NamedAccounts extends UnresolvedUnknownNamedAccounts = UnresolvedUnknownNamedAccounts,
|
|
344
|
+
Data extends UnresolvedNetworkSpecificData = UnresolvedNetworkSpecificData,
|
|
345
|
+
ArgumentsType = undefined,
|
|
346
|
+
>(
|
|
347
|
+
moduleObjects: ModuleObject<NamedAccounts, Data, ArgumentsType>[],
|
|
348
|
+
userConfig: ResolvedUserConfig<NamedAccounts, Data>,
|
|
349
|
+
resolvedExecutionParams: ResolvedExecutionParams,
|
|
350
|
+
args?: ArgumentsType,
|
|
351
|
+
): Promise<Environment<NamedAccounts, Data, UnknownDeployments>> {
|
|
352
|
+
const scriptModuleById: {[id: string]: DeployScriptModule<NamedAccounts, Data, ArgumentsType>} = {};
|
|
353
|
+
const scriptIdBags: {[tag: string]: string[]} = {};
|
|
354
|
+
const ids: string[] = [];
|
|
355
|
+
|
|
356
|
+
for (const moduleObject of moduleObjects) {
|
|
357
|
+
const id = moduleObject.id;
|
|
358
|
+
let scriptModule = moduleObject.module;
|
|
359
|
+
scriptModuleById[id] = scriptModule;
|
|
360
|
+
|
|
361
|
+
let scriptTags = scriptModule.tags;
|
|
362
|
+
if (scriptTags !== undefined) {
|
|
363
|
+
if (typeof scriptTags === 'string') {
|
|
364
|
+
scriptTags = [scriptTags];
|
|
365
|
+
}
|
|
366
|
+
for (const tag of scriptTags) {
|
|
367
|
+
if (tag.indexOf(',') >= 0) {
|
|
368
|
+
throw new Error('Tag cannot contains commas');
|
|
369
|
+
}
|
|
370
|
+
const bag = scriptIdBags[tag] || [];
|
|
371
|
+
scriptIdBags[tag] = bag;
|
|
372
|
+
bag.push(id);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (resolvedExecutionParams.tags !== undefined && resolvedExecutionParams.tags.length > 0) {
|
|
377
|
+
let found = false;
|
|
378
|
+
if (scriptTags !== undefined) {
|
|
379
|
+
for (const tagToFind of resolvedExecutionParams.tags) {
|
|
380
|
+
for (const tag of scriptTags) {
|
|
381
|
+
if (tag === tagToFind) {
|
|
382
|
+
ids.push(id);
|
|
383
|
+
found = true;
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (found) {
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
ids.push(id);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const {internal, external} = await createEnvironment<NamedAccounts, Data, UnknownDeployments>(
|
|
398
|
+
userConfig,
|
|
399
|
+
resolvedExecutionParams,
|
|
400
|
+
deploymentStore,
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
await internal.recoverTransactionsIfAny();
|
|
404
|
+
|
|
405
|
+
const scriptsRegisteredToRun: {[filename: string]: boolean} = {};
|
|
406
|
+
const scriptsToRun: Array<{
|
|
407
|
+
func: DeployScriptModule<NamedAccounts, Data, ArgumentsType>;
|
|
408
|
+
id: string;
|
|
409
|
+
}> = [];
|
|
410
|
+
const scriptsToRunAtTheEnd: Array<{
|
|
411
|
+
func: DeployScriptModule<NamedAccounts, Data, ArgumentsType>;
|
|
412
|
+
id: string;
|
|
413
|
+
}> = [];
|
|
414
|
+
function recurseDependencies(id: string) {
|
|
415
|
+
if (scriptsRegisteredToRun[id]) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const scriptModule = scriptModuleById[id];
|
|
419
|
+
if (scriptModule.dependencies) {
|
|
420
|
+
for (const dependency of scriptModule.dependencies) {
|
|
421
|
+
const scriptFilePathsToAdd = scriptIdBags[dependency];
|
|
422
|
+
if (scriptFilePathsToAdd) {
|
|
423
|
+
for (const scriptFilenameToAdd of scriptFilePathsToAdd) {
|
|
424
|
+
recurseDependencies(scriptFilenameToAdd);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (!scriptsRegisteredToRun[id]) {
|
|
430
|
+
if (scriptModule.runAtTheEnd) {
|
|
431
|
+
scriptsToRunAtTheEnd.push({
|
|
432
|
+
id: id,
|
|
433
|
+
func: scriptModule,
|
|
434
|
+
});
|
|
435
|
+
} else {
|
|
436
|
+
scriptsToRun.push({
|
|
437
|
+
id: id,
|
|
438
|
+
func: scriptModule,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
scriptsRegisteredToRun[id] = true;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
for (const id of ids) {
|
|
445
|
+
recurseDependencies(id);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// TODO store in the execution context
|
|
449
|
+
const gasPriceEstimate = await getRoughGasPriceEstimate(external.network.provider);
|
|
450
|
+
if (resolvedExecutionParams.askBeforeProceeding) {
|
|
451
|
+
console.log(
|
|
452
|
+
`Network: ${external.name} \n \t Chain: ${external.network.chain.name} \n \t Tags: ${Object.keys(
|
|
453
|
+
external.tags,
|
|
454
|
+
).join(',')}`,
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
const prompt = await promptExecutor.prompt({
|
|
458
|
+
type: 'confirm',
|
|
459
|
+
name: 'proceed',
|
|
460
|
+
message: `gas price is currently in this range:
|
|
461
|
+
slow: ${formatEther(gasPriceEstimate.slow.maxFeePerGas)} (priority: ${formatEther(
|
|
462
|
+
gasPriceEstimate.slow.maxPriorityFeePerGas,
|
|
463
|
+
)})
|
|
464
|
+
average: ${formatEther(gasPriceEstimate.average.maxFeePerGas)} (priority: ${formatEther(
|
|
465
|
+
gasPriceEstimate.average.maxPriorityFeePerGas,
|
|
466
|
+
)})
|
|
467
|
+
fast: ${formatEther(gasPriceEstimate.fast.maxFeePerGas)} (priority: ${formatEther(
|
|
468
|
+
gasPriceEstimate.fast.maxPriorityFeePerGas,
|
|
469
|
+
)})
|
|
470
|
+
|
|
471
|
+
Do you want to proceed (note that gas price can change for each tx)`,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
if (!prompt.proceed) {
|
|
475
|
+
promptExecutor.exit();
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
for (const deployScript of scriptsToRun.concat(scriptsToRunAtTheEnd)) {
|
|
480
|
+
if (deployScript.func.id && external.hasMigrationBeenDone(deployScript.func.id)) {
|
|
481
|
+
logger.info(`skipping ${deployScript.id} as migrations already executed and complete`);
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
let skip = false;
|
|
485
|
+
const spinner = spin(`- Executing ${deployScript.id}`);
|
|
486
|
+
// if (deployScript.func.skip) {
|
|
487
|
+
// const spinner = spin(` - skip?()`);
|
|
488
|
+
// try {
|
|
489
|
+
// skip = await deployScript.func.skip(external, args);
|
|
490
|
+
// spinner.succeed(skip ? `skipping ${filename}` : undefined);
|
|
491
|
+
// } catch (e) {
|
|
492
|
+
// spinner.fail();
|
|
493
|
+
// throw e;
|
|
494
|
+
// }
|
|
495
|
+
// }
|
|
496
|
+
if (!skip) {
|
|
497
|
+
let result;
|
|
498
|
+
|
|
499
|
+
try {
|
|
500
|
+
result = await deployScript.func(external, args);
|
|
501
|
+
spinner.succeed(`\n`);
|
|
502
|
+
} catch (e) {
|
|
503
|
+
spinner.fail();
|
|
504
|
+
throw e;
|
|
505
|
+
}
|
|
506
|
+
if (result && typeof result === 'boolean') {
|
|
507
|
+
if (!deployScript.func.id) {
|
|
508
|
+
throw new Error(
|
|
509
|
+
`${deployScript.id} return true to not be executed again, but does not provide an id. the script function needs to have the field "id" to be set`,
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
internal.recordMigration(deployScript.func.id);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (resolvedExecutionParams.reportGasUse) {
|
|
518
|
+
const provider = external.network.provider;
|
|
519
|
+
const transactionHashes = provider.transactionHashes;
|
|
520
|
+
|
|
521
|
+
let totalGasUsed = 0;
|
|
522
|
+
for (const hash of transactionHashes) {
|
|
523
|
+
const transactionReceipt = await provider.request({method: 'eth_getTransactionReceipt', params: [hash]});
|
|
524
|
+
if (transactionReceipt) {
|
|
525
|
+
const gasUsed = Number(transactionReceipt.gasUsed);
|
|
526
|
+
totalGasUsed += gasUsed;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
console.log({totalGasUsed});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return external;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return {
|
|
537
|
+
executeDeployScriptModules,
|
|
538
|
+
resolveConfigAndExecuteDeployScriptModules,
|
|
539
|
+
};
|
|
540
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export {
|
|
2
|
+
setupDeployScripts,
|
|
3
|
+
loadEnvironment,
|
|
4
|
+
resolveConfig,
|
|
5
|
+
resolveExecutionParams,
|
|
6
|
+
getChainIdForEnvironment,
|
|
7
|
+
getEnvironmentName,
|
|
8
|
+
createExecutor,
|
|
9
|
+
} from './executor/index.js';
|
|
10
|
+
export {createEnvironment, loadDeployments} from './environment/index.js';
|
|
11
|
+
|
|
12
|
+
// used by hardhat-deploy and instead of having hardhat-deploy depends on @rocketh/core we export it here as well
|
|
13
|
+
export {enhanceEnvIfNeeded} from '@rocketh/core/environment';
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
getChainConfigFromUserConfigAndDefaultChainInfo,
|
|
17
|
+
chainByCanonicalName,
|
|
18
|
+
getDefaultChainInfoByName,
|
|
19
|
+
getDefaultChainInfoFromChainId,
|
|
20
|
+
} from './environment/chains.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {logs} from 'named-logs';
|
|
2
|
+
|
|
3
|
+
import {ProgressIndicator} from '@rocketh/core/types';
|
|
4
|
+
|
|
5
|
+
export const logger = logs('rocketh');
|
|
6
|
+
|
|
7
|
+
const loggerProgressIndicator: ProgressIndicator = {
|
|
8
|
+
start(msg?: string) {
|
|
9
|
+
if (msg) {
|
|
10
|
+
logger.log(msg);
|
|
11
|
+
}
|
|
12
|
+
return this;
|
|
13
|
+
},
|
|
14
|
+
stop() {
|
|
15
|
+
return this;
|
|
16
|
+
},
|
|
17
|
+
succeed(msg?: string) {
|
|
18
|
+
if (msg) {
|
|
19
|
+
logger.log(msg);
|
|
20
|
+
}
|
|
21
|
+
return this;
|
|
22
|
+
},
|
|
23
|
+
fail(msg?: string) {
|
|
24
|
+
if (msg) {
|
|
25
|
+
logger.error(msg);
|
|
26
|
+
}
|
|
27
|
+
return this;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let lastSpin = loggerProgressIndicator;
|
|
32
|
+
export function spin(message?: string): ProgressIndicator {
|
|
33
|
+
lastSpin = lastSpin.start(message);
|
|
34
|
+
return lastSpin;
|
|
35
|
+
}
|
package/src/types.ts
ADDED