@diamondslab/diamonds-hardhat-foundry 1.0.2 → 2.1.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 (59) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/README.md +568 -4
  3. package/contracts/DiamondABILoader.sol +329 -0
  4. package/contracts/DiamondForgeHelpers.sol +309 -85
  5. package/contracts/DiamondFuzzBase.sol +305 -114
  6. package/dist/foundry.d.ts +28 -0
  7. package/dist/foundry.d.ts.map +1 -1
  8. package/dist/foundry.js +82 -1
  9. package/dist/foundry.js.map +1 -1
  10. package/dist/framework/DeploymentManager.d.ts +10 -11
  11. package/dist/framework/DeploymentManager.d.ts.map +1 -1
  12. package/dist/framework/DeploymentManager.js +56 -45
  13. package/dist/framework/DeploymentManager.js.map +1 -1
  14. package/dist/framework/ForgeFuzzingFramework.d.ts +4 -0
  15. package/dist/framework/ForgeFuzzingFramework.d.ts.map +1 -1
  16. package/dist/framework/ForgeFuzzingFramework.js +16 -2
  17. package/dist/framework/ForgeFuzzingFramework.js.map +1 -1
  18. package/dist/framework/HelperGenerator.d.ts.map +1 -1
  19. package/dist/framework/HelperGenerator.js +11 -0
  20. package/dist/framework/HelperGenerator.js.map +1 -1
  21. package/dist/index.d.ts +0 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +0 -8
  24. package/dist/index.js.map +1 -1
  25. package/dist/tasks/deploy.js +3 -2
  26. package/dist/tasks/deploy.js.map +1 -1
  27. package/dist/tasks/generate-helpers.js +6 -4
  28. package/dist/tasks/generate-helpers.js.map +1 -1
  29. package/dist/tasks/init.js +3 -2
  30. package/dist/tasks/init.js.map +1 -1
  31. package/dist/tasks/test.js +13 -2
  32. package/dist/tasks/test.js.map +1 -1
  33. package/dist/templates/DiamondDeployment.sol.template +38 -0
  34. package/dist/templates/ExampleFuzzTest.t.sol.template +118 -0
  35. package/dist/templates/ExampleIntegrationTest.t.sol.template +87 -0
  36. package/dist/templates/ExampleUnitTest.t.sol.template +65 -0
  37. package/dist/types/hardhat.d.ts +1 -1
  38. package/dist/types/hardhat.d.ts.map +1 -1
  39. package/dist/types/hardhat.js +1 -0
  40. package/dist/types/hardhat.js.map +1 -1
  41. package/dist/utils/foundry.d.ts +1 -0
  42. package/dist/utils/foundry.d.ts.map +1 -1
  43. package/dist/utils/foundry.js +3 -0
  44. package/dist/utils/foundry.js.map +1 -1
  45. package/package.json +7 -4
  46. package/src/foundry.ts +104 -0
  47. package/src/framework/DeploymentManager.ts +74 -69
  48. package/src/framework/ForgeFuzzingFramework.ts +23 -1
  49. package/src/framework/HelperGenerator.ts +13 -0
  50. package/src/index.ts +0 -5
  51. package/src/tasks/deploy.ts +3 -1
  52. package/src/tasks/generate-helpers.ts +6 -2
  53. package/src/tasks/init.ts +3 -1
  54. package/src/tasks/test.ts +12 -1
  55. package/src/templates/ExampleFuzzTest.t.sol.template +26 -17
  56. package/src/templates/ExampleIntegrationTest.t.sol.template +9 -1
  57. package/src/templates/ExampleUnitTest.t.sol.template +7 -1
  58. package/src/types/hardhat.ts +1 -1
  59. package/src/utils/foundry.ts +5 -0
package/README.md CHANGED
@@ -30,14 +30,18 @@ pnpm add -D @diamondslab/diamonds-hardhat-foundry
30
30
 
31
31
  - **Foundry**: Install from [getfoundry.sh](https://getfoundry.sh/)
32
32
  - **Hardhat**: `^2.26.0` or later
33
- - **Peer Dependencies**:
33
+ - **Required Peer Dependencies**:
34
34
  - `@diamondslab/diamonds` - Core Diamond deployment library
35
- - `@diamondslab/hardhat-diamonds` - Hardhat Diamond configuration helpers
35
+ - `@diamondslab/hardhat-diamonds` - Hardhat Diamond configuration and LocalDiamondDeployer
36
+ - `@nomicfoundation/hardhat-ethers` - Ethers.js integration
37
+ - `ethers` - Ethereum library
36
38
 
37
39
  ```bash
38
- npm install --save-dev @diamondslab/diamonds @diamondslab/hardhat-diamonds hardhat
40
+ npm install --save-dev @diamondslab/diamonds @diamondslab/hardhat-diamonds @nomicfoundation/hardhat-ethers ethers hardhat
39
41
  ```
40
42
 
43
+ > **Note**: Version 2.0.0+ requires `@diamondslab/hardhat-diamonds` as a peer dependency for LocalDiamondDeployer. See [MIGRATION.md](./MIGRATION.md) for upgrade instructions from v1.x.
44
+
41
45
  ## Quick Start
42
46
 
43
47
  ### 1. Configure Hardhat
@@ -99,6 +103,156 @@ This generates `test/foundry/helpers/DiamondDeployment.sol` with:
99
103
  - All facet addresses
100
104
  - Helper functions for test setup
101
105
 
106
+ ## Importing Helper Contracts
107
+
108
+ Version 2.0.0+ provides importable Solidity helper contracts for your tests:
109
+
110
+ ### DiamondFuzzBase - Base Contract for Fuzz Tests
111
+
112
+ Extend `DiamondFuzzBase` to create Diamond fuzz tests with built-in helpers:
113
+
114
+ ```solidity
115
+ // SPDX-License-Identifier: MIT
116
+ pragma solidity ^0.8.0;
117
+
118
+ import "forge-std/Test.sol";
119
+ import "@diamondslab/diamonds-hardhat-foundry/contracts/DiamondFuzzBase.sol";
120
+ import "../helpers/DiamondDeployment.sol";
121
+
122
+ contract MyDiamondFuzzTest is DiamondFuzzBase {
123
+ /// Override to load your deployed Diamond
124
+ function _loadDiamondAddress() internal view override returns (address) {
125
+ return DiamondDeployment.diamond();
126
+ }
127
+
128
+ function setUp() public override {
129
+ super.setUp(); // Loads Diamond and ABI
130
+ // Your additional setup
131
+ }
132
+
133
+ function testFuzz_SomeFunction(address user, uint256 amount) public {
134
+ // Use built-in helpers
135
+ vm.assume(DiamondForgeHelpers.isValidTestAddress(user));
136
+ vm.assume(DiamondForgeHelpers.isValidTestAmount(amount));
137
+
138
+ bytes4 selector = bytes4(keccak256("transfer(address,uint256)"));
139
+ bytes memory data = abi.encode(user, amount);
140
+ (bool success, ) = _callDiamond(selector, data);
141
+ assertTrue(success);
142
+ }
143
+ }
144
+ ```
145
+
146
+ **Built-in DiamondFuzzBase Methods:**
147
+
148
+ - `_loadDiamondAddress()` - Override to provide Diamond address
149
+ - `_getDiamondABIPath()` - Override to customize ABI file path
150
+ - `_callDiamond(selector, data)` - Call Diamond function
151
+ - `_callDiamondWithValue(selector, data, value)` - Call payable function
152
+ - `_expectDiamondRevert(selector, data, expectedError)` - Test reverts
153
+ - `_verifyFacetRouting(selector, expectedFacet)` - Check selector routing
154
+ - `_measureDiamondGas(selector, data)` - Measure gas consumption
155
+ - `_getDiamondOwner()` - Get Diamond owner address
156
+ - `_hasRole(role, account)` - Check role-based access control
157
+ - `_grantRole(role, account)` - Grant role (requires permissions)
158
+ - `_revokeRole(role, account)` - Revoke role
159
+
160
+ ### DiamondForgeHelpers - Utility Library
161
+
162
+ Use `DiamondForgeHelpers` for validation, assertions, and DiamondLoupe queries:
163
+
164
+ ```solidity
165
+ import "@diamondslab/diamonds-hardhat-foundry/contracts/DiamondForgeHelpers.sol";
166
+
167
+ contract MyTest is Test {
168
+ using DiamondForgeHelpers for address;
169
+
170
+ function setUp() public {
171
+ address diamond = deployDiamond();
172
+
173
+ // Validate Diamond deployment
174
+ DiamondForgeHelpers.assertValidDiamond(diamond);
175
+
176
+ // Validate facet
177
+ address facet = getFacet();
178
+ DiamondForgeHelpers.assertValidFacet(facet, "MyFacet");
179
+ }
180
+
181
+ function testFuzz_ValidInputs(address addr, uint256 amount) public {
182
+ // Filter fuzz inputs
183
+ vm.assume(DiamondForgeHelpers.isValidTestAddress(addr));
184
+ vm.assume(DiamondForgeHelpers.isValidTestAmount(amount));
185
+ // Your test logic
186
+ }
187
+
188
+ function testSelectorRouting() public {
189
+ bytes4 selector = bytes4(keccak256("someFunction()"));
190
+
191
+ // Assert selector exists
192
+ DiamondForgeHelpers.assertSelectorExists(diamond, selector);
193
+
194
+ // Assert routing to expected facet
195
+ DiamondForgeHelpers.assertSelectorRouting(diamond, selector, expectedFacet);
196
+
197
+ // Get facet address
198
+ address facet = DiamondForgeHelpers.getFacetAddress(diamond, selector);
199
+ }
200
+ }
201
+ ```
202
+
203
+ **DiamondForgeHelpers Functions:**
204
+
205
+ - `assertValidDiamond(address)` - Validate Diamond deployment
206
+ - `assertValidFacet(address, name)` - Validate facet deployment
207
+ - `isValidTestAddress(address)` - Filter fuzz addresses
208
+ - `isValidTestAmount(uint256)` - Filter fuzz amounts
209
+ - `assertSelectorExists(diamond, selector)` - Verify selector registered
210
+ - `assertSelectorRouting(diamond, selector, facet)` - Verify routing
211
+ - `getFacetAddress(diamond, selector)` - Get facet for selector
212
+ - `getFacetAddresses(diamond)` - Get all facet addresses
213
+ - `getFacetSelectors(diamond, facet)` - Get selectors for facet
214
+ - `getDiamondOwner(diamond)` - Get owner address
215
+ - `boundAddress(seed)` - Generate valid fuzz address
216
+ - `boundAmount(seed, min, max)` - Generate valid fuzz amount
217
+ - `selectorsEqual(a, b)` - Compare selector arrays
218
+
219
+ ### DiamondABILoader - ABI File Parser
220
+
221
+ Load and parse Diamond ABI files in your tests:
222
+
223
+ ```solidity
224
+ import "@diamondslab/diamonds-hardhat-foundry/contracts/DiamondABILoader.sol";
225
+
226
+ contract MyIntegrationTest is Test {
227
+ using DiamondABILoader for string;
228
+
229
+ function testABILoading() public {
230
+ // Load Diamond ABI
231
+ string memory abiJson = DiamondABILoader.loadDiamondABI("./diamond-abi/MyDiamond.json");
232
+
233
+ // Extract selectors and signatures
234
+ bytes4[] memory selectors = abiJson.extractSelectors();
235
+ string[] memory signatures = abiJson.extractSignatures();
236
+
237
+ console.log("Functions found:", selectors.length);
238
+
239
+ // Get function info
240
+ for (uint i = 0; i < selectors.length; i++) {
241
+ (bytes4 sel, string memory sig) = abiJson.getFunctionInfo(i);
242
+ console.log("Function:", sig);
243
+ }
244
+ }
245
+ }
246
+ ```
247
+
248
+ **DiamondABILoader Functions:**
249
+
250
+ - `loadDiamondABI(path)` - Load ABI JSON from file
251
+ - `extractSelectors(abiJson)` - Extract all function selectors
252
+ - `extractSignatures(abiJson)` - Extract all function signatures
253
+ - `getFunctionInfo(abiJson, index)` - Get selector and signature
254
+ - `verifySelectorsMatch(abiJson, expectedSelectors)` - Validate selectors
255
+
102
256
  ### 5. Run Foundry Tests
103
257
 
104
258
  ```bash
@@ -184,6 +338,205 @@ npx hardhat diamonds-forge:test --match-test "testOwnership" --verbosity 4
184
338
  npx hardhat diamonds-forge:test --skip-deployment --match-contract "MyTest"
185
339
  ```
186
340
 
341
+ ## Dynamic Helper Generation
342
+
343
+ Version 2.0.0+ introduces **dynamic helper generation** that creates deployment-specific Solidity helpers without hardcoded addresses.
344
+
345
+ ### How It Works
346
+
347
+ When you deploy a Diamond and generate helpers, the plugin creates `test/foundry/helpers/DiamondDeployment.sol` with:
348
+
349
+ ```solidity
350
+ library DiamondDeployment {
351
+ /// @notice Get the deployed Diamond address
352
+ function getDiamondAddress() internal pure returns (address) {
353
+ return 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512;
354
+ }
355
+
356
+ /// @notice Get the deployer address
357
+ function getDeployerAddress() internal pure returns (address) {
358
+ return 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
359
+ }
360
+
361
+ // Additional deployment-specific data...
362
+ }
363
+ ```
364
+
365
+ **Key Benefits:**
366
+
367
+ - ✅ **No hardcoded addresses in test files** - All addresses come from deployment records
368
+ - ✅ **Network-specific helpers** - Different helpers for different networks
369
+ - ✅ **Automatic regeneration** - Helpers update when you redeploy
370
+ - ✅ **Type-safe** - Solidity library ensures compile-time validation
371
+
372
+ ### Using Generated Helpers
373
+
374
+ ```solidity
375
+ import "../helpers/DiamondDeployment.sol";
376
+
377
+ contract MyTest is Test {
378
+ address diamond;
379
+ address deployer;
380
+
381
+ function setUp() public {
382
+ // Load from generated helpers
383
+ diamond = DiamondDeployment.getDiamondAddress();
384
+ deployer = DiamondDeployment.getDeployerAddress();
385
+
386
+ // Use in tests
387
+ vm.prank(deployer);
388
+ IDiamond(diamond).someFunction();
389
+ }
390
+ }
391
+ ```
392
+
393
+ ## Deployment Management
394
+
395
+ The plugin provides flexible deployment management with two modes:
396
+
397
+ ### Ephemeral Deployments (Default)
398
+
399
+ For quick testing without persisting deployment records:
400
+
401
+ ```bash
402
+ # Deploy Diamond for this test run only
403
+ npx hardhat diamonds-forge:test --diamond-name MyDiamond
404
+
405
+ # Deployment is cached in memory but not saved to file
406
+ # Helpers are generated from cached data
407
+ # Next run will deploy fresh Diamond
408
+ ```
409
+
410
+ **Use ephemeral mode when:**
411
+ - Running tests in CI/CD
412
+ - Testing with default Hardhat network
413
+ - You don't need to reuse deployments
414
+ - Each test run should start clean
415
+
416
+ ### Persistent Deployments
417
+
418
+ Save deployment records for reuse across test runs:
419
+
420
+ ```bash
421
+ # Deploy and save deployment record
422
+ npx hardhat diamonds-forge:deploy --diamond-name MyDiamond --network localhost
423
+
424
+ # Run tests using saved deployment
425
+ npx hardhat diamonds-forge:test --network localhost --use-deployment
426
+
427
+ # Deployment is loaded from file
428
+ # Subsequent runs reuse the same Diamond
429
+ ```
430
+
431
+ **Use persistent mode when:**
432
+ - Testing on persistent networks (localhost, testnets)
433
+ - Developing against specific Diamond deployment
434
+ - Testing upgrade scenarios
435
+ - Running integration tests
436
+
437
+ ### Task Flags Reference
438
+
439
+ **Deployment Control:**
440
+ - `--save-deployment` - Save deployment record to file (persistent mode)
441
+ - `--use-deployment` - Load existing deployment instead of deploying new one
442
+ - `--force-deploy` - Force new deployment even if one exists
443
+
444
+ **Helper Control:**
445
+ - `--skip-helpers` - Don't generate DiamondDeployment.sol
446
+ - `--helpers-dir <path>` - Custom output directory for helpers
447
+
448
+ **Test Filtering:**
449
+ - `--match-test <pattern>` - Run only tests matching name pattern
450
+ - `--match-contract <contract>` - Run only tests in specified contract
451
+ - `--match-path <path>` - Run only tests in files matching path
452
+
453
+ **Output Control:**
454
+ - `--verbosity <1-5>` - Set Forge output verbosity (default: 2)
455
+ - `--gas-report` - Display detailed gas usage report
456
+ - `--coverage` - Generate test coverage report
457
+
458
+ **Network Control:**
459
+ - `--network <name>` - Network to use (hardhat, localhost, sepolia, etc.)
460
+ - `--fork-url <url>` - Custom RPC URL for forking
461
+
462
+ ### Examples
463
+
464
+ ```bash
465
+ # Quick ephemeral test (default)
466
+ npx hardhat diamonds-forge:test
467
+
468
+ # Save deployment for reuse
469
+ npx hardhat diamonds-forge:test --save-deployment --network localhost
470
+
471
+ # Reuse saved deployment
472
+ npx hardhat diamonds-forge:test --use-deployment --network localhost
473
+
474
+ # Test specific functionality with gas report
475
+ npx hardhat diamonds-forge:test --match-test "testOwnership" --gas-report
476
+
477
+ # Run only fuzz tests with high verbosity
478
+ npx hardhat diamonds-forge:test --match-contract "Fuzz" --verbosity 4
479
+
480
+ # Force redeploy even if deployment exists
481
+ npx hardhat diamonds-forge:test --force-deploy --network localhost
482
+ ```
483
+
484
+ ## Snapshot and Restore
485
+
486
+ The `DiamondForgeHelpers` library provides snapshot/restore functionality for advanced testing scenarios.
487
+
488
+ ### Basic Usage
489
+
490
+ ```solidity
491
+ import "@diamondslab/diamonds-hardhat-foundry/contracts/DiamondForgeHelpers.sol";
492
+
493
+ contract MyTest is Test {
494
+ using DiamondForgeHelpers for *;
495
+
496
+ function test_MultipleScenarios() public {
497
+ // Save initial state
498
+ uint256 snapshot = DiamondForgeHelpers.snapshotState();
499
+
500
+ // Test scenario A
501
+ runScenarioA();
502
+
503
+ // Restore to initial state
504
+ DiamondForgeHelpers.revertToSnapshot(snapshot);
505
+
506
+ // Test scenario B from same starting point
507
+ runScenarioB();
508
+ }
509
+ }
510
+ ```
511
+
512
+ ### When to Use Snapshots
513
+
514
+ **Good Use Cases:**
515
+ - Testing multiple outcomes from same initial state
516
+ - Expensive setup that you want to reuse
517
+ - Testing state transitions and rollbacks
518
+ - Benchmarking gas costs across scenarios
519
+
520
+ **Don't Use For:**
521
+ - Normal test isolation (Forge does this automatically)
522
+ - Production/testnet testing (snapshots only work locally)
523
+
524
+ ### Snapshot Examples
525
+
526
+ See comprehensive examples in `test/foundry/integration/SnapshotExample.t.sol`:
527
+
528
+ ```bash
529
+ forge test --match-path "**/SnapshotExample.t.sol" -vv
530
+ ```
531
+
532
+ **Available in examples:**
533
+ - Basic snapshot/restore workflow
534
+ - Multiple snapshots with different states
535
+ - Snapshot with contract state changes
536
+ - Test isolation patterns
537
+
538
+ For detailed snapshot documentation, see [TESTING.md](./TESTING.md#snapshot-and-restore).
539
+
187
540
  ## Programmatic API
188
541
 
189
542
  Use the framework classes directly in your scripts:
@@ -428,7 +781,218 @@ export default {
428
781
 
429
782
  ## Troubleshooting
430
783
 
431
- ### Foundry Not Found
784
+ ### Common Issues
785
+
786
+ #### Foundry Not Found
787
+
788
+ **Error:** `Foundry not installed` or `forge: command not found`
789
+
790
+ **Solution:** Install Foundry from [getfoundry.sh](https://getfoundry.sh/):
791
+
792
+ ```bash
793
+ curl -L https://foundry.paradigm.xyz | bash
794
+ foundryup
795
+ ```
796
+
797
+ Verify installation:
798
+ ```bash
799
+ forge --version
800
+ ```
801
+
802
+ #### LocalDiamondDeployer Not Found
803
+
804
+ **Error:** `LocalDiamondDeployer not found` or `Cannot find module`
805
+
806
+ **Solution:** Ensure you have the `@diamondslab/hardhat-diamonds` package installed:
807
+
808
+ ```bash
809
+ npm install --save-dev @diamondslab/hardhat-diamonds
810
+ ```
811
+
812
+ Import it in your `hardhat.config.ts`:
813
+
814
+ ```typescript
815
+ import "@diamondslab/hardhat-diamonds";
816
+ import "@diamondslab/diamonds-hardhat-foundry";
817
+ ```
818
+
819
+ #### Deployment Record Not Found
820
+
821
+ **Error:** `No deployment record found for MyDiamond-hardhat-31337.json`
822
+
823
+ **Solution:** Deploy your Diamond first:
824
+
825
+ ```bash
826
+ npx hardhat diamonds-forge:deploy --diamond-name MyDiamond --network localhost
827
+ ```
828
+
829
+ Or use ephemeral deployment (default) which doesn't require saved records:
830
+
831
+ ```bash
832
+ npx hardhat diamonds-forge:test
833
+ ```
834
+
835
+ #### Diamond Has No Code
836
+
837
+ **Error:** `DiamondFuzzBase: Diamond has no code` when running tests
838
+
839
+ **Cause:** Test is trying to use a Diamond address that doesn't have deployed code.
840
+
841
+ **Solutions:**
842
+
843
+ 1. **For tests using hardhat network (ephemeral):**
844
+ - Tests should deploy their own Diamond in `setUp()`
845
+ - See `BasicDiamondIntegration.t.sol` for self-deploying pattern
846
+
847
+ 2. **For tests using deployed Diamond:**
848
+ - Start Hardhat node: `npx hardhat node`
849
+ - Deploy Diamond: `npx hardhat diamonds-forge:deploy --network localhost`
850
+ - Run tests: `npx hardhat diamonds-forge:test --network localhost`
851
+
852
+ 3. **Make tests fork-aware:**
853
+ ```solidity
854
+ function setUp() public {
855
+ diamond = DiamondDeployment.getDiamondAddress();
856
+
857
+ // Check if Diamond is deployed (forking)
858
+ if (diamond.code.length == 0) {
859
+ // Skip test or deploy in test
860
+ return;
861
+ }
862
+
863
+ // Proceed with test setup
864
+ }
865
+ ```
866
+
867
+ #### Generated Helpers Not Compiling
868
+
869
+ **Error:** Compilation errors in `test/foundry/helpers/DiamondDeployment.sol`
870
+
871
+ **Solutions:**
872
+
873
+ 1. Ensure Foundry remappings are correct in `foundry.toml`:
874
+ ```toml
875
+ [profile.default]
876
+ src = "contracts"
877
+ test = "test/foundry"
878
+ remappings = [
879
+ "@diamondslab/diamonds-hardhat-foundry/=node_modules/@diamondslab/diamonds-hardhat-foundry/",
880
+ ]
881
+ ```
882
+
883
+ 2. Verify Diamond deployed successfully before generating helpers:
884
+ ```bash
885
+ npx hardhat diamonds-forge:deploy --diamond-name MyDiamond
886
+ npx hardhat diamonds-forge:generate-helpers --diamond-name MyDiamond
887
+ ```
888
+
889
+ 3. Check that deployment data is valid:
890
+ - Look in `diamonds/MyDiamond/deployments/`
891
+ - Verify JSON file contains `DiamondAddress` field
892
+
893
+ #### Peer Dependency Warnings
894
+
895
+ **Warning:** `ERESOLVE unable to resolve dependency tree` or peer dependency conflicts
896
+
897
+ **Solution:** Install all required peer dependencies:
898
+
899
+ ```bash
900
+ npm install --save-dev \
901
+ @diamondslab/diamonds \
902
+ @diamondslab/hardhat-diamonds \
903
+ @nomicfoundation/hardhat-ethers \
904
+ ethers \
905
+ hardhat
906
+ ```
907
+
908
+ For package.json, specify compatible versions:
909
+
910
+ ```json
911
+ {
912
+ "devDependencies": {
913
+ "@diamondslab/diamonds": "^3.0.0",
914
+ "@diamondslab/hardhat-diamonds": "^2.0.0",
915
+ "@diamondslab/diamonds-hardhat-foundry": "^2.0.0",
916
+ "@nomicfoundation/hardhat-ethers": "^3.0.0",
917
+ "ethers": "^6.0.0",
918
+ "hardhat": "^2.26.0"
919
+ }
920
+ }
921
+ ```
922
+
923
+ #### Tests Pass Locally But Fail in CI
924
+
925
+ **Cause:** CI environment differences (network, timing, dependencies)
926
+
927
+ **Solutions:**
928
+
929
+ 1. **Ensure Foundry is installed in CI:**
930
+ ```yaml
931
+ # GitHub Actions example
932
+ - name: Install Foundry
933
+ uses: foundry-rs/foundry-toolchain@v1
934
+
935
+ - name: Run tests
936
+ run: npx hardhat diamonds-forge:test
937
+ ```
938
+
939
+ 2. **Use ephemeral deployments for CI (default):**
940
+ ```bash
941
+ # This works in CI without persistent network
942
+ npx hardhat diamonds-forge:test
943
+ ```
944
+
945
+ 3. **For persistent network testing in CI:**
946
+ ```yaml
947
+ - name: Start Hardhat node
948
+ run: npx hardhat node &
949
+
950
+ - name: Wait for node
951
+ run: sleep 5
952
+
953
+ - name: Run tests
954
+ run: npx hardhat diamonds-forge:test --network localhost
955
+ ```
956
+
957
+ #### Import Resolution Errors
958
+
959
+ **Error:** `File import callback not supported` or module resolution failures
960
+
961
+ **Solution:** Check your `hardhat.config.ts` has correct imports:
962
+
963
+ ```typescript
964
+ import "@nomicfoundation/hardhat-ethers";
965
+ import "@diamondslab/hardhat-diamonds";
966
+ import "@diamondslab/diamonds-hardhat-foundry";
967
+
968
+ export default {
969
+ solidity: "0.8.28",
970
+ // ... config
971
+ };
972
+ ```
973
+
974
+ Ensure TypeScript compilation targets CommonJS:
975
+
976
+ ```json
977
+ // tsconfig.json
978
+ {
979
+ "compilerOptions": {
980
+ "module": "CommonJS",
981
+ "moduleResolution": "node"
982
+ }
983
+ }
984
+ ```
985
+
986
+ ### Getting Help
987
+
988
+ If you encounter issues not covered here:
989
+
990
+ 1. Check the [TESTING.md](./TESTING.md) guide for detailed testing workflows
991
+ 2. Review [MIGRATION.md](./MIGRATION.md) if upgrading from v1.x
992
+ 3. See [DESIGN.md](./DESIGN.md) for architecture details
993
+ 4. Open an issue on [GitHub](https://github.com/diamondslab/diamonds-hardhat-foundry/issues)
994
+
995
+ ## Foundry Not Found
432
996
 
433
997
  **Error:** `Foundry not installed`
434
998