hardhat 2.18.3 → 2.19.0

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 (61) hide show
  1. package/builtin-tasks/vars.d.ts +2 -0
  2. package/builtin-tasks/vars.d.ts.map +1 -0
  3. package/builtin-tasks/vars.js +41 -0
  4. package/builtin-tasks/vars.js.map +1 -0
  5. package/internal/cli/cli.js +4 -0
  6. package/internal/cli/cli.js.map +1 -1
  7. package/internal/cli/vars.d.ts +2 -0
  8. package/internal/cli/vars.d.ts.map +1 -0
  9. package/internal/cli/vars.js +216 -0
  10. package/internal/cli/vars.js.map +1 -0
  11. package/internal/context.d.ts +4 -0
  12. package/internal/context.d.ts.map +1 -1
  13. package/internal/context.js +3 -0
  14. package/internal/context.js.map +1 -1
  15. package/internal/core/config/config-env.d.ts +34 -0
  16. package/internal/core/config/config-env.d.ts.map +1 -1
  17. package/internal/core/config/config-env.js +47 -1
  18. package/internal/core/config/config-env.js.map +1 -1
  19. package/internal/core/config/config-loading.d.ts +1 -0
  20. package/internal/core/config/config-loading.d.ts.map +1 -1
  21. package/internal/core/config/config-loading.js +2 -1
  22. package/internal/core/config/config-loading.js.map +1 -1
  23. package/internal/core/errors-list.d.ts +30 -0
  24. package/internal/core/errors-list.d.ts.map +1 -1
  25. package/internal/core/errors-list.js +36 -1
  26. package/internal/core/errors-list.js.map +1 -1
  27. package/internal/core/tasks/builtin-tasks.d.ts +1 -0
  28. package/internal/core/tasks/builtin-tasks.d.ts.map +1 -1
  29. package/internal/core/tasks/builtin-tasks.js +1 -0
  30. package/internal/core/tasks/builtin-tasks.js.map +1 -1
  31. package/internal/core/vars/vars-manager-setup.d.ts +22 -0
  32. package/internal/core/vars/vars-manager-setup.d.ts.map +1 -0
  33. package/internal/core/vars/vars-manager-setup.js +95 -0
  34. package/internal/core/vars/vars-manager-setup.js.map +1 -0
  35. package/internal/core/vars/vars-manager.d.ts +21 -0
  36. package/internal/core/vars/vars-manager.d.ts.map +1 -0
  37. package/internal/core/vars/vars-manager.js +110 -0
  38. package/internal/core/vars/vars-manager.js.map +1 -0
  39. package/internal/hardhat-network/stack-traces/constants.d.ts +1 -1
  40. package/internal/hardhat-network/stack-traces/constants.js +1 -1
  41. package/internal/solidity/compiler/solc-info.d.ts.map +1 -1
  42. package/internal/solidity/compiler/solc-info.js +1 -0
  43. package/internal/solidity/compiler/solc-info.js.map +1 -1
  44. package/internal/util/global-dir.d.ts +1 -0
  45. package/internal/util/global-dir.d.ts.map +1 -1
  46. package/internal/util/global-dir.js +5 -1
  47. package/internal/util/global-dir.js.map +1 -1
  48. package/package.json +1 -1
  49. package/src/builtin-tasks/vars.ts +54 -0
  50. package/src/internal/cli/cli.ts +5 -1
  51. package/src/internal/cli/vars.ts +301 -0
  52. package/src/internal/context.ts +8 -0
  53. package/src/internal/core/config/config-env.ts +54 -0
  54. package/src/internal/core/config/config-loading.ts +1 -1
  55. package/src/internal/core/errors-list.ts +39 -1
  56. package/src/internal/core/tasks/builtin-tasks.ts +1 -0
  57. package/src/internal/core/vars/vars-manager-setup.ts +124 -0
  58. package/src/internal/core/vars/vars-manager.ts +152 -0
  59. package/src/internal/hardhat-network/stack-traces/constants.ts +1 -1
  60. package/src/internal/solidity/compiler/solc-info.ts +1 -0
  61. package/src/internal/util/global-dir.ts +4 -0
@@ -0,0 +1,54 @@
1
+ import { HardhatError } from "../internal/core/errors";
2
+ import { scope } from "../internal/core/config/config-env";
3
+ import { ERRORS } from "../internal/core/errors-list";
4
+
5
+ const varsScope = scope("vars", "Manage your configuration variables");
6
+
7
+ varsScope
8
+ .task("set", "Set the value of a configuration variable")
9
+ .addPositionalParam("var", "The name of the variable")
10
+ .addOptionalPositionalParam(
11
+ "value",
12
+ "The value to store. Omit to be prompted for it."
13
+ )
14
+ .setAction(async () => {
15
+ throw new HardhatError(ERRORS.VARS.ONLY_MANAGED_IN_CLI);
16
+ });
17
+
18
+ varsScope
19
+ .task("get", "Get the value of a configuration variable")
20
+ .addPositionalParam("var", "The name of the variable")
21
+ .setAction(async () => {
22
+ throw new HardhatError(ERRORS.VARS.ONLY_MANAGED_IN_CLI);
23
+ });
24
+
25
+ varsScope
26
+ .task("list", "List all the configuration variables")
27
+ .setAction(async () => {
28
+ throw new HardhatError(ERRORS.VARS.ONLY_MANAGED_IN_CLI);
29
+ });
30
+
31
+ varsScope
32
+ .task("delete", "Delete a configuration variable")
33
+ .addPositionalParam("var", "The name of the variable")
34
+ .setAction(async () => {
35
+ throw new HardhatError(ERRORS.VARS.ONLY_MANAGED_IN_CLI);
36
+ });
37
+
38
+ varsScope
39
+ .task(
40
+ "path",
41
+ "Show the path of the file where all the configuration variables are stored"
42
+ )
43
+ .setAction(async () => {
44
+ throw new HardhatError(ERRORS.VARS.ONLY_MANAGED_IN_CLI);
45
+ });
46
+
47
+ varsScope
48
+ .task(
49
+ "setup",
50
+ "Show how to setup the configuration variables used by this project"
51
+ )
52
+ .setAction(async () => {
53
+ throw new HardhatError(ERRORS.VARS.ONLY_MANAGED_IN_CLI);
54
+ });
@@ -1,7 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import debug from "debug";
3
3
  import "source-map-support/register";
4
-
5
4
  import {
6
5
  TASK_COMPILE,
7
6
  TASK_HELP,
@@ -50,6 +49,7 @@ import {
50
49
  installHardhatVSCode,
51
50
  isHardhatVSCodeInstalled,
52
51
  } from "./hardhat-vscode-installation";
52
+ import { handleVars } from "./vars";
53
53
 
54
54
  const log = debug("hardhat:core:cli");
55
55
 
@@ -212,6 +212,10 @@ async function main() {
212
212
 
213
213
  const ctx = HardhatContext.createHardhatContext();
214
214
 
215
+ if (scopeOrTaskName === "vars" && allUnparsedCLAs.length > 1) {
216
+ process.exit(await handleVars(allUnparsedCLAs, hardhatArguments.config));
217
+ }
218
+
215
219
  const { resolvedConfig, userConfig } = loadConfigAndTasks(
216
220
  hardhatArguments,
217
221
  {
@@ -0,0 +1,301 @@
1
+ import chalk from "chalk";
2
+ import debug from "debug";
3
+ import { HardhatError, assertHardhatInvariant } from "../core/errors";
4
+ import { ERRORS } from "../core/errors-list";
5
+ import { HardhatContext } from "../context";
6
+ import { VarsManagerSetup } from "../core/vars/vars-manager-setup";
7
+ import {
8
+ importCsjOrEsModule,
9
+ resolveConfigPath,
10
+ } from "../core/config/config-loading";
11
+ import { getVarsFilePath } from "../util/global-dir";
12
+ import { ArgumentsParser } from "./ArgumentsParser";
13
+ import { emoji } from "./emoji";
14
+
15
+ const log = debug("hardhat:cli:vars");
16
+
17
+ export async function handleVars(
18
+ allUnparsedCLAs: string[],
19
+ configPath: string | undefined
20
+ ): Promise<number> {
21
+ const { taskDefinition, taskArguments } =
22
+ await getTaskDefinitionAndTaskArguments(allUnparsedCLAs);
23
+
24
+ switch (taskDefinition.name) {
25
+ case "set":
26
+ return set(taskArguments.var, taskArguments.value);
27
+ case "get":
28
+ return get(taskArguments.var);
29
+ case "list":
30
+ return list();
31
+ case "delete":
32
+ return del(taskArguments.var);
33
+ case "path":
34
+ return path();
35
+ case "setup":
36
+ return setup(configPath);
37
+ default:
38
+ console.error(chalk.red(`Invalid task '${taskDefinition.name}'`));
39
+ return 1; // Error code
40
+ }
41
+ }
42
+
43
+ async function set(key: string, value?: string): Promise<number> {
44
+ const varsManager = HardhatContext.getHardhatContext().varsManager;
45
+
46
+ varsManager.validateKey(key);
47
+
48
+ varsManager.set(key, value ?? (await getVarValue()));
49
+
50
+ if (process.stdout.isTTY) {
51
+ console.warn(
52
+ `The configuration variable has been stored in ${varsManager.getStoragePath()}`
53
+ );
54
+ }
55
+
56
+ return 0;
57
+ }
58
+
59
+ function get(key: string): number {
60
+ const value = HardhatContext.getHardhatContext().varsManager.get(key);
61
+
62
+ if (value !== undefined) {
63
+ console.log(value);
64
+ return 0;
65
+ }
66
+
67
+ console.warn(
68
+ chalk.yellow(
69
+ `The configuration variable '${key}' is not set in ${HardhatContext.getHardhatContext().varsManager.getStoragePath()}`
70
+ )
71
+ );
72
+ return 1;
73
+ }
74
+
75
+ function list(): number {
76
+ const keys = HardhatContext.getHardhatContext().varsManager.list();
77
+ const varsStoragePath =
78
+ HardhatContext.getHardhatContext().varsManager.getStoragePath();
79
+
80
+ if (keys.length > 0) {
81
+ keys.forEach((k) => console.log(k));
82
+
83
+ if (process.stdout.isTTY) {
84
+ console.warn(
85
+ `\nAll configuration variables are stored in ${varsStoragePath}`
86
+ );
87
+ }
88
+ } else {
89
+ if (process.stdout.isTTY) {
90
+ console.warn(
91
+ chalk.yellow(
92
+ `There are no configuration variables stored in ${varsStoragePath}`
93
+ )
94
+ );
95
+ }
96
+ }
97
+
98
+ return 0;
99
+ }
100
+
101
+ function del(key: string): number {
102
+ const varsStoragePath =
103
+ HardhatContext.getHardhatContext().varsManager.getStoragePath();
104
+
105
+ if (HardhatContext.getHardhatContext().varsManager.delete(key)) {
106
+ if (process.stdout.isTTY) {
107
+ console.warn(
108
+ `The configuration variable was deleted from ${varsStoragePath}`
109
+ );
110
+ }
111
+ return 0;
112
+ }
113
+
114
+ console.warn(
115
+ chalk.yellow(
116
+ `There is no configuration variable '${key}' to delete from ${varsStoragePath}`
117
+ )
118
+ );
119
+
120
+ return 1;
121
+ }
122
+
123
+ function path() {
124
+ console.log(HardhatContext.getHardhatContext().varsManager.getStoragePath());
125
+ return 0;
126
+ }
127
+
128
+ function setup(configPath: string | undefined) {
129
+ log("Switching to SetupVarsManager to collect vars");
130
+
131
+ const varsManagerSetup = new VarsManagerSetup(getVarsFilePath());
132
+
133
+ HardhatContext.getHardhatContext().varsManager = varsManagerSetup;
134
+
135
+ try {
136
+ log("Loading config and tasks to trigger vars collection");
137
+ loadConfigFile(configPath);
138
+ } catch (err: any) {
139
+ console.error(
140
+ chalk.red(
141
+ "There is an error in your Hardhat configuration file. Please double check it.\n"
142
+ )
143
+ );
144
+
145
+ // eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
146
+ throw err;
147
+ }
148
+
149
+ listVarsToSetup(varsManagerSetup);
150
+
151
+ return 0;
152
+ }
153
+
154
+ // The code below duplicates a section from the 'loadConfigAndTasks' function.
155
+ // While we could have refactored the 'config-loading.ts' module to make this logic reusable,
156
+ // it would have added complexity and potentially made the code harder to understand.
157
+ function loadConfigFile(configPath: string | undefined) {
158
+ const configEnv = require(`../core/config/config-env`);
159
+
160
+ // Load all the functions and objects exported by the 'config-env' file in a global scope
161
+ const globalAsAny: any = global;
162
+ Object.entries(configEnv).forEach(
163
+ ([key, value]) => (globalAsAny[key] = value)
164
+ );
165
+
166
+ const resolvedConfigPath = resolveConfigPath(configPath);
167
+ importCsjOrEsModule(resolvedConfigPath);
168
+ }
169
+
170
+ async function getVarValue(): Promise<string> {
171
+ const { default: enquirer } = await import("enquirer");
172
+
173
+ const response: { value: string } = await enquirer.prompt({
174
+ type: "password",
175
+ name: "value",
176
+ message: "Enter value:",
177
+ });
178
+
179
+ return response.value;
180
+ }
181
+
182
+ function listVarsToSetup(varsManagerSetup: VarsManagerSetup) {
183
+ const HH_SET_COMMAND = "npx hardhat vars set";
184
+
185
+ const requiredKeysToSet = varsManagerSetup.getRequiredVarsToSet();
186
+ const optionalKeysToSet = varsManagerSetup.getOptionalVarsToSet();
187
+
188
+ if (requiredKeysToSet.length === 0 && optionalKeysToSet.length === 0) {
189
+ console.log(
190
+ chalk.green(
191
+ "There are no configuration variables that need to be set for this project"
192
+ )
193
+ );
194
+ console.log();
195
+ printAlreadySetKeys(varsManagerSetup);
196
+ return;
197
+ }
198
+
199
+ if (requiredKeysToSet.length > 0) {
200
+ console.log(
201
+ chalk.bold(
202
+ `${emoji("❗ ")}The following configuration variables need to be set:\n`
203
+ )
204
+ );
205
+ console.log(
206
+ requiredKeysToSet.map((k) => ` ${HH_SET_COMMAND} ${k}`).join("\n")
207
+ );
208
+ console.log();
209
+ }
210
+
211
+ if (optionalKeysToSet.length > 0) {
212
+ console.log(
213
+ chalk.bold(
214
+ `${emoji("💡 ")}The following configuration variables are optional:\n`
215
+ )
216
+ );
217
+ console.log(
218
+ optionalKeysToSet.map((k) => ` ${HH_SET_COMMAND} ${k}`).join("\n")
219
+ );
220
+ console.log();
221
+ }
222
+
223
+ printAlreadySetKeys(varsManagerSetup);
224
+ }
225
+
226
+ function printAlreadySetKeys(varsManagerSetup: VarsManagerSetup) {
227
+ const requiredKeysAlreadySet = varsManagerSetup.getRequiredVarsAlreadySet();
228
+ const optionalKeysAlreadySet = varsManagerSetup.getOptionalVarsAlreadySet();
229
+ const envVars = varsManagerSetup.getEnvVars();
230
+
231
+ if (
232
+ requiredKeysAlreadySet.length === 0 &&
233
+ optionalKeysAlreadySet.length === 0 &&
234
+ envVars.length === 0
235
+ ) {
236
+ return;
237
+ }
238
+
239
+ console.log(
240
+ `${chalk.bold(`${emoji("✔️ ")}Configuration variables already set:`)}`
241
+ );
242
+ console.log();
243
+
244
+ if (requiredKeysAlreadySet.length > 0) {
245
+ console.log(" Mandatory:");
246
+ console.log(requiredKeysAlreadySet.map((x) => ` ${x}`).join("\n"));
247
+ console.log();
248
+ }
249
+
250
+ if (optionalKeysAlreadySet.length > 0) {
251
+ console.log(" Optional:");
252
+ console.log(optionalKeysAlreadySet.map((x) => ` ${x}`).join("\n"));
253
+ console.log();
254
+ }
255
+
256
+ if (envVars.length > 0) {
257
+ console.log(" Set via environment variables:");
258
+ console.log(envVars.map((x) => ` ${x}`).join("\n"));
259
+ console.log();
260
+ }
261
+ }
262
+
263
+ async function getTaskDefinitionAndTaskArguments(allUnparsedCLAs: string[]) {
264
+ const ctx = HardhatContext.getHardhatContext();
265
+ ctx.setConfigLoadingAsStarted();
266
+ require("../../builtin-tasks/vars");
267
+ ctx.setConfigLoadingAsFinished();
268
+
269
+ const argumentsParser = new ArgumentsParser();
270
+
271
+ const taskDefinitions = ctx.tasksDSL.getTaskDefinitions();
272
+ const scopesDefinitions = ctx.tasksDSL.getScopesDefinitions();
273
+
274
+ const { scopeName, taskName, unparsedCLAs } =
275
+ argumentsParser.parseScopeAndTaskNames(
276
+ allUnparsedCLAs,
277
+ taskDefinitions,
278
+ scopesDefinitions
279
+ );
280
+
281
+ assertHardhatInvariant(
282
+ scopeName === "vars",
283
+ "This function should only be called to handle tasks under the 'vars' scope"
284
+ );
285
+
286
+ const taskDefinition = ctx.tasksDSL.getTaskDefinition(scopeName, taskName);
287
+
288
+ if (taskDefinition === undefined) {
289
+ throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_SCOPED_TASK, {
290
+ scope: scopeName,
291
+ task: taskName,
292
+ });
293
+ }
294
+
295
+ const taskArguments = argumentsParser.parseTaskArguments(
296
+ taskDefinition,
297
+ unparsedCLAs
298
+ );
299
+
300
+ return { taskDefinition, taskArguments };
301
+ }
@@ -8,7 +8,10 @@ import {
8
8
 
9
9
  import { assertHardhatInvariant, HardhatError } from "./core/errors";
10
10
  import { ERRORS } from "./core/errors-list";
11
+ import { VarsManagerSetup } from "./core/vars/vars-manager-setup";
12
+ import { VarsManager } from "./core/vars/vars-manager";
11
13
  import { TasksDSL } from "./core/tasks/dsl";
14
+ import { getVarsFilePath } from "./util/global-dir";
12
15
  import { getRequireCachedFiles } from "./util/platform";
13
16
 
14
17
  export type GlobalWithHardhatContext = typeof global & {
@@ -16,6 +19,10 @@ export type GlobalWithHardhatContext = typeof global & {
16
19
  };
17
20
 
18
21
  export class HardhatContext {
22
+ constructor() {
23
+ this.varsManager = new VarsManager(getVarsFilePath());
24
+ }
25
+
19
26
  public static isCreated(): boolean {
20
27
  const globalWithHardhatContext = global as GlobalWithHardhatContext;
21
28
  return globalWithHardhatContext.__hardhatContext !== undefined;
@@ -49,6 +56,7 @@ export class HardhatContext {
49
56
  public readonly environmentExtenders: EnvironmentExtender[] = [];
50
57
  public environment?: HardhatRuntimeEnvironment;
51
58
  public readonly providerExtenders: ProviderExtender[] = [];
59
+ public varsManager: VarsManager | VarsManagerSetup;
52
60
 
53
61
  public readonly configExtenders: ConfigExtender[] = [];
54
62
 
@@ -9,6 +9,8 @@ import {
9
9
  TaskArguments,
10
10
  } from "../../../types";
11
11
  import { HardhatContext } from "../../context";
12
+ import { HardhatError } from "../errors";
13
+ import { ERRORS } from "../errors-list";
12
14
  import * as argumentTypes from "../params/argumentTypes";
13
15
 
14
16
  /**
@@ -173,3 +175,55 @@ export function experimentalAddHardhatNetworkMessageTraceHook(
173
175
  const ctx = HardhatContext.getHardhatContext();
174
176
  ctx.experimentalHardhatNetworkMessageTraceHooks.push(hook);
175
177
  }
178
+
179
+ /**
180
+ * This object provides methods to interact with the configuration variables.
181
+ */
182
+ export const vars = {
183
+ has: hasVar,
184
+ get: getVar,
185
+ };
186
+
187
+ /**
188
+ * Checks if a configuration variable exists.
189
+ *
190
+ * @remarks
191
+ * This method, when used during setup (via `npx hardhat vars setup`), will mark the variable as optional.
192
+ *
193
+ * @param varName - The name of the variable to check.
194
+ *
195
+ * @returns `true` if the variable exists, `false` otherwise.
196
+ */
197
+ function hasVar(varName: string): boolean {
198
+ // varsManager will be an instance of VarsManager or VarsManagerSetup depending on the context (vars setup mode or not)
199
+ return HardhatContext.getHardhatContext().varsManager.has(varName, true);
200
+ }
201
+
202
+ /**
203
+ * Gets the value of the given configuration variable.
204
+ *
205
+ * @remarks
206
+ * This method, when used during setup (via `npx hardhat vars setup`), will mark the variable as required,
207
+ * unless a default value is provided.
208
+ *
209
+ * @param varName - The name of the variable to retrieve.
210
+ * @param [defaultValue] - An optional default value to return if the variable does not exist.
211
+ *
212
+ * @returns The value of the configuration variable if it exists, or the default value if provided.
213
+ *
214
+ * @throws HH1201 if the variable does not exist and no default value is set.
215
+ */
216
+ function getVar(varName: string, defaultValue?: string): string {
217
+ // varsManager will be an instance of VarsManager or VarsManagerSetup depending on the context (vars setup mode or not)
218
+ const value = HardhatContext.getHardhatContext().varsManager.get(
219
+ varName,
220
+ defaultValue,
221
+ true
222
+ );
223
+
224
+ if (value !== undefined) return value;
225
+
226
+ throw new HardhatError(ERRORS.VARS.VALUE_NOT_FOUND_FOR_VAR, {
227
+ value: varName,
228
+ });
229
+ }
@@ -25,7 +25,7 @@ import { DEFAULT_SOLC_VERSION } from "./default-config";
25
25
 
26
26
  const log = debug("hardhat:core:config");
27
27
 
28
- function importCsjOrEsModule(filePath: string): any {
28
+ export function importCsjOrEsModule(filePath: string): any {
29
29
  try {
30
30
  const imported = require(filePath);
31
31
  return imported.default !== undefined ? imported.default : imported;
@@ -41,6 +41,7 @@ export const ERROR_RANGES: {
41
41
  INTERNAL: { min: 900, max: 999, title: "Internal Hardhat errors" },
42
42
  SOURCE_NAMES: { min: 1000, max: 1099, title: "Source name errors" },
43
43
  CONTRACT_NAMES: { min: 1100, max: 1199, title: "Contract name errors" },
44
+ VARS: { min: 1200, max: 1299, title: "Connfiguration variables errors" },
44
45
  };
45
46
 
46
47
  export const ERRORS = {
@@ -643,7 +644,7 @@ Please double check your task definitions.`,
643
644
  ARGUMENTS: {
644
645
  INVALID_ENV_VAR_VALUE: {
645
646
  number: 300,
646
- message: "Invalid environment variable %varName%'s value: %value%",
647
+ message: "Invalid environment variable '%varName%' with value: '%value%'",
647
648
  title: "Invalid environment variable value",
648
649
  description: `You are setting one of Hardhat's arguments using an environment variable, but it has an incorrect value.
649
650
 
@@ -1298,6 +1299,43 @@ A fully qualified name should look like file.sol:Contract`,
1298
1299
  shouldBeReported: false,
1299
1300
  },
1300
1301
  },
1302
+ VARS: {
1303
+ ONLY_MANAGED_IN_CLI: {
1304
+ number: 1200,
1305
+ title: "Configuration variables can only be managed from the CLI",
1306
+ message:
1307
+ "Configuration variables can only be managed from the CLI. They cannot be modified programmatically.",
1308
+ description: `Configuration variables can only be managed from the CLI. They cannot be modified programmatically.`,
1309
+ shouldBeReported: false,
1310
+ },
1311
+ VALUE_NOT_FOUND_FOR_VAR: {
1312
+ number: 1201,
1313
+ title: "Configuration variable is not set",
1314
+ message:
1315
+ "Cannot find a value for the configuration variable '%value%'. Use 'npx hardhat vars set %value%' to set it or 'npx hardhat vars setup' to list all the configuration variables used by this project.",
1316
+ description: `Cannot find a value for a mandatory configuration variable.
1317
+
1318
+ Use 'npx hardhat vars set VAR' to set it or 'npx hardhat vars setup' to list all the configuration variables used by this project.`,
1319
+ shouldBeReported: false,
1320
+ },
1321
+ INVALID_CONFIG_VAR_NAME: {
1322
+ number: 1202,
1323
+ title: "Invalid name for a configuration variable",
1324
+ message:
1325
+ "Invalid name for a configuration variable: '%value%'. Configuration variables can only have alphanumeric characters and underscores, and they cannot start with a number.",
1326
+ description: `Invalid name for a configuration variable.
1327
+
1328
+ Configuration variables can only have alphanumeric characters and underscores, and they cannot start with a number.`,
1329
+ shouldBeReported: false,
1330
+ },
1331
+ INVALID_EMPTY_VALUE: {
1332
+ number: 1203,
1333
+ title: "Invalid empty value for configuration variable",
1334
+ message: "A configuration variable cannot have an empty value.",
1335
+ description: "A configuration variable cannot have an empty value.",
1336
+ shouldBeReported: false,
1337
+ },
1338
+ },
1301
1339
  };
1302
1340
 
1303
1341
  /**
@@ -6,4 +6,5 @@ import "../../../builtin-tasks/flatten";
6
6
  import "../../../builtin-tasks/help";
7
7
  import "../../../builtin-tasks/node";
8
8
  import "../../../builtin-tasks/run";
9
+ import "../../../builtin-tasks/vars";
9
10
  import "../../../builtin-tasks/test";
@@ -0,0 +1,124 @@
1
+ import debug from "debug";
2
+ import { VarsManager } from "./vars-manager";
3
+
4
+ const log = debug("hardhat:core:vars:varsManagerSetup");
5
+
6
+ /**
7
+ * This class is ONLY used when collecting the required and optional vars that have to be filled by the user
8
+ */
9
+ export class VarsManagerSetup extends VarsManager {
10
+ private readonly _getVarsAlreadySet: Set<string>;
11
+ private readonly _hasVarsAlreadySet: Set<string>;
12
+ private readonly _getVarsWithDefaultValueAlreadySet: Set<string>;
13
+
14
+ private readonly _getVarsToSet: Set<string>;
15
+ private readonly _hasVarsToSet: Set<string>;
16
+ private readonly _getVarsWithDefaultValueToSet: Set<string>;
17
+
18
+ constructor(varsFilePath: string) {
19
+ log("Creating a new instance of VarsManagerSetup");
20
+
21
+ super(varsFilePath);
22
+
23
+ this._getVarsAlreadySet = new Set();
24
+ this._hasVarsAlreadySet = new Set();
25
+ this._getVarsWithDefaultValueAlreadySet = new Set();
26
+
27
+ this._getVarsToSet = new Set();
28
+ this._hasVarsToSet = new Set();
29
+ this._getVarsWithDefaultValueToSet = new Set();
30
+ }
31
+
32
+ // Checks if the key exists, and updates sets accordingly.
33
+ // Ignore the parameter 'includeEnvs' defined in the parent class because during setup env vars are ignored.
34
+ public has(key: string): boolean {
35
+ log(`function 'has' called with key '${key}'`);
36
+
37
+ const hasKey = super.has(key);
38
+
39
+ if (hasKey) {
40
+ this._hasVarsAlreadySet.add(key);
41
+ } else {
42
+ this._hasVarsToSet.add(key);
43
+ }
44
+
45
+ return hasKey;
46
+ }
47
+
48
+ // Gets the value for the provided key, and updates sets accordingly.
49
+ // Ignore the parameter 'includeEnvs' defined in the parent class because during setup env vars are ignored.
50
+ public get(key: string, defaultValue?: string): string {
51
+ log(`function 'get' called with key '${key}'`);
52
+
53
+ const varAlreadySet = super.has(key);
54
+
55
+ if (varAlreadySet) {
56
+ if (defaultValue !== undefined) {
57
+ this._getVarsWithDefaultValueAlreadySet.add(key);
58
+ } else {
59
+ this._getVarsAlreadySet.add(key);
60
+ }
61
+ } else {
62
+ if (defaultValue !== undefined) {
63
+ this._getVarsWithDefaultValueToSet.add(key);
64
+ } else {
65
+ this._getVarsToSet.add(key);
66
+ }
67
+ }
68
+
69
+ // Do not return undefined to avoid throwing an error
70
+ return super.get(key, defaultValue) ?? "";
71
+ }
72
+
73
+ public getRequiredVarsAlreadySet(): string[] {
74
+ return this._getRequired(this._getVarsAlreadySet, this._hasVarsAlreadySet);
75
+ }
76
+
77
+ public getOptionalVarsAlreadySet(): string[] {
78
+ return this._getOptionals(
79
+ this._getVarsAlreadySet,
80
+ this._hasVarsAlreadySet,
81
+ this._getVarsWithDefaultValueAlreadySet
82
+ );
83
+ }
84
+
85
+ public getRequiredVarsToSet(): string[] {
86
+ return this._getRequired(this._getVarsToSet, this._hasVarsToSet);
87
+ }
88
+
89
+ public getOptionalVarsToSet(): string[] {
90
+ return this._getOptionals(
91
+ this._getVarsToSet,
92
+ this._hasVarsToSet,
93
+ this._getVarsWithDefaultValueToSet
94
+ );
95
+ }
96
+
97
+ // How to calculate required and optional variables:
98
+ //
99
+ // G = get function
100
+ // H = has function
101
+ // GD = get function with default value
102
+ //
103
+ // optional variables = H + (GD - G)
104
+ // required variables = G - H
105
+ private _getRequired(getVars: Set<string>, hasVars: Set<string>): string[] {
106
+ return Array.from(getVars).filter((k) => !hasVars.has(k));
107
+ }
108
+
109
+ private _getOptionals(
110
+ getVars: Set<string>,
111
+ hasVars: Set<string>,
112
+ getVarsWithDefault: Set<string>
113
+ ): string[] {
114
+ const result = new Set(hasVars);
115
+
116
+ for (const k of getVarsWithDefault) {
117
+ if (!getVars.has(k)) {
118
+ result.add(k);
119
+ }
120
+ }
121
+
122
+ return Array.from(result);
123
+ }
124
+ }