hardhat 2.17.4 → 2.18.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.
Files changed (85) hide show
  1. package/README.md +1 -1
  2. package/builtin-tasks/compile.js +17 -1
  3. package/builtin-tasks/compile.js.map +1 -1
  4. package/builtin-tasks/help.js +36 -5
  5. package/builtin-tasks/help.js.map +1 -1
  6. package/internal/cli/ArgumentsParser.d.ts +7 -2
  7. package/internal/cli/ArgumentsParser.d.ts.map +1 -1
  8. package/internal/cli/ArgumentsParser.js +72 -11
  9. package/internal/cli/ArgumentsParser.js.map +1 -1
  10. package/internal/cli/HelpPrinter.d.ts +7 -3
  11. package/internal/cli/HelpPrinter.d.ts.map +1 -1
  12. package/internal/cli/HelpPrinter.js +53 -22
  13. package/internal/cli/HelpPrinter.js.map +1 -1
  14. package/internal/cli/cli.js +29 -15
  15. package/internal/cli/cli.js.map +1 -1
  16. package/internal/cli/project-creation.d.ts.map +1 -1
  17. package/internal/cli/project-creation.js +61 -7
  18. package/internal/cli/project-creation.js.map +1 -1
  19. package/internal/core/config/config-env.d.ts +2 -1
  20. package/internal/core/config/config-env.d.ts.map +1 -1
  21. package/internal/core/config/config-env.js +7 -1
  22. package/internal/core/config/config-env.js.map +1 -1
  23. package/internal/core/errors-list.d.ts +28 -0
  24. package/internal/core/errors-list.d.ts.map +1 -1
  25. package/internal/core/errors-list.js +36 -2
  26. package/internal/core/errors-list.js.map +1 -1
  27. package/internal/core/runtime-environment.d.ts +5 -3
  28. package/internal/core/runtime-environment.d.ts.map +1 -1
  29. package/internal/core/runtime-environment.js +30 -7
  30. package/internal/core/runtime-environment.js.map +1 -1
  31. package/internal/core/tasks/dsl.d.ts +10 -1
  32. package/internal/core/tasks/dsl.d.ts.map +1 -1
  33. package/internal/core/tasks/dsl.js +64 -4
  34. package/internal/core/tasks/dsl.js.map +1 -1
  35. package/internal/core/tasks/task-definitions.d.ts +31 -4
  36. package/internal/core/tasks/task-definitions.d.ts.map +1 -1
  37. package/internal/core/tasks/task-definitions.js +51 -5
  38. package/internal/core/tasks/task-definitions.js.map +1 -1
  39. package/internal/core/tasks/util.d.ts +6 -0
  40. package/internal/core/tasks/util.d.ts.map +1 -0
  41. package/internal/core/tasks/util.js +19 -0
  42. package/internal/core/tasks/util.js.map +1 -0
  43. package/internal/lib/hardhat-lib.d.ts.map +1 -1
  44. package/internal/lib/hardhat-lib.js +1 -1
  45. package/internal/lib/hardhat-lib.js.map +1 -1
  46. package/internal/sentry/anonymizer.d.ts.map +1 -1
  47. package/internal/sentry/anonymizer.js +3 -1
  48. package/internal/sentry/anonymizer.js.map +1 -1
  49. package/internal/solidity/compiler/solc-info.d.ts +2 -0
  50. package/internal/solidity/compiler/solc-info.d.ts.map +1 -0
  51. package/internal/solidity/compiler/solc-info.js +69 -0
  52. package/internal/solidity/compiler/solc-info.js.map +1 -0
  53. package/package.json +1 -1
  54. package/register.js +1 -1
  55. package/register.js.map +1 -1
  56. package/sample-projects/typescript-viem/LICENSE.md +11 -0
  57. package/sample-projects/typescript-viem/README.md +13 -0
  58. package/sample-projects/typescript-viem/contracts/Lock.sol +34 -0
  59. package/sample-projects/typescript-viem/hardhat.config.ts +8 -0
  60. package/sample-projects/typescript-viem/scripts/deploy.ts +26 -0
  61. package/sample-projects/typescript-viem/test/Lock.ts +132 -0
  62. package/sample-projects/typescript-viem/tsconfig.json +11 -0
  63. package/src/builtin-tasks/compile.ts +34 -10
  64. package/src/builtin-tasks/help.ts +47 -5
  65. package/src/internal/cli/ArgumentsParser.ts +79 -13
  66. package/src/internal/cli/HelpPrinter.ts +89 -24
  67. package/src/internal/cli/cli.ts +43 -25
  68. package/src/internal/cli/project-creation.ts +91 -24
  69. package/src/internal/core/config/config-env.ts +11 -0
  70. package/src/internal/core/errors-list.ts +38 -2
  71. package/src/internal/core/runtime-environment.ts +32 -7
  72. package/src/internal/core/tasks/dsl.ts +99 -4
  73. package/src/internal/core/tasks/task-definitions.ts +97 -3
  74. package/src/internal/core/tasks/util.ts +18 -0
  75. package/src/internal/lib/hardhat-lib.ts +1 -0
  76. package/src/internal/sentry/anonymizer.ts +3 -1
  77. package/src/internal/solidity/compiler/solc-info.ts +67 -0
  78. package/src/register.ts +1 -0
  79. package/src/types/builtin-tasks/compile.ts +5 -0
  80. package/src/types/runtime.ts +35 -1
  81. package/types/builtin-tasks/compile.d.ts +4 -0
  82. package/types/builtin-tasks/compile.d.ts.map +1 -1
  83. package/types/builtin-tasks/compile.js.map +1 -1
  84. package/types/runtime.d.ts +24 -1
  85. package/types/runtime.d.ts.map +1 -1
@@ -1,11 +1,14 @@
1
+ import { TASK_HELP } from "../../builtin-tasks/task-names";
1
2
  import {
2
3
  CLIArgumentType,
3
4
  HardhatArguments,
4
5
  HardhatParamDefinitions,
5
6
  ParamDefinition,
6
7
  ParamDefinitionsMap,
8
+ ScopesMap,
7
9
  TaskArguments,
8
10
  TaskDefinition,
11
+ TasksMap,
9
12
  } from "../../types";
10
13
  import { HardhatError } from "../core/errors";
11
14
  import { ERRORS } from "../core/errors-list";
@@ -50,19 +53,20 @@ export class ArgumentsParser {
50
53
  rawCLAs: string[]
51
54
  ): {
52
55
  hardhatArguments: HardhatArguments;
53
- taskName?: string;
54
- unparsedCLAs: string[];
56
+ scopeOrTaskName: string | undefined;
57
+ allUnparsedCLAs: string[];
55
58
  } {
56
59
  const hardhatArguments: Partial<HardhatArguments> = {};
57
- let taskName: string | undefined;
58
- const unparsedCLAs: string[] = [];
60
+ let scopeOrTaskName: string | undefined;
61
+ const allUnparsedCLAs: string[] = [];
59
62
 
60
63
  for (let i = 0; i < rawCLAs.length; i++) {
61
64
  const arg = rawCLAs[i];
62
65
 
63
- if (taskName === undefined) {
66
+ if (scopeOrTaskName === undefined) {
64
67
  if (!this._hasCLAParamNameFormat(arg)) {
65
- taskName = arg;
68
+ scopeOrTaskName = arg;
69
+ allUnparsedCLAs.push(arg);
66
70
  continue;
67
71
  }
68
72
 
@@ -78,11 +82,11 @@ export class ArgumentsParser {
78
82
  i,
79
83
  hardhatParamDefinitions,
80
84
  hardhatArguments,
81
- taskName
85
+ scopeOrTaskName
82
86
  );
83
87
  } else {
84
88
  if (!this._isCLAParamName(arg, hardhatParamDefinitions)) {
85
- unparsedCLAs.push(arg);
89
+ allUnparsedCLAs.push(arg);
86
90
  continue;
87
91
  }
88
92
 
@@ -91,7 +95,7 @@ export class ArgumentsParser {
91
95
  i,
92
96
  hardhatParamDefinitions,
93
97
  hardhatArguments,
94
- taskName
98
+ scopeOrTaskName
95
99
  );
96
100
  }
97
101
  }
@@ -102,11 +106,73 @@ export class ArgumentsParser {
102
106
  envVariableArguments,
103
107
  hardhatArguments
104
108
  ),
105
- taskName,
106
- unparsedCLAs,
109
+ scopeOrTaskName,
110
+ allUnparsedCLAs,
107
111
  };
108
112
  }
109
113
 
114
+ public parseScopeAndTaskNames(
115
+ allUnparsedCLAs: string[],
116
+ taskDefinitions: TasksMap,
117
+ scopeDefinitions: ScopesMap
118
+ ): {
119
+ scopeName?: string;
120
+ taskName: string;
121
+ unparsedCLAs: string[];
122
+ } {
123
+ const [firstCLA, secondCLA] = allUnparsedCLAs;
124
+
125
+ if (allUnparsedCLAs.length === 0) {
126
+ return {
127
+ taskName: TASK_HELP,
128
+ unparsedCLAs: [],
129
+ };
130
+ } else if (allUnparsedCLAs.length === 1) {
131
+ if (scopeDefinitions[firstCLA] !== undefined) {
132
+ // this is a bit of a hack, but it's the easiest way to print
133
+ // the help of a scope when no task is specified
134
+ return {
135
+ taskName: TASK_HELP,
136
+ unparsedCLAs: [firstCLA],
137
+ };
138
+ } else if (taskDefinitions[firstCLA] !== undefined) {
139
+ return {
140
+ taskName: firstCLA,
141
+ unparsedCLAs: allUnparsedCLAs.slice(1),
142
+ };
143
+ } else {
144
+ throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_TASK, {
145
+ task: firstCLA,
146
+ });
147
+ }
148
+ } else {
149
+ const scopeDefinition = scopeDefinitions[firstCLA];
150
+ if (scopeDefinition !== undefined) {
151
+ if (scopeDefinition.tasks[secondCLA] !== undefined) {
152
+ return {
153
+ scopeName: firstCLA,
154
+ taskName: secondCLA,
155
+ unparsedCLAs: allUnparsedCLAs.slice(2),
156
+ };
157
+ } else {
158
+ throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_SCOPED_TASK, {
159
+ scope: firstCLA,
160
+ task: secondCLA,
161
+ });
162
+ }
163
+ } else if (taskDefinitions[firstCLA] !== undefined) {
164
+ return {
165
+ taskName: firstCLA,
166
+ unparsedCLAs: allUnparsedCLAs.slice(1),
167
+ };
168
+ } else {
169
+ throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_TASK, {
170
+ task: firstCLA,
171
+ });
172
+ }
173
+ }
174
+ }
175
+
110
176
  public parseTaskArguments(
111
177
  taskDefinition: TaskDefinition,
112
178
  rawCLAs: string[]
@@ -207,7 +273,7 @@ export class ArgumentsParser {
207
273
  index: number,
208
274
  paramDefinitions: ParamDefinitionsMap,
209
275
  parsedArguments: TaskArguments,
210
- taskName?: string
276
+ scopeOrTaskName?: string
211
277
  ) {
212
278
  const claArg = rawCLAs[index];
213
279
  const paramName = ArgumentsParser.cLAToParamName(claArg);
@@ -228,7 +294,7 @@ export class ArgumentsParser {
228
294
  if (value === undefined) {
229
295
  throw new HardhatError(ERRORS.ARGUMENTS.MISSING_TASK_ARGUMENT, {
230
296
  param: ArgumentsParser.paramNameToCLA(paramName),
231
- task: taskName ?? "help",
297
+ task: scopeOrTaskName ?? "help",
232
298
  });
233
299
  }
234
300
 
@@ -2,6 +2,9 @@ import {
2
2
  HardhatParamDefinitions,
3
3
  ParamDefinition,
4
4
  ParamDefinitionsMap,
5
+ ScopeDefinition,
6
+ ScopesMap,
7
+ TaskDefinition,
5
8
  TasksMap,
6
9
  } from "../../types";
7
10
  import { HardhatError } from "../core/errors";
@@ -15,55 +18,69 @@ export class HelpPrinter {
15
18
  private readonly _executableName: string,
16
19
  private readonly _version: string,
17
20
  private readonly _hardhatParamDefinitions: HardhatParamDefinitions,
18
- private readonly _tasks: TasksMap
21
+ private readonly _tasks: TasksMap,
22
+ private readonly _scopes: ScopesMap
19
23
  ) {}
20
24
 
21
25
  public printGlobalHelp(includeSubtasks = false) {
22
26
  console.log(`${this._programName} version ${this._version}\n`);
23
27
 
24
28
  console.log(
25
- `Usage: ${this._executableName} [GLOBAL OPTIONS] <TASK> [TASK OPTIONS]\n`
29
+ `Usage: ${this._executableName} [GLOBAL OPTIONS] [SCOPE] <TASK> [TASK OPTIONS]\n`
26
30
  );
27
31
 
28
32
  console.log("GLOBAL OPTIONS:\n");
29
33
 
30
- this._printParamDetails(this._hardhatParamDefinitions);
34
+ let length = this._printParamDetails(this._hardhatParamDefinitions);
31
35
 
32
36
  console.log("\n\nAVAILABLE TASKS:\n");
33
37
 
34
- const tasksToShow: TasksMap = {};
35
- for (const [taskName, taskDefinition] of Object.entries(this._tasks)) {
36
- if (includeSubtasks || !taskDefinition.isSubtask) {
37
- tasksToShow[taskName] = taskDefinition;
38
- }
39
- }
40
-
41
- const nameLength = Object.keys(tasksToShow)
42
- .map((n) => n.length)
43
- .reduce((a, b) => Math.max(a, b), 0);
38
+ length = this._printTasks(this._tasks, includeSubtasks, length);
44
39
 
45
- for (const name of Object.keys(tasksToShow).sort()) {
46
- const { description = "" } = this._tasks[name];
40
+ if (Object.keys(this._scopes).length > 0) {
41
+ console.log("\n\nAVAILABLE TASK SCOPES:\n");
47
42
 
48
- console.log(` ${name.padEnd(nameLength)}\t${description}`);
43
+ this._printScopes(this._scopes, length);
49
44
  }
50
45
 
51
46
  console.log("");
52
47
 
53
48
  console.log(
54
- `To get help for a specific task run: npx ${this._executableName} help [task]\n`
49
+ `To get help for a specific task run: npx ${this._executableName} help [SCOPE] <TASK>\n`
55
50
  );
56
51
  }
57
52
 
58
- public printTaskHelp(taskName: string) {
59
- const taskDefinition = this._tasks[taskName];
53
+ public printScopeHelp(
54
+ scopeDefinition: ScopeDefinition,
55
+ includeSubtasks = false
56
+ ) {
57
+ const name = scopeDefinition.name;
58
+ const description = scopeDefinition.description ?? "";
59
+
60
+ console.log(`${this._programName} version ${this._version}`);
60
61
 
61
- if (taskDefinition === undefined) {
62
- throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_TASK, {
63
- task: taskName,
62
+ console.log(
63
+ `\nUsage: hardhat [GLOBAL OPTIONS] ${name} <TASK> [TASK OPTIONS]`
64
+ );
65
+
66
+ console.log(`\nAVAILABLE TASKS:\n`);
67
+
68
+ if (this._scopes[name] === undefined) {
69
+ throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_SCOPE, {
70
+ scope: name,
64
71
  });
65
72
  }
66
73
 
74
+ this._printTasks(this._scopes[name].tasks, includeSubtasks);
75
+
76
+ console.log(`\n${name}: ${description}`);
77
+
78
+ console.log(
79
+ `\nFor global options help run: ${this._executableName} help\n`
80
+ );
81
+ }
82
+
83
+ public printTaskHelp(taskDefinition: TaskDefinition) {
67
84
  const {
68
85
  description = "",
69
86
  name,
@@ -78,8 +95,11 @@ export class HelpPrinter {
78
95
  positionalParamDefinitions
79
96
  );
80
97
 
98
+ const scope =
99
+ taskDefinition.scope !== undefined ? `${taskDefinition.scope} ` : "";
100
+
81
101
  console.log(
82
- `Usage: ${this._executableName} [GLOBAL OPTIONS] ${name}${paramsList}${positionalParamsList}\n`
102
+ `Usage: ${this._executableName} [GLOBAL OPTIONS] ${scope}${name}${paramsList}${positionalParamsList}\n`
83
103
  );
84
104
 
85
105
  if (Object.keys(paramDefinitions).length > 0) {
@@ -103,6 +123,49 @@ export class HelpPrinter {
103
123
  console.log(`For global options help run: ${this._executableName} help\n`);
104
124
  }
105
125
 
126
+ private _printTasks(
127
+ tasksMap: TasksMap,
128
+ includeSubtasks: boolean,
129
+ length: number = 0
130
+ ) {
131
+ const taskNameList = Object.entries(tasksMap)
132
+ .filter(
133
+ ([, taskDefinition]) => includeSubtasks || !taskDefinition.isSubtask
134
+ )
135
+ .map(([taskName]) => taskName)
136
+ .sort();
137
+
138
+ const nameLength = taskNameList
139
+ .map((n) => n.length)
140
+ .reduce((a, b) => Math.max(a, b), length);
141
+
142
+ for (const name of taskNameList) {
143
+ const { description = "" } = tasksMap[name];
144
+
145
+ console.log(` ${name.padEnd(nameLength)}\t${description}`);
146
+ }
147
+
148
+ return nameLength;
149
+ }
150
+
151
+ private _printScopes(scopesMap: ScopesMap, length: number) {
152
+ const scopeNamesList = Object.entries(scopesMap)
153
+ .map(([scopeName]) => scopeName)
154
+ .sort();
155
+
156
+ const nameLength = scopeNamesList
157
+ .map((n) => n.length)
158
+ .reduce((a, b) => Math.max(a, b), length);
159
+
160
+ for (const name of scopeNamesList) {
161
+ const { description = "" } = scopesMap[name];
162
+
163
+ console.log(` ${name.padEnd(nameLength)}\t${description}`);
164
+ }
165
+
166
+ return nameLength;
167
+ }
168
+
106
169
  private _getParamValueDescription<T>(paramDefinition: ParamDefinition<T>) {
107
170
  return `<${paramDefinition.type.name.toUpperCase()}>`;
108
171
  }
@@ -162,7 +225,7 @@ export class HelpPrinter {
162
225
  return paramsList;
163
226
  }
164
227
 
165
- private _printParamDetails(paramDefinitions: ParamDefinitionsMap) {
228
+ private _printParamDetails(paramDefinitions: ParamDefinitionsMap): number {
166
229
  const paramsNameLength = Object.keys(paramDefinitions)
167
230
  .map((n) => ArgumentsParser.paramNameToCLA(n).length)
168
231
  .reduce((a, b) => Math.max(a, b), 0);
@@ -185,6 +248,8 @@ export class HelpPrinter {
185
248
 
186
249
  console.log(msg);
187
250
  }
251
+
252
+ return paramsNameLength;
188
253
  }
189
254
 
190
255
  private _printPositionalParamDetails(
@@ -127,15 +127,12 @@ async function main() {
127
127
 
128
128
  const argumentsParser = new ArgumentsParser();
129
129
 
130
- const {
131
- hardhatArguments,
132
- taskName: parsedTaskName,
133
- unparsedCLAs,
134
- } = argumentsParser.parseHardhatArguments(
135
- HARDHAT_PARAM_DEFINITIONS,
136
- envVariableArguments,
137
- process.argv.slice(2)
138
- );
130
+ const { hardhatArguments, scopeOrTaskName, allUnparsedCLAs } =
131
+ argumentsParser.parseHardhatArguments(
132
+ HARDHAT_PARAM_DEFINITIONS,
133
+ envVariableArguments,
134
+ process.argv.slice(2)
135
+ );
139
136
 
140
137
  if (hardhatArguments.verbose) {
141
138
  Reporter.setVerbose(true);
@@ -160,13 +157,13 @@ async function main() {
160
157
  // The code marked with the tag #INIT-DEP can be deleted after HarhatV3 is out.
161
158
 
162
159
  // Create a new Hardhat project
163
- if (parsedTaskName === "init") {
160
+ if (scopeOrTaskName === "init") {
164
161
  return await createNewProject();
165
162
  }
166
163
  // #INIT-DEP - START OF DEPRECATED CODE
167
164
  else {
168
165
  if (
169
- parsedTaskName === undefined &&
166
+ scopeOrTaskName === undefined &&
170
167
  hardhatArguments.config === undefined &&
171
168
  !isCwdInsideProject()
172
169
  ) {
@@ -213,21 +210,29 @@ async function main() {
213
210
  }
214
211
  }
215
212
 
216
- let taskName = parsedTaskName ?? TASK_HELP;
217
-
218
- const showEmptyConfigWarning = true;
219
- const showSolidityConfigWarnings = taskName === TASK_COMPILE;
220
-
221
213
  const ctx = HardhatContext.createHardhatContext();
222
214
 
223
215
  const { resolvedConfig, userConfig } = loadConfigAndTasks(
224
216
  hardhatArguments,
225
217
  {
226
- showEmptyConfigWarning,
227
- showSolidityConfigWarnings,
218
+ showEmptyConfigWarning: true,
219
+ showSolidityConfigWarnings: scopeOrTaskName === TASK_COMPILE,
228
220
  }
229
221
  );
230
222
 
223
+ const envExtenders = ctx.environmentExtenders;
224
+ const providerExtenders = ctx.providerExtenders;
225
+ const taskDefinitions = ctx.tasksDSL.getTaskDefinitions();
226
+ const scopesDefinitions = ctx.tasksDSL.getScopesDefinitions();
227
+
228
+ // eslint-disable-next-line prefer-const
229
+ let { scopeName, taskName, unparsedCLAs } =
230
+ argumentsParser.parseScopeAndTaskNames(
231
+ allUnparsedCLAs,
232
+ taskDefinitions,
233
+ scopesDefinitions
234
+ );
235
+
231
236
  let telemetryConsent: boolean | undefined = hasConsentedTelemetry();
232
237
 
233
238
  const isHelpCommand = hardhatArguments.help || taskName === TASK_HELP;
@@ -252,22 +257,34 @@ async function main() {
252
257
  Reporter.setEnabled(true);
253
258
  }
254
259
 
255
- const envExtenders = ctx.environmentExtenders;
256
- const providerExtenders = ctx.providerExtenders;
257
- const taskDefinitions = ctx.tasksDSL.getTaskDefinitions();
258
-
259
260
  const [abortAnalytics, hitPromise] = await analytics.sendTaskHit();
260
261
 
261
262
  let taskArguments: TaskArguments;
262
263
 
263
264
  // --help is a also special case
264
265
  if (hardhatArguments.help && taskName !== TASK_HELP) {
265
- taskArguments = { task: taskName };
266
+ // we "move" the task and scope names to the task arguments,
267
+ // and run the help task
268
+ if (scopeName !== undefined) {
269
+ taskArguments = { scopeOrTask: scopeName, task: taskName };
270
+ } else {
271
+ taskArguments = { scopeOrTask: taskName };
272
+ }
266
273
  taskName = TASK_HELP;
274
+ scopeName = undefined;
267
275
  } else {
268
- const taskDefinition = taskDefinitions[taskName];
276
+ const taskDefinition = ctx.tasksDSL.getTaskDefinition(
277
+ scopeName,
278
+ taskName
279
+ );
269
280
 
270
281
  if (taskDefinition === undefined) {
282
+ if (scopeName !== undefined) {
283
+ throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_SCOPED_TASK, {
284
+ scope: scopeName,
285
+ task: taskName,
286
+ });
287
+ }
271
288
  throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_TASK, {
272
289
  task: taskName,
273
290
  });
@@ -289,6 +306,7 @@ async function main() {
289
306
  resolvedConfig,
290
307
  hardhatArguments,
291
308
  taskDefinitions,
309
+ scopesDefinitions,
292
310
  envExtenders,
293
311
  ctx.experimentalHardhatNetworkMessageTraceHooks,
294
312
  userConfig,
@@ -300,7 +318,7 @@ async function main() {
300
318
  try {
301
319
  const timestampBeforeRun = new Date().getTime();
302
320
 
303
- await env.run(taskName, taskArguments);
321
+ await env.run({ scope: scopeName, task: taskName }, taskArguments);
304
322
 
305
323
  const timestampAfterRun = new Date().getTime();
306
324
 
@@ -30,35 +30,51 @@ import { Dependencies, PackageManager } from "./types";
30
30
  enum Action {
31
31
  CREATE_JAVASCRIPT_PROJECT_ACTION = "Create a JavaScript project",
32
32
  CREATE_TYPESCRIPT_PROJECT_ACTION = "Create a TypeScript project",
33
+ CREATE_TYPESCRIPT_VIEM_PROJECT_ACTION = "Create a TypeScript project (with Viem)",
33
34
  CREATE_EMPTY_HARDHAT_CONFIG_ACTION = "Create an empty hardhat.config.js",
34
35
  QUIT_ACTION = "Quit",
35
36
  }
36
37
 
37
38
  type SampleProjectTypeCreationAction =
38
39
  | Action.CREATE_JAVASCRIPT_PROJECT_ACTION
39
- | Action.CREATE_TYPESCRIPT_PROJECT_ACTION;
40
+ | Action.CREATE_TYPESCRIPT_PROJECT_ACTION
41
+ | Action.CREATE_TYPESCRIPT_VIEM_PROJECT_ACTION;
40
42
 
41
43
  const HARDHAT_PACKAGE_NAME = "hardhat";
42
44
 
43
- const PROJECT_DEPENDENCIES: Dependencies = {
45
+ const PROJECT_DEPENDENCIES: Dependencies = {};
46
+
47
+ const ETHERS_PROJECT_DEPENDENCIES: Dependencies = {
44
48
  "@nomicfoundation/hardhat-toolbox": "^3.0.0",
45
49
  };
46
50
 
51
+ const VIEM_PROJECT_DEPENDENCIES: Dependencies = {
52
+ "@nomicfoundation/hardhat-toolbox-viem": "^1.0.0",
53
+ };
54
+
47
55
  const PEER_DEPENDENCIES: Dependencies = {
48
56
  hardhat: "^2.14.0",
49
57
  "@nomicfoundation/hardhat-network-helpers": "^1.0.0",
50
- "@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
51
- "@nomicfoundation/hardhat-ethers": "^3.0.0",
52
58
  "@nomicfoundation/hardhat-verify": "^1.0.0",
53
59
  chai: "^4.2.0",
54
- ethers: "^6.4.0",
55
60
  "hardhat-gas-reporter": "^1.0.8",
56
61
  "solidity-coverage": "^0.8.0",
62
+ };
63
+
64
+ const ETHERS_PEER_DEPENDENCIES: Dependencies = {
65
+ "@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
66
+ "@nomicfoundation/hardhat-ethers": "^3.0.0",
67
+ ethers: "^6.4.0",
57
68
  "@typechain/hardhat": "^8.0.0",
58
69
  typechain: "^8.1.0",
59
70
  "@typechain/ethers-v6": "^0.4.0",
60
71
  };
61
72
 
73
+ const VIEM_PEER_DEPENDENCIES: Dependencies = {
74
+ "@nomicfoundation/hardhat-viem": "^1.0.0",
75
+ viem: "^1.15.1",
76
+ };
77
+
62
78
  const TYPESCRIPT_DEPENDENCIES: Dependencies = {};
63
79
 
64
80
  const TYPESCRIPT_PEER_DEPENDENCIES: Dependencies = {
@@ -69,6 +85,15 @@ const TYPESCRIPT_PEER_DEPENDENCIES: Dependencies = {
69
85
  typescript: ">=4.5.0",
70
86
  };
71
87
 
88
+ const TYPESCRIPT_ETHERS_PEER_DEPENDENCIES: Dependencies = {
89
+ typescript: ">=4.5.0",
90
+ };
91
+
92
+ const TYPESCRIPT_VIEM_PEER_DEPENDENCIES: Dependencies = {
93
+ "@types/chai-as-promised": "^7.1.6",
94
+ typescript: "~5.0.4",
95
+ };
96
+
72
97
  // generated with the "colossal" font
73
98
  function printAsciiLogo() {
74
99
  console.log(
@@ -130,6 +155,8 @@ async function copySampleProject(
130
155
  false,
131
156
  "Shouldn't try to create a TypeScript project in an ESM based project"
132
157
  );
158
+ } else if (projectType === Action.CREATE_TYPESCRIPT_VIEM_PROJECT_ACTION) {
159
+ sampleProjectName = "typescript-viem";
133
160
  } else {
134
161
  sampleProjectName = "typescript";
135
162
  }
@@ -262,26 +289,36 @@ async function getAction(isEsm: boolean): Promise<Action> {
262
289
  type: "select",
263
290
  message: "What do you want to do?",
264
291
  initial: 0,
265
- choices: Object.values(Action).map((a: Action) => {
266
- let message: string;
267
- if (isEsm) {
268
- if (a === Action.CREATE_EMPTY_HARDHAT_CONFIG_ACTION) {
269
- message = a.replace(".js", ".cjs");
270
- } else if (a === Action.CREATE_TYPESCRIPT_PROJECT_ACTION) {
271
- message = `${a} (not available for ESM projects)`;
292
+ choices: Object.values(Action)
293
+ .filter((a: Action) => {
294
+ if (isEsm && a === Action.CREATE_TYPESCRIPT_VIEM_PROJECT_ACTION) {
295
+ // we omit the viem option for ESM projects to avoid showing
296
+ // two disabled options
297
+ return false;
298
+ }
299
+
300
+ return true;
301
+ })
302
+ .map((a: Action) => {
303
+ let message: string;
304
+ if (isEsm) {
305
+ if (a === Action.CREATE_EMPTY_HARDHAT_CONFIG_ACTION) {
306
+ message = a.replace(".js", ".cjs");
307
+ } else if (a === Action.CREATE_TYPESCRIPT_PROJECT_ACTION) {
308
+ message = `${a} (not available for ESM projects)`;
309
+ } else {
310
+ message = a;
311
+ }
272
312
  } else {
273
313
  message = a;
274
314
  }
275
- } else {
276
- message = a;
277
- }
278
-
279
- return {
280
- name: a,
281
- message,
282
- value: a,
283
- };
284
- }),
315
+
316
+ return {
317
+ name: a,
318
+ message,
319
+ value: a,
320
+ };
321
+ }),
285
322
  },
286
323
  ]);
287
324
 
@@ -588,12 +625,13 @@ async function getDependencies(
588
625
  !(await doesNpmAutoInstallPeerDependencies());
589
626
 
590
627
  const shouldInstallTypescriptDependencies =
591
- projectType === Action.CREATE_TYPESCRIPT_PROJECT_ACTION;
628
+ projectType === Action.CREATE_TYPESCRIPT_PROJECT_ACTION ||
629
+ projectType === Action.CREATE_TYPESCRIPT_VIEM_PROJECT_ACTION;
592
630
 
593
631
  const shouldInstallTypescriptPeerDependencies =
594
632
  shouldInstallTypescriptDependencies && shouldInstallPeerDependencies;
595
633
 
596
- return {
634
+ const commonDependencies: Dependencies = {
597
635
  [HARDHAT_PACKAGE_NAME]: `^${(await getPackageJson()).version}`,
598
636
  ...PROJECT_DEPENDENCIES,
599
637
  ...(shouldInstallPeerDependencies ? PEER_DEPENDENCIES : {}),
@@ -602,4 +640,33 @@ async function getDependencies(
602
640
  ? TYPESCRIPT_PEER_DEPENDENCIES
603
641
  : {}),
604
642
  };
643
+
644
+ // At the moment, the default toolbox is the ethers based toolbox
645
+ const shouldInstallDefaultToolbox =
646
+ projectType !== Action.CREATE_TYPESCRIPT_VIEM_PROJECT_ACTION;
647
+
648
+ const ethersToolboxDependencies: Dependencies = {
649
+ ...ETHERS_PROJECT_DEPENDENCIES,
650
+ ...(shouldInstallPeerDependencies ? ETHERS_PEER_DEPENDENCIES : {}),
651
+ ...(shouldInstallTypescriptPeerDependencies
652
+ ? TYPESCRIPT_ETHERS_PEER_DEPENDENCIES
653
+ : {}),
654
+ };
655
+
656
+ const viemToolboxDependencies: Dependencies = {
657
+ ...VIEM_PROJECT_DEPENDENCIES,
658
+ ...(shouldInstallPeerDependencies ? VIEM_PEER_DEPENDENCIES : {}),
659
+ ...(shouldInstallTypescriptPeerDependencies
660
+ ? TYPESCRIPT_VIEM_PEER_DEPENDENCIES
661
+ : {}),
662
+ };
663
+
664
+ const toolboxDependencies: Dependencies = shouldInstallDefaultToolbox
665
+ ? ethersToolboxDependencies
666
+ : viemToolboxDependencies;
667
+
668
+ return {
669
+ ...commonDependencies,
670
+ ...toolboxDependencies,
671
+ };
605
672
  }
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ActionType,
3
3
  ConfigExtender,
4
+ ConfigurableScopeDefinition,
4
5
  ConfigurableTaskDefinition,
5
6
  EnvironmentExtender,
6
7
  ExperimentalHardhatNetworkMessageTraceHook,
@@ -116,6 +117,16 @@ export function subtask<TaskArgumentsT extends TaskArguments>(
116
117
  // Backwards compatibility alias
117
118
  export const internalTask = subtask;
118
119
 
120
+ export function scope(
121
+ name: string,
122
+ description?: string
123
+ ): ConfigurableScopeDefinition {
124
+ const ctx = HardhatContext.getHardhatContext();
125
+ const dsl = ctx.tasksDSL;
126
+
127
+ return dsl.scope(name, description);
128
+ }
129
+
119
130
  export const types = argumentTypes;
120
131
 
121
132
  /**