hardhat-deploy 2.0.0-next.61 → 2.0.0-next.62

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 (90) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +195 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/config/default.d.ts.map +1 -0
  6. package/dist/config/default.js.map +1 -0
  7. package/dist/config/get-config.d.ts.map +1 -0
  8. package/dist/config/get-config.js.map +1 -0
  9. package/dist/config/validation.d.ts.map +1 -0
  10. package/dist/config/validation.js.map +1 -0
  11. package/dist/generate-types.d.ts.map +1 -0
  12. package/dist/generate-types.js.map +1 -0
  13. package/dist/helpers.d.ts.map +1 -0
  14. package/dist/helpers.js.map +1 -0
  15. package/dist/hook-handlers/config.d.ts.map +1 -0
  16. package/dist/hook-handlers/config.js.map +1 -0
  17. package/dist/hook-handlers/solidity.d.ts.map +1 -0
  18. package/dist/hook-handlers/solidity.js.map +1 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/tasks/deploy.d.ts.map +1 -0
  22. package/dist/tasks/deploy.js.map +1 -0
  23. package/dist/type-extensions.d.ts.map +1 -0
  24. package/dist/type-extensions.js.map +1 -0
  25. package/dist/types.d.ts.map +1 -0
  26. package/dist/types.js.map +1 -0
  27. package/dist/utils/files.d.ts.map +1 -0
  28. package/dist/utils/files.js.map +1 -0
  29. package/package.json +15 -9
  30. package/src/cli.ts +244 -0
  31. package/templates/basic/README.md +44 -0
  32. package/templates/basic/contracts/Counter.sol +19 -0
  33. package/templates/basic/contracts/Counter.t.sol +29 -0
  34. package/templates/basic/deploy/01_deploy_counter.ts +13 -0
  35. package/templates/basic/hardhat.config.ts +50 -0
  36. package/templates/basic/package.json +31 -0
  37. package/templates/basic/pnpm-lock.yaml +1643 -0
  38. package/templates/basic/rocketh/config.ts +65 -0
  39. package/templates/basic/rocketh/deploy.ts +20 -0
  40. package/templates/basic/rocketh/environment.ts +22 -0
  41. package/templates/basic/test/Counter.ts +61 -0
  42. package/templates/basic/tsconfig.json +13 -0
  43. package/dist/esm/config/default.d.ts.map +0 -1
  44. package/dist/esm/config/default.js.map +0 -1
  45. package/dist/esm/config/get-config.d.ts.map +0 -1
  46. package/dist/esm/config/get-config.js.map +0 -1
  47. package/dist/esm/config/validation.d.ts.map +0 -1
  48. package/dist/esm/config/validation.js.map +0 -1
  49. package/dist/esm/generate-types.d.ts.map +0 -1
  50. package/dist/esm/generate-types.js.map +0 -1
  51. package/dist/esm/helpers.d.ts.map +0 -1
  52. package/dist/esm/helpers.js.map +0 -1
  53. package/dist/esm/hook-handlers/config.d.ts.map +0 -1
  54. package/dist/esm/hook-handlers/config.js.map +0 -1
  55. package/dist/esm/hook-handlers/solidity.d.ts.map +0 -1
  56. package/dist/esm/hook-handlers/solidity.js.map +0 -1
  57. package/dist/esm/index.d.ts.map +0 -1
  58. package/dist/esm/index.js.map +0 -1
  59. package/dist/esm/tasks/deploy.d.ts.map +0 -1
  60. package/dist/esm/tasks/deploy.js.map +0 -1
  61. package/dist/esm/type-extensions.d.ts.map +0 -1
  62. package/dist/esm/type-extensions.js.map +0 -1
  63. package/dist/esm/types.d.ts.map +0 -1
  64. package/dist/esm/types.js.map +0 -1
  65. package/dist/esm/utils/files.d.ts.map +0 -1
  66. package/dist/esm/utils/files.js.map +0 -1
  67. /package/dist/{esm/config → config}/default.d.ts +0 -0
  68. /package/dist/{esm/config → config}/default.js +0 -0
  69. /package/dist/{esm/config → config}/get-config.d.ts +0 -0
  70. /package/dist/{esm/config → config}/get-config.js +0 -0
  71. /package/dist/{esm/config → config}/validation.d.ts +0 -0
  72. /package/dist/{esm/config → config}/validation.js +0 -0
  73. /package/dist/{esm/generate-types.d.ts → generate-types.d.ts} +0 -0
  74. /package/dist/{esm/generate-types.js → generate-types.js} +0 -0
  75. /package/dist/{esm/helpers.d.ts → helpers.d.ts} +0 -0
  76. /package/dist/{esm/helpers.js → helpers.js} +0 -0
  77. /package/dist/{esm/hook-handlers → hook-handlers}/config.d.ts +0 -0
  78. /package/dist/{esm/hook-handlers → hook-handlers}/config.js +0 -0
  79. /package/dist/{esm/hook-handlers → hook-handlers}/solidity.d.ts +0 -0
  80. /package/dist/{esm/hook-handlers → hook-handlers}/solidity.js +0 -0
  81. /package/dist/{esm/index.d.ts → index.d.ts} +0 -0
  82. /package/dist/{esm/index.js → index.js} +0 -0
  83. /package/dist/{esm/tasks → tasks}/deploy.d.ts +0 -0
  84. /package/dist/{esm/tasks → tasks}/deploy.js +0 -0
  85. /package/dist/{esm/type-extensions.d.ts → type-extensions.d.ts} +0 -0
  86. /package/dist/{esm/type-extensions.js → type-extensions.js} +0 -0
  87. /package/dist/{esm/types.d.ts → types.d.ts} +0 -0
  88. /package/dist/{esm/types.js → types.js} +0 -0
  89. /package/dist/{esm/utils → utils}/files.d.ts +0 -0
  90. /package/dist/{esm/utils → utils}/files.js +0 -0
package/src/cli.ts ADDED
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { readFileSync, readdirSync, mkdirSync, copyFileSync, existsSync, writeFileSync, statSync } from 'fs';
5
+ import { join, dirname, basename } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import * as readline from 'readline';
8
+ import pkg from '../package.json' with { type: 'json' };
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ const program = new Command();
14
+
15
+ // Get the current version of hardhat-deploy
16
+ const getHardhatDeployVersion = (): string => {
17
+ return pkg.version;
18
+ };
19
+
20
+ const askFolder = async (): Promise<string> => {
21
+ const rl = readline.createInterface({
22
+ input: process.stdin,
23
+ output: process.stdout,
24
+ });
25
+
26
+ return new Promise((resolve) => {
27
+ rl.question('Enter folder path (default: ./): ', (answer) => {
28
+ rl.close();
29
+ resolve(answer.trim() || './');
30
+ });
31
+ });
32
+ };
33
+
34
+ const askAutoInstall = async (): Promise<boolean> => {
35
+ const rl = readline.createInterface({
36
+ input: process.stdin,
37
+ output: process.stdout,
38
+ });
39
+
40
+ return new Promise((resolve) => {
41
+ rl.question('Auto-install dependencies with pnpm? (Y/n): ', (answer) => {
42
+ rl.close();
43
+ const trimmed = answer.trim().toLowerCase();
44
+ resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes');
45
+ });
46
+ });
47
+ };
48
+
49
+ const isFolderEmpty = (folderPath: string): boolean => {
50
+ if (!existsSync(folderPath)) {
51
+ return true;
52
+ }
53
+
54
+ try {
55
+ const files = readdirSync(folderPath);
56
+ return files.length === 0;
57
+ } catch (error) {
58
+ // If we can't read the directory, treat it as not empty
59
+ return false;
60
+ }
61
+ };
62
+
63
+ const copyFile = (
64
+ source: string,
65
+ target: string,
66
+ replacements: Record<string, string> = {},
67
+ gitignorePatterns: string[] = []
68
+ ): void => {
69
+ const fileName = basename(source);
70
+
71
+ // Check if file should be skipped based on gitignore patterns
72
+ for (const pattern of gitignorePatterns) {
73
+ if (fileName === pattern || fileName.endsWith(pattern.replace('*', ''))) {
74
+ return; // Skip this file
75
+ }
76
+ }
77
+
78
+ let content = readFileSync(source, 'utf-8');
79
+
80
+ // Apply replacements
81
+ for (const [search, replace] of Object.entries(replacements)) {
82
+ content = content.replaceAll(search, replace);
83
+ }
84
+
85
+ mkdirSync(dirname(target), { recursive: true });
86
+
87
+ // For binary files, just copy as-is
88
+ if (source.endsWith('.lock') || source.endsWith('.so') || source.endsWith('.wasm')) {
89
+ copyFileSync(source, target);
90
+ } else {
91
+ writeFileSync(target, content, 'utf-8');
92
+ }
93
+ };
94
+
95
+ const parseGitignore = (gitignorePath: string): string[] => {
96
+ if (!existsSync(gitignorePath)) {
97
+ return [];
98
+ }
99
+
100
+ const content = readFileSync(gitignorePath, 'utf-8');
101
+ return content
102
+ .split('\n')
103
+ .map((line: string) => line.trim())
104
+ .filter((line: string) => line && !line.startsWith('#'));
105
+ };
106
+
107
+ const copyFolder = (
108
+ source: string,
109
+ target: string,
110
+ replacements: Record<string, string> = {},
111
+ gitignorePatterns: string[] = []
112
+ ): void => {
113
+ if (!existsSync(target)) {
114
+ mkdirSync(target, { recursive: true });
115
+ }
116
+
117
+ const files = readdirSync(source);
118
+
119
+ files.forEach((file) => {
120
+ const sourcePath = join(source, file);
121
+ const targetPath = join(target, file);
122
+
123
+ const stat = statSync(sourcePath);
124
+
125
+ if (stat.isDirectory()) {
126
+ // Check if directory should be skipped based on gitignore patterns
127
+ const shouldSkip = gitignorePatterns.some(pattern =>
128
+ file === pattern.replace('/', '') || pattern.startsWith('/') && file === pattern.slice(1)
129
+ );
130
+
131
+ if (!shouldSkip) {
132
+ copyFolder(sourcePath, targetPath, replacements, gitignorePatterns);
133
+ }
134
+ } else {
135
+ copyFile(sourcePath, targetPath, replacements, gitignorePatterns);
136
+ }
137
+ });
138
+ };
139
+
140
+ const generateProject = (targetFolder: string, projectName?: string): void => {
141
+ // find template in published package
142
+ const templatePath = join(__dirname, '../templates/basic');
143
+ const gitignorePath = join(templatePath, '.gitignore');
144
+
145
+ // Parse gitignore patterns
146
+ const gitignorePatterns = parseGitignore(gitignorePath);
147
+
148
+ // Determine project name from folder or use placeholder
149
+ const folderName = projectName || basename(targetFolder === './' ? process.cwd() : targetFolder);
150
+
151
+ // Get the current version of hardhat-deploy
152
+ const hardhatDeployVersion = getHardhatDeployVersion();
153
+
154
+ const replacements: Record<string, string> = {
155
+ 'template-hardhat-node-test-runner': `${folderName}`,
156
+ 'workspace:*': hardhatDeployVersion,
157
+ };
158
+
159
+ console.log(`Generating project in: ${targetFolder}`);
160
+ copyFolder(templatePath, targetFolder, replacements, gitignorePatterns);
161
+ console.log('✓ Project initialized successfully!');
162
+ };
163
+
164
+ const runPnpmInstall = async (folderPath: string): Promise<void> => {
165
+ console.log(`Installing dependencies...`);
166
+ const { spawn } = await import('child_process');
167
+
168
+ return new Promise((resolve, reject) => {
169
+ const pnpm = spawn('pnpm', ['install'], {
170
+ cwd: folderPath,
171
+ stdio: 'inherit',
172
+ });
173
+
174
+ pnpm.on('close', (code) => {
175
+ if (code === 0) {
176
+ console.log('✓ Dependencies installed successfully!');
177
+ resolve();
178
+ } else {
179
+ reject(new Error(`pnpm install failed with exit code ${code}`));
180
+ }
181
+ });
182
+
183
+ pnpm.on('error', (error) => {
184
+ reject(error);
185
+ });
186
+ });
187
+ };
188
+
189
+ program
190
+ .name('hardhat-deploy')
191
+ .description('CLI for hardhat-deploy')
192
+ .version(pkg.version);
193
+
194
+ program
195
+ .command('init')
196
+ .argument('[folder]', 'folder to initialize the project in')
197
+ .option('--install', 'auto-install dependencies with pnpm')
198
+ .description('Initialize a new hardhat-deploy project')
199
+ .action(async (folder?: string, options?: { install?: boolean }) => {
200
+ let targetFolder = folder;
201
+ let autoInstall = options?.install ?? false;
202
+
203
+ // If no folder specified, ask user
204
+ if (!targetFolder) {
205
+ targetFolder = await askFolder();
206
+ // If we prompted for folder, also prompt for auto-install
207
+ autoInstall = await askAutoInstall();
208
+ }
209
+
210
+ // Normalize path
211
+ targetFolder = targetFolder.trim();
212
+
213
+ // Check if folder is empty
214
+ if (!isFolderEmpty(targetFolder)) {
215
+ console.error(`Error: Folder "${targetFolder}" is not empty. Please specify an empty folder or a new folder path.`);
216
+ process.exit(1);
217
+ }
218
+
219
+ // Generate project
220
+ generateProject(targetFolder);
221
+
222
+ // Auto-install if requested
223
+ if (autoInstall) {
224
+ try {
225
+ await runPnpmInstall(targetFolder);
226
+ } catch (error) {
227
+ console.error('Failed to install dependencies:', error);
228
+ console.log('\nYou can install dependencies manually:');
229
+ console.log(` cd ${targetFolder === './' ? '.' : targetFolder}`);
230
+ console.log(' pnpm install');
231
+ process.exit(1);
232
+ }
233
+ }
234
+
235
+ // Show next steps
236
+ console.log(`\nNext steps:`);
237
+ console.log(` cd ${targetFolder === './' ? '.' : targetFolder}`);
238
+ if (!autoInstall) {
239
+ console.log(` pnpm install`);
240
+ }
241
+ console.log(` pnpm hardhat test`);
242
+ });
243
+
244
+ program.parse();
@@ -0,0 +1,44 @@
1
+ # Sample Hardhat 3 Project (`node:test`)
2
+
3
+ This project showcases a Hardhat 3 project using the [hardhat-deploy](https://github.com/wighawag/hardhat-deploy) plugin (along with the [rocketh](https://github.com/wighawag/rocketh) deployment system) and the native Node.js test runner (`node:test`) .
4
+
5
+ To learn more about the hardhat-deploy and rocketh, please visit the [Documentation](https://rocketh.dev).
6
+
7
+ ## Project Overview
8
+
9
+ This example project includes:
10
+
11
+ - A simple Hardhat configuration file.
12
+ - Foundry-compatible Solidity unit tests.
13
+ - TypeScript integration tests using [`node:test`](nodejs.org/api/test.html) and the built-in mechanism to load deployments in test via hardhat-deploy and rocketh.
14
+
15
+ ## Usage
16
+
17
+ ### Running Tests
18
+
19
+ To run all the tests in the project, execute the following command:
20
+
21
+ ```bash
22
+ pnpm hardhat test
23
+ ```
24
+
25
+ You can also selectively run the Solidity or `node:test` tests:
26
+
27
+ ```bash
28
+ pnpm hardhat test solidity
29
+ pnpm hardhat test nodejs
30
+ ```
31
+
32
+ ### Deploying Contracts
33
+
34
+ To deploy the contracts to an in-memory network, run:
35
+
36
+ ```bash
37
+ pnpm hardhat deploy
38
+ ```
39
+
40
+ To deploy the contracts to a specific network, use the `--network` option:
41
+
42
+ ```bash
43
+ pnpm hardhat deploy --network <network-name>
44
+ ```
@@ -0,0 +1,19 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.28;
3
+
4
+ contract Counter {
5
+ uint public x;
6
+
7
+ event Increment(uint by);
8
+
9
+ function inc() public {
10
+ x++;
11
+ emit Increment(1);
12
+ }
13
+
14
+ function incBy(uint by) public {
15
+ require(by > 0, "incBy: increment should be positive");
16
+ x += by;
17
+ emit Increment(by);
18
+ }
19
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {Counter} from "./Counter.sol";
5
+ import {Test} from "forge-std/Test.sol";
6
+
7
+ contract CounterTest is Test {
8
+ Counter counter;
9
+
10
+ function setUp() public {
11
+ counter = new Counter();
12
+ }
13
+
14
+ function test_InitialValue() public view {
15
+ require(counter.x() == 0, "Initial value should be 0");
16
+ }
17
+
18
+ function testFuzz_Inc(uint8 x) public {
19
+ for (uint8 i = 0; i < x; i++) {
20
+ counter.inc();
21
+ }
22
+ require(counter.x() == x, "Value after calling inc x times should be x");
23
+ }
24
+
25
+ function test_IncByZero() public {
26
+ vm.expectRevert();
27
+ counter.incBy(0);
28
+ }
29
+ }
@@ -0,0 +1,13 @@
1
+ import { deployScript, artifacts } from "../rocketh/deploy.js";
2
+
3
+ export default deployScript(
4
+ async ({ deploy, namedAccounts }) => {
5
+ const { deployer } = namedAccounts;
6
+
7
+ await deploy("Counter", {
8
+ account: deployer,
9
+ artifact: artifacts.Counter,
10
+ });
11
+ },
12
+ { tags: ["Counter", "Counter_deploy"] },
13
+ );
@@ -0,0 +1,50 @@
1
+ import { configVariable, defineConfig } from "hardhat/config";
2
+ import hardhatNodeTestRunnerPlugin from "@nomicfoundation/hardhat-node-test-runner";
3
+ import hardhatKeyStorePlugin from "@nomicfoundation/hardhat-keystore";
4
+ import hardhatNetworkHelpersPlugin from "@nomicfoundation/hardhat-network-helpers";
5
+ import hardhatViemPlugin from "@nomicfoundation/hardhat-viem";
6
+ import hardhatViemAssertionsPlugin from "@nomicfoundation/hardhat-viem-assertions";
7
+ import HardhatDeploy from "hardhat-deploy";
8
+
9
+ export default defineConfig({
10
+ plugins: [
11
+ hardhatNodeTestRunnerPlugin,
12
+ hardhatKeyStorePlugin,
13
+ hardhatNetworkHelpersPlugin,
14
+ HardhatDeploy,
15
+ hardhatViemPlugin,
16
+ hardhatViemAssertionsPlugin
17
+ ],
18
+ solidity: {
19
+ profiles: {
20
+ default: {
21
+ version: "0.8.28",
22
+ },
23
+ production: {
24
+ version: "0.8.28",
25
+ settings: {
26
+ optimizer: {
27
+ enabled: true,
28
+ runs: 200,
29
+ },
30
+ },
31
+ },
32
+ },
33
+ },
34
+ networks: {
35
+ hardhatMainnet: {
36
+ type: "edr-simulated",
37
+ chainType: "l1",
38
+ },
39
+ hardhatOp: {
40
+ type: "edr-simulated",
41
+ chainType: "op",
42
+ },
43
+ sepolia: {
44
+ type: "http",
45
+ chainType: "l1",
46
+ url: configVariable("SEPOLIA_RPC_URL"),
47
+ accounts: [configVariable("SEPOLIA_PRIVATE_KEY")],
48
+ },
49
+ },
50
+ });
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "template-hardhat-node-test-runner",
3
+ "version": "0.0.0",
4
+ "description": "A TypeScript Hardhat project using Node Test Runner",
5
+ "type": "module",
6
+ "devDependencies": {
7
+ "@nomicfoundation/hardhat-keystore": "^3.0.3",
8
+ "@nomicfoundation/hardhat-network-helpers": "^3.0.3",
9
+ "@nomicfoundation/hardhat-node-test-runner": "^3.0.8",
10
+ "@nomicfoundation/hardhat-viem": "^3.0.2",
11
+ "@nomicfoundation/hardhat-viem-assertions": "^3.0.5",
12
+ "@rocketh/deploy": "^0.17.9",
13
+ "@rocketh/doc": "^0.17.18",
14
+ "@rocketh/export": "^0.17.18",
15
+ "@rocketh/node": "^0.17.18",
16
+ "@rocketh/proxy": "^0.17.13",
17
+ "@rocketh/read-execute": "^0.17.9",
18
+ "@rocketh/verifier": "^0.17.18",
19
+ "@rocketh/viem": "^0.17.6",
20
+ "@types/node": "^25.0.10",
21
+ "forge-std": "foundry-rs/forge-std#v1.9.4",
22
+ "hardhat": "^3.1.5",
23
+ "hardhat-deploy": "workspace:*",
24
+ "rocketh": "^0.17.14",
25
+ "typescript": "~5.9.3",
26
+ "viem": "^2.43.0"
27
+ },
28
+ "scripts": {
29
+ "test": "hardhat test"
30
+ }
31
+ }