@nomicfoundation/hardhat-utils 3.0.0-next.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 (173) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +5 -0
  3. package/dist/src/bigint.d.ts +32 -0
  4. package/dist/src/bigint.d.ts.map +1 -0
  5. package/dist/src/bigint.js +54 -0
  6. package/dist/src/bigint.js.map +1 -0
  7. package/dist/src/bytecode.d.ts +27 -0
  8. package/dist/src/bytecode.d.ts.map +1 -0
  9. package/dist/src/bytecode.js +60 -0
  10. package/dist/src/bytecode.js.map +1 -0
  11. package/dist/src/bytes.d.ts +34 -0
  12. package/dist/src/bytes.d.ts.map +1 -0
  13. package/dist/src/bytes.js +47 -0
  14. package/dist/src/bytes.js.map +1 -0
  15. package/dist/src/ci.d.ts +7 -0
  16. package/dist/src/ci.d.ts.map +1 -0
  17. package/dist/src/ci.js +18 -0
  18. package/dist/src/ci.js.map +1 -0
  19. package/dist/src/common-errors.d.ts +5 -0
  20. package/dist/src/common-errors.d.ts.map +1 -0
  21. package/dist/src/common-errors.js +7 -0
  22. package/dist/src/common-errors.js.map +1 -0
  23. package/dist/src/crypto.d.ts +25 -0
  24. package/dist/src/crypto.d.ts.map +1 -0
  25. package/dist/src/crypto.js +32 -0
  26. package/dist/src/crypto.js.map +1 -0
  27. package/dist/src/date.d.ts +21 -0
  28. package/dist/src/date.d.ts.map +1 -0
  29. package/dist/src/date.js +27 -0
  30. package/dist/src/date.js.map +1 -0
  31. package/dist/src/debug.d.ts +16 -0
  32. package/dist/src/debug.d.ts.map +1 -0
  33. package/dist/src/debug.js +28 -0
  34. package/dist/src/debug.js.map +1 -0
  35. package/dist/src/error.d.ts +80 -0
  36. package/dist/src/error.d.ts.map +1 -0
  37. package/dist/src/error.js +97 -0
  38. package/dist/src/error.js.map +1 -0
  39. package/dist/src/errors/bytecode.d.ts +18 -0
  40. package/dist/src/errors/bytecode.d.ts.map +1 -0
  41. package/dist/src/errors/bytecode.js +59 -0
  42. package/dist/src/errors/bytecode.js.map +1 -0
  43. package/dist/src/errors/fs.d.ts +25 -0
  44. package/dist/src/errors/fs.d.ts.map +1 -0
  45. package/dist/src/errors/fs.js +41 -0
  46. package/dist/src/errors/fs.js.map +1 -0
  47. package/dist/src/errors/package.d.ts +8 -0
  48. package/dist/src/errors/package.d.ts.map +1 -0
  49. package/dist/src/errors/package.js +12 -0
  50. package/dist/src/errors/package.js.map +1 -0
  51. package/dist/src/errors/request.d.ts +25 -0
  52. package/dist/src/errors/request.d.ts.map +1 -0
  53. package/dist/src/errors/request.js +64 -0
  54. package/dist/src/errors/request.js.map +1 -0
  55. package/dist/src/errors/subprocess.d.ts +8 -0
  56. package/dist/src/errors/subprocess.d.ts.map +1 -0
  57. package/dist/src/errors/subprocess.js +12 -0
  58. package/dist/src/errors/subprocess.js.map +1 -0
  59. package/dist/src/eth.d.ts +56 -0
  60. package/dist/src/eth.d.ts.map +1 -0
  61. package/dist/src/eth.js +78 -0
  62. package/dist/src/eth.js.map +1 -0
  63. package/dist/src/fs.d.ts +241 -0
  64. package/dist/src/fs.d.ts.map +1 -0
  65. package/dist/src/fs.js +581 -0
  66. package/dist/src/fs.js.map +1 -0
  67. package/dist/src/global-dir.d.ts +28 -0
  68. package/dist/src/global-dir.d.ts.map +1 -0
  69. package/dist/src/global-dir.js +42 -0
  70. package/dist/src/global-dir.js.map +1 -0
  71. package/dist/src/hex.d.ts +117 -0
  72. package/dist/src/hex.d.ts.map +1 -0
  73. package/dist/src/hex.js +187 -0
  74. package/dist/src/hex.js.map +1 -0
  75. package/dist/src/internal/bytecode.d.ts +45 -0
  76. package/dist/src/internal/bytecode.d.ts.map +1 -0
  77. package/dist/src/internal/bytecode.js +73 -0
  78. package/dist/src/internal/bytecode.js.map +1 -0
  79. package/dist/src/internal/eth.d.ts +21 -0
  80. package/dist/src/internal/eth.d.ts.map +1 -0
  81. package/dist/src/internal/eth.js +58 -0
  82. package/dist/src/internal/eth.js.map +1 -0
  83. package/dist/src/internal/global-dir.d.ts +4 -0
  84. package/dist/src/internal/global-dir.d.ts.map +1 -0
  85. package/dist/src/internal/global-dir.js +6 -0
  86. package/dist/src/internal/global-dir.js.map +1 -0
  87. package/dist/src/internal/hex.d.ts +2 -0
  88. package/dist/src/internal/hex.d.ts.map +1 -0
  89. package/dist/src/internal/hex.js +16 -0
  90. package/dist/src/internal/hex.js.map +1 -0
  91. package/dist/src/internal/lang.d.ts +2 -0
  92. package/dist/src/internal/lang.d.ts.map +1 -0
  93. package/dist/src/internal/lang.js +9 -0
  94. package/dist/src/internal/lang.js.map +1 -0
  95. package/dist/src/internal/package.d.ts +2 -0
  96. package/dist/src/internal/package.d.ts.map +1 -0
  97. package/dist/src/internal/package.js +15 -0
  98. package/dist/src/internal/package.js.map +1 -0
  99. package/dist/src/internal/request.d.ts +20 -0
  100. package/dist/src/internal/request.d.ts.map +1 -0
  101. package/dist/src/internal/request.js +101 -0
  102. package/dist/src/internal/request.js.map +1 -0
  103. package/dist/src/lang.d.ts +30 -0
  104. package/dist/src/lang.d.ts.map +1 -0
  105. package/dist/src/lang.js +41 -0
  106. package/dist/src/lang.js.map +1 -0
  107. package/dist/src/number.d.ts +23 -0
  108. package/dist/src/number.d.ts.map +1 -0
  109. package/dist/src/number.js +30 -0
  110. package/dist/src/number.js.map +1 -0
  111. package/dist/src/package.d.ts +75 -0
  112. package/dist/src/package.d.ts.map +1 -0
  113. package/dist/src/package.js +97 -0
  114. package/dist/src/package.js.map +1 -0
  115. package/dist/src/path.d.ts +26 -0
  116. package/dist/src/path.d.ts.map +1 -0
  117. package/dist/src/path.js +38 -0
  118. package/dist/src/path.js.map +1 -0
  119. package/dist/src/request.d.ts +118 -0
  120. package/dist/src/request.d.ts.map +1 -0
  121. package/dist/src/request.js +208 -0
  122. package/dist/src/request.js.map +1 -0
  123. package/dist/src/stream.d.ts +10 -0
  124. package/dist/src/stream.d.ts.map +1 -0
  125. package/dist/src/stream.js +16 -0
  126. package/dist/src/stream.js.map +1 -0
  127. package/dist/src/string.d.ts +45 -0
  128. package/dist/src/string.d.ts.map +1 -0
  129. package/dist/src/string.js +60 -0
  130. package/dist/src/string.js.map +1 -0
  131. package/dist/src/subprocess.d.ts +13 -0
  132. package/dist/src/subprocess.d.ts.map +1 -0
  133. package/dist/src/subprocess.js +33 -0
  134. package/dist/src/subprocess.js.map +1 -0
  135. package/dist/src/synchronization.d.ts +6 -0
  136. package/dist/src/synchronization.d.ts.map +1 -0
  137. package/dist/src/synchronization.js +107 -0
  138. package/dist/src/synchronization.js.map +1 -0
  139. package/package.json +90 -0
  140. package/src/bigint.ts +61 -0
  141. package/src/bytecode.ts +90 -0
  142. package/src/bytes.ts +51 -0
  143. package/src/ci.ts +19 -0
  144. package/src/common-errors.ts +7 -0
  145. package/src/crypto.ts +35 -0
  146. package/src/date.ts +28 -0
  147. package/src/debug.ts +38 -0
  148. package/src/error.ts +105 -0
  149. package/src/errors/bytecode.ts +75 -0
  150. package/src/errors/fs.ts +47 -0
  151. package/src/errors/package.ts +13 -0
  152. package/src/errors/request.ts +84 -0
  153. package/src/errors/subprocess.ts +17 -0
  154. package/src/eth.ts +91 -0
  155. package/src/fs.ts +678 -0
  156. package/src/global-dir.ts +51 -0
  157. package/src/hex.ts +232 -0
  158. package/src/internal/bytecode.ts +129 -0
  159. package/src/internal/eth.ts +71 -0
  160. package/src/internal/global-dir.ts +10 -0
  161. package/src/internal/hex.ts +21 -0
  162. package/src/internal/lang.ts +12 -0
  163. package/src/internal/package.ts +15 -0
  164. package/src/internal/request.ts +165 -0
  165. package/src/lang.ts +48 -0
  166. package/src/number.ts +38 -0
  167. package/src/package.ts +143 -0
  168. package/src/path.ts +45 -0
  169. package/src/request.ts +341 -0
  170. package/src/stream.ts +16 -0
  171. package/src/string.ts +69 -0
  172. package/src/subprocess.ts +46 -0
  173. package/src/synchronization.ts +126 -0
@@ -0,0 +1,51 @@
1
+ import { generatePaths, HARDHAT_PACKAGE_NAME } from "./internal/global-dir.js";
2
+
3
+ import { ensureDir } from "@nomicfoundation/hardhat-utils/fs";
4
+
5
+ /**
6
+ * Returns the configuration directory path for a given package (defaults to "hardhat").
7
+ * Ensures that the directory exists before returning the path.
8
+ *
9
+ * @param packageName The name of the package for which to generate paths. Defaults to "hardhat" if no package name is provided.
10
+ * @returns The path to the hardhat configuration directory.
11
+ * @throws FileSystemAccessError for any error.
12
+ */
13
+ export async function getConfigDir(
14
+ packageName: string = HARDHAT_PACKAGE_NAME,
15
+ ): Promise<string> {
16
+ const { config } = await generatePaths(packageName);
17
+ await ensureDir(config);
18
+ return config;
19
+ }
20
+
21
+ /**
22
+ * Returns the cache directory path for a given package (defaults to "hardhat").
23
+ * Ensures that the directory exists before returning the path.
24
+ *
25
+ * @param packageName The name of the package for which to generate paths. Defaults to "hardhat" if no package name is provided.
26
+ * @returns The path to the hardhat cache directory.
27
+ * @throws FileSystemAccessError for any error.
28
+ */
29
+ export async function getCacheDir(
30
+ packageName: string = HARDHAT_PACKAGE_NAME,
31
+ ): Promise<string> {
32
+ const { cache } = await generatePaths(packageName);
33
+ await ensureDir(cache);
34
+ return cache;
35
+ }
36
+
37
+ /**
38
+ * Returns the telemetry directory path for a given package (defaults to "hardhat").
39
+ * Ensures that the directory exists before returning the path.
40
+ *
41
+ * @param packageName The name of the package for which to generate paths. Defaults to "hardhat" if no package name is provided.
42
+ * @returns A promise that resolves to the path of the telemetry directory.
43
+ * @throws FileSystemAccessError for any error.
44
+ */
45
+ export async function getTelemetryDir(
46
+ packageName: string = HARDHAT_PACKAGE_NAME,
47
+ ): Promise<string> {
48
+ const { data } = await generatePaths(packageName);
49
+ await ensureDir(data);
50
+ return data;
51
+ }
package/src/hex.ts ADDED
@@ -0,0 +1,232 @@
1
+ import { InvalidParameterError } from "./common-errors.js";
2
+ import { padToEven } from "./internal/hex.js";
3
+
4
+ export type PrefixedHexString = `0x${string}`;
5
+
6
+ /**
7
+ * Converts a non-negative safe integer or bigint to a hexadecimal string.
8
+ *
9
+ * @param value The number to convert.
10
+ * @returns The hexadecimal representation of the number.
11
+ * @throws InvalidParameterError If the input is not a safe integer or is negative.
12
+ */
13
+ export function numberToHexString(value: number | bigint): PrefixedHexString {
14
+ if (
15
+ value < 0 ||
16
+ (typeof value === "number" && !Number.isSafeInteger(value))
17
+ ) {
18
+ throw new InvalidParameterError(
19
+ `Expected a non-negative safe integer or bigint. Received: ${value}`,
20
+ );
21
+ }
22
+
23
+ return `0x${value.toString(16)}`;
24
+ }
25
+
26
+ /**
27
+ * Converts a hexadecimal string to a bigint. The string must be a valid
28
+ * hexadecimal string. The string may be prefixed with "0x" or not. The
29
+ * empty string is considered a valid hexadecimal string, so is the string
30
+ * "0x" and will be converted to 0.
31
+ *
32
+ * @param hexString The hexadecimal string to convert. It must be a valid
33
+ * hexadecimal string.
34
+ * @returns The bigint representation of the hexadecimal string.
35
+ * @throws InvalidParameterError If the input is not a hexadecimal string.
36
+ */
37
+ export function hexStringToBigInt(hexString: string): bigint {
38
+ if (!isHexString(hexString)) {
39
+ throw new InvalidParameterError(
40
+ `Expected a valid hexadecimal string. Received: ${hexString}`,
41
+ );
42
+ }
43
+ // Prefix the string as it is required to make BigInt interpret it as a
44
+ // hexadecimal number.
45
+ let prefixedHexString = getPrefixedHexString(hexString);
46
+ // BigInt does not support "0x" as a valid hexadecimal number, so we need to
47
+ // add a zero after the prefix if the string is "0x".
48
+ prefixedHexString = prefixedHexString === "0x" ? "0x0" : prefixedHexString;
49
+
50
+ const bigInt = BigInt(prefixedHexString);
51
+
52
+ return bigInt;
53
+ }
54
+
55
+ /**
56
+ * Converts a hexadecimal string to a number. The string must be a valid
57
+ * hexadecimal string. The string may be prefixed with "0x" or not. The
58
+ * empty string is considered a valid hexadecimal string, so is the string
59
+ * "0x" and will be converted to 0.
60
+ *
61
+ * @param hexString The hexadecimal string to convert. It must be a valid
62
+ * hexadecimal string.
63
+ * @returns The number representation of the hexadecimal string.
64
+ * @throws InvalidParameterError If the input is not a hexadecimal string or the value exceeds the Number.MAX_SAFE_INTEGER limit.
65
+ */
66
+ export function hexStringToNumber(hexString: string): number {
67
+ if (!isHexString(hexString)) {
68
+ throw new InvalidParameterError(
69
+ `Expected a valid hexadecimal string. Received: ${hexString}`,
70
+ );
71
+ }
72
+
73
+ // Prefix the string as it is required to make parseInt interpret it as a
74
+ // hexadecimal number.
75
+ let prefixedHexString = getPrefixedHexString(hexString);
76
+
77
+ // Handle the special case where the string is "0x".
78
+ prefixedHexString = prefixedHexString === "0x" ? "0x0" : prefixedHexString;
79
+
80
+ const numberValue = parseInt(prefixedHexString, 16);
81
+
82
+ if (numberValue > Number.MAX_SAFE_INTEGER) {
83
+ throw new InvalidParameterError(
84
+ `Value exceeds the safe integer limit. Received: ${hexString}`,
85
+ );
86
+ }
87
+
88
+ return numberValue;
89
+ }
90
+
91
+ /**
92
+ * Converts a Uint8Array to a hexadecimal string.
93
+ *
94
+ * @param bytes The bytes to convert.
95
+ * @returns PrefixedHexString The hexadecimal representation of the bytes.
96
+ */
97
+ export function bytesToHexString(bytes: Uint8Array): PrefixedHexString {
98
+ return getPrefixedHexString(Buffer.from(bytes).toString("hex"));
99
+ }
100
+
101
+ /**
102
+ * Converts a hexadecimal string to a Uint8Array. The string must be a valid
103
+ * hexadecimal string. The string may be prefixed with "0x" or not. The empty
104
+ * string is considered a valid hexadecimal string, so is the string "0x" and
105
+ * will be converted to Uint8Array([0]).
106
+ *
107
+ * @param hexString The hexadecimal string to convert.
108
+ * @returns The byte representation of the hexadecimal string.
109
+ * @throws InvalidParameterError If the input is not a hexadecimal string.
110
+ */
111
+ export function hexStringToBytes(hexString: string): Uint8Array {
112
+ if (!isHexString(hexString)) {
113
+ throw new InvalidParameterError(
114
+ `Expected a valid hexadecimal string. Received: ${hexString}`,
115
+ );
116
+ }
117
+
118
+ // Pad the hex string if it's odd, as Buffer.from will truncate it
119
+ // the last character if it's not a full byte.
120
+ // See: https://nodejs.org/api/buffer.html#buffers-and-character-encodings
121
+ const unprefixedHexString = getUnprefixedHexString(padToEven(hexString));
122
+ return Uint8Array.from(Buffer.from(unprefixedHexString, "hex"));
123
+ }
124
+
125
+ /**
126
+ * Normalizes and validates a string that represents a hexadecimal number.
127
+ * The normalization process includes trimming any leading or trailing
128
+ * whitespace, converting all characters to lowercase, and ensuring the string
129
+ * has a "0x" prefix. The validation process checks if the string is a valid
130
+ * hexadecimal string.
131
+ *
132
+ * @param hexString The hex string to normalize.
133
+ * @returns The normalized hexadecimal string.
134
+ */
135
+ export function normalizeHexString(hexString: string): PrefixedHexString {
136
+ const normalizedHexString = hexString.trim().toLowerCase();
137
+
138
+ if (!isHexString(normalizedHexString)) {
139
+ throw new InvalidParameterError(
140
+ `Expected a valid hexadecimal string. Received: ${hexString}`,
141
+ );
142
+ }
143
+
144
+ return getPrefixedHexString(normalizedHexString);
145
+ }
146
+
147
+ /**
148
+ * Checks if a string starts with "0x" (case-insensitive).
149
+ * This function does not validate the input.
150
+ *
151
+ * @param hexString The string to check.
152
+ * @returns True if the string starts with "0x", false otherwise.
153
+ */
154
+ export function isPrefixedHexString(
155
+ hexString: string,
156
+ ): hexString is PrefixedHexString {
157
+ return hexString.toLowerCase().startsWith("0x");
158
+ }
159
+
160
+ /**
161
+ * Removes the "0x" prefix from a hexadecimal string.
162
+ * If the string is not prefixed, it is returned as is.
163
+ * This function does not validate the input.
164
+ *
165
+ * @param hexString The hexadecimal string.
166
+ * @returns The hexadecimal string without the "0x" prefix.
167
+ */
168
+ export function getUnprefixedHexString(hexString: string): string {
169
+ return isPrefixedHexString(hexString) ? hexString.substring(2) : hexString;
170
+ }
171
+
172
+ /**
173
+ * Adds the "0x" prefix to a hexadecimal string.
174
+ * If the string is already prefixed, it is returned as is.
175
+ * This function does not validate the input.
176
+ *
177
+ * @param hexString The hexadecimal string.
178
+ * @returns The hexadecimal string with the "0x" prefix.
179
+ */
180
+ export function getPrefixedHexString(hexString: string): PrefixedHexString {
181
+ return isPrefixedHexString(hexString) ? hexString : `0x${hexString}`;
182
+ }
183
+
184
+ /**
185
+ * Checks if a value is a hexadecimal string. The string may be prefixed with
186
+ * "0x" or not. The empty string is considered a valid hexadecimal string, so
187
+ * is the string "0x".
188
+ *
189
+ * @param value The value to check.
190
+ * @returns True if the value is a hexadecimal string, false otherwise.
191
+ */
192
+ export function isHexString(value: unknown): boolean {
193
+ return typeof value === "string" && /^(?:0x)?[0-9a-f]*$/i.test(value);
194
+ }
195
+
196
+ /**
197
+ * Removes leading zeros from a hexadecimal string, unless the string
198
+ * represents the number zero ("0x0").
199
+ * This function does not validate the input.
200
+ *
201
+ * @param hexString The hexadecimal string.
202
+ * @returns The hexadecimal string without leading zeros.
203
+ */
204
+ export function unpadHexString(hexString: string): string {
205
+ const unprefixedHexString = getUnprefixedHexString(hexString);
206
+ const unpaddedHexString = unprefixedHexString.replace(/^0+/, "");
207
+ return unpaddedHexString === "" ? "0x0" : `0x${unpaddedHexString}`;
208
+ }
209
+
210
+ /**
211
+ * Pads a hexadecimal string with zeros on the left to a specified length, or
212
+ * truncates it from the left if it's too long.
213
+ * This function does not validate the input.
214
+ *
215
+ * @param hexString The hexadecimal string to pad.
216
+ * @param length The desired length of the hexadecimal string.
217
+ * @returns The padded hexadecimal string.
218
+ */
219
+ export function setLengthLeft(
220
+ hexString: string,
221
+ length: number,
222
+ ): PrefixedHexString {
223
+ const unprefixedHexString = getUnprefixedHexString(hexString);
224
+
225
+ // if the string is longer than the desired length, truncate it
226
+ if (unprefixedHexString.length > length) {
227
+ return `0x${unprefixedHexString.slice(-length)}`;
228
+ }
229
+
230
+ const paddedHexString = unprefixedHexString.padStart(length, "0");
231
+ return `0x${paddedHexString}`;
232
+ }
@@ -0,0 +1,129 @@
1
+ import type { PrefixedHexString } from "../hex.js";
2
+
3
+ import {
4
+ AmbiguousLibraryNameError,
5
+ InvalidLibraryAddressError,
6
+ MissingLibrariesError,
7
+ OverlappingLibrariesError,
8
+ UnnecessaryLibraryError,
9
+ } from "../errors/bytecode.js";
10
+ import { isAddress } from "../eth.js";
11
+
12
+ export interface Artifact {
13
+ bytecode: string;
14
+ linkReferences: {
15
+ [sourceName: string]: {
16
+ [libraryName: string]: Array<{ start: number; length: number }>;
17
+ };
18
+ };
19
+ }
20
+
21
+ export interface LibraryLink {
22
+ sourceName: string;
23
+ libraryName: string;
24
+ libraryFqn: string;
25
+ address: string;
26
+ }
27
+
28
+ export interface LibraryAddresses {
29
+ [contractName: string]: PrefixedHexString;
30
+ }
31
+
32
+ /**
33
+ * Check that the provided library addresses are valid Ethereum addresses.
34
+ * If any of them are not, an InvalidLibraryAddressError is thrown.
35
+ */
36
+ export function checkProvidedLibraryAddresses(
37
+ providedLibraries: LibraryAddresses,
38
+ ): void {
39
+ const librariesWithInvalidAddresses: LibraryAddresses = {};
40
+ for (const [name, address] of Object.entries(providedLibraries)) {
41
+ if (!isAddress(address)) {
42
+ librariesWithInvalidAddresses[name] = address;
43
+ }
44
+ }
45
+
46
+ if (Object.keys(librariesWithInvalidAddresses).length === 0) {
47
+ return;
48
+ }
49
+
50
+ throw new InvalidLibraryAddressError(librariesWithInvalidAddresses);
51
+ }
52
+
53
+ /**
54
+ * Check that the provided libraries can't be resolved to multiple libraries, or
55
+ * that they are not needed by the contract. If any of these conditions are met,
56
+ * an AmbiguousLibraryNameError or an UnnecessaryLibraryError is thrown.
57
+ */
58
+ export function checkAmbiguousOrUnnecessaryLinks(
59
+ providedLibraries: LibraryAddresses,
60
+ neededLibraries: LibraryLink[],
61
+ ): void {
62
+ const ambiguousLibraries: Record<string, LibraryLink[]> = {};
63
+ const unnecessaryLibraries: string[] = [];
64
+
65
+ for (const providedLibraryName of Object.keys(providedLibraries)) {
66
+ const matchingLibraries = neededLibraries.filter(
67
+ ({ libraryName, libraryFqn }) =>
68
+ libraryName === providedLibraryName ||
69
+ libraryFqn === providedLibraryName,
70
+ );
71
+
72
+ if (matchingLibraries.length > 1) {
73
+ ambiguousLibraries[providedLibraryName] = matchingLibraries;
74
+ } else if (matchingLibraries.length === 0) {
75
+ unnecessaryLibraries.push(providedLibraryName);
76
+ }
77
+ }
78
+
79
+ if (Object.keys(ambiguousLibraries).length > 0) {
80
+ throw new AmbiguousLibraryNameError(ambiguousLibraries);
81
+ }
82
+
83
+ if (unnecessaryLibraries.length > 0) {
84
+ throw new UnnecessaryLibraryError(unnecessaryLibraries);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Check that each library is only provided once, either by its name or its
90
+ * fully qualified name. If a library is provided more than once, an
91
+ * OverlappingLibrariesError is thrown.
92
+ */
93
+ export function checkOverlappingLibraryNames(
94
+ providedLibraries: LibraryAddresses,
95
+ neededLibraries: LibraryLink[],
96
+ ): void {
97
+ const overlappingLibraries = neededLibraries
98
+ .filter(
99
+ ({ libraryName, libraryFqn }) =>
100
+ providedLibraries[libraryFqn] !== undefined &&
101
+ providedLibraries[libraryName] !== undefined,
102
+ )
103
+ .map(({ libraryFqn }) => libraryFqn);
104
+
105
+ if (overlappingLibraries.length === 0) {
106
+ return;
107
+ }
108
+
109
+ throw new OverlappingLibrariesError(overlappingLibraries);
110
+ }
111
+
112
+ /**
113
+ * Check if the needed libraries have all their addresses resolved. If an
114
+ * address is missing, it means that the user didn't provide it in the
115
+ * providedLibraries map. In that case, an MissingLibrariesError is thrown.
116
+ */
117
+ export function checkMissingLibraryAddresses(
118
+ neededLibraries: LibraryLink[],
119
+ ): void {
120
+ const missingLibraries = neededLibraries
121
+ .filter(({ address }) => address === undefined)
122
+ .map(({ libraryFqn }) => libraryFqn);
123
+
124
+ if (missingLibraries.length === 0) {
125
+ return;
126
+ }
127
+
128
+ throw new MissingLibrariesError(missingLibraries);
129
+ }
@@ -0,0 +1,71 @@
1
+ import { utf8StringToBytes } from "../bytes.js";
2
+ import { keccak256 } from "../crypto.js";
3
+ import { bytesToHexString, getUnprefixedHexString } from "../hex.js";
4
+
5
+ class RandomBytesGenerator {
6
+ #nextValue: Uint8Array;
7
+
8
+ private constructor(nextValue: Uint8Array) {
9
+ this.#nextValue = nextValue;
10
+ }
11
+
12
+ public static async create(seed: string): Promise<RandomBytesGenerator> {
13
+ const nextValue = await keccak256(Buffer.from(seed));
14
+
15
+ return new RandomBytesGenerator(nextValue);
16
+ }
17
+
18
+ public async next(): Promise<Uint8Array> {
19
+ const valueToReturn = this.#nextValue;
20
+
21
+ this.#nextValue = await keccak256(this.#nextValue);
22
+
23
+ return valueToReturn;
24
+ }
25
+ }
26
+
27
+ let hashGenerator: RandomBytesGenerator | null = null;
28
+ let addressGenerator: RandomBytesGenerator | null = null;
29
+
30
+ export async function getHashGenerator(): Promise<RandomBytesGenerator> {
31
+ if (hashGenerator === null) {
32
+ hashGenerator = await RandomBytesGenerator.create("hashSeed");
33
+ }
34
+ return hashGenerator;
35
+ }
36
+
37
+ export async function getAddressGenerator(): Promise<RandomBytesGenerator> {
38
+ if (addressGenerator === null) {
39
+ addressGenerator = await RandomBytesGenerator.create("addressSeed");
40
+ }
41
+ return addressGenerator;
42
+ }
43
+
44
+ /**
45
+ * Checks if a value is an Ethereum address and if the checksum is valid.
46
+ * This method is a a an adaptation of the ethereumjs methods at this link:
47
+ * https://github.com/ethereumjs/ethereumjs-monorepo/blob/47f388bfeec553519d11259fee7e7161a77b29b2/packages/util/src/account.ts#L440-L478
48
+ * The main differences are:
49
+ * - the two methods have been merged into one
50
+ * - tha `eip1191ChainId` parameter has been removed.
51
+ * - the code has been modified to use the `hardhat-utils` methods
52
+ *
53
+ */
54
+ export async function isValidChecksum(hexAddress: string): Promise<boolean> {
55
+ const address = getUnprefixedHexString(hexAddress).toLowerCase();
56
+
57
+ const bytes = utf8StringToBytes(address);
58
+
59
+ const hash = bytesToHexString(await keccak256(bytes)).slice(2);
60
+
61
+ let ret = "";
62
+ for (let i = 0; i < address.length; i++) {
63
+ if (parseInt(hash[i], 16) >= 8) {
64
+ ret += address[i].toUpperCase();
65
+ } else {
66
+ ret += address[i];
67
+ }
68
+ }
69
+
70
+ return `0x${ret}` === hexAddress;
71
+ }
@@ -0,0 +1,10 @@
1
+ import type envPaths from "env-paths";
2
+
3
+ export const HARDHAT_PACKAGE_NAME = "hardhat";
4
+
5
+ export async function generatePaths(
6
+ packageName: string,
7
+ ): Promise<envPaths.Paths> {
8
+ const { default: envPaths } = await import("env-paths");
9
+ return envPaths(packageName);
10
+ }
@@ -0,0 +1,21 @@
1
+ import {
2
+ getPrefixedHexString,
3
+ getUnprefixedHexString,
4
+ isPrefixedHexString,
5
+ } from "../hex.js";
6
+
7
+ export function padToEven(value: string): string {
8
+ const isPrefixed = isPrefixedHexString(value);
9
+ const unprefixed = getUnprefixedHexString(value);
10
+
11
+ let padded;
12
+ if (unprefixed.length === 0) {
13
+ // Pad the empty string with a single zero, as Buffer.from([]) will not
14
+ // interpret it correctly otherwise.
15
+ padded = "00";
16
+ } else {
17
+ padded = unprefixed.length % 2 === 0 ? unprefixed : `0${unprefixed}`;
18
+ }
19
+
20
+ return isPrefixed ? getPrefixedHexString(padded) : padded;
21
+ }
@@ -0,0 +1,12 @@
1
+ import type rfdcT from "rfdc";
2
+
3
+ let clone: ReturnType<typeof rfdcT> | null = null;
4
+ export async function getDeepCloneFunction(): Promise<<T>(input: T) => T> {
5
+ const { default: rfdc } = await import("rfdc");
6
+
7
+ if (clone === null) {
8
+ clone = rfdc();
9
+ }
10
+
11
+ return clone;
12
+ }
@@ -0,0 +1,15 @@
1
+ import { fileURLToPath } from "node:url";
2
+
3
+ export function getFilePath(filePathOrUrl: string): string | undefined {
4
+ if (filePathOrUrl.startsWith("file://")) {
5
+ try {
6
+ // This can throw on Windows if the url is malformed,
7
+ // so we catch it and return undefined
8
+ return fileURLToPath(filePathOrUrl);
9
+ } catch (_) {
10
+ return undefined;
11
+ }
12
+ }
13
+
14
+ return filePathOrUrl;
15
+ }