Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Commit b092fe5

Browse files
authored
feat: write hardhat style artifacts to disk (#38)
* feat: `ForgeArtifacts` can write to disk Adds a function `writeArtifactsSync` that accepts an output directory and will write hardhat style artifacts to disk in that directory. * feat: write hh style artifacts to disk on build * test: add tests for writing artifacts to disk * chore: add changeset
1 parent 6d0971c commit b092fe5

6 files changed

Lines changed: 86 additions & 3 deletions

File tree

.changeset/strong-cheetahs-call.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@foundry-rs/hardhat-forge": patch
3+
---
4+
5+
Write hh style artifacts to disk

packages/hardhat-forge/src/forge/artifacts.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ import {
2828
import { ForgeArtifact } from "./types";
2929

3030
export class ForgeArtifacts implements IArtifacts {
31-
constructor(private _out: string, private _cache: string) {}
31+
constructor(
32+
private _root: string,
33+
private _sources: string,
34+
private _out: string,
35+
private _cache: string
36+
) {}
3237

3338
public async readArtifact(name: string): Promise<Artifact> {
3439
const artifactPath = await this._getArtifactPath(name);
@@ -473,6 +478,32 @@ Please replace "${contractName}" for the correct contract name wherever you are
473478

474479
return undefined;
475480
}
481+
482+
/**
483+
* Given the path to a directory, hardhat style artifacts will
484+
* be written to disk
485+
*/
486+
public writeArtifactsSync(outDir: string) {
487+
const paths = this._getArtifactPathsSync();
488+
const artifacts = path.relative(this._root, outDir);
489+
490+
for (const filepath of paths) {
491+
const forgeArtifact = fsExtra.readJsonSync(filepath) as ForgeArtifact;
492+
const artifact = this.readArtifactSync(path.parse(filepath).name);
493+
494+
const contractPath = forgeArtifact.ast?.absolutePath;
495+
if (!contractPath) {
496+
throw new Error(
497+
`Must compile with ast to build harhat style artifacts`
498+
);
499+
}
500+
501+
const dir = path.join(this._root, artifacts, contractPath);
502+
const out = path.join(dir, path.basename(filepath));
503+
fsExtra.mkdirpSync(path.dirname(out));
504+
fsExtra.writeJsonSync(out, artifact, { spaces: 2 });
505+
}
506+
}
476507
}
477508

478509
/**

packages/hardhat-forge/src/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ extendEnvironment((hre) => {
2020
config.cache_path ?? "cache",
2121
SOLIDITY_FILES_CACHE_FILENAME
2222
);
23-
return new ForgeArtifacts(outDir, cacheDir);
23+
24+
const artifacts = new ForgeArtifacts(
25+
hre.config.paths.root,
26+
config.src,
27+
outDir,
28+
cacheDir
29+
);
30+
31+
artifacts.writeArtifactsSync(hre.config.paths.artifacts);
32+
return artifacts;
2433
});
2534
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
contract FooBar {
5+
6+
function example() public {}
7+
8+
}

packages/hardhat-forge/test/helpers.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { resetHardhatContext } from "hardhat/plugins-testing";
22
import { HardhatRuntimeEnvironment } from "hardhat/types";
3+
import fsExtra from "fs-extra";
4+
35
import path from "path";
46

57
declare module "mocha" {
@@ -19,3 +21,17 @@ export function useEnvironment(fixtureProjectName: string) {
1921
resetHardhatContext();
2022
});
2123
}
24+
25+
export async function getAllFiles(directory: string, files: string[] = []) {
26+
const current = await fsExtra.readdir(directory);
27+
for (const file of current) {
28+
const next = path.join(directory, file);
29+
const info = await fsExtra.stat(next);
30+
if (info.isDirectory()) {
31+
files = await getAllFiles(next, files);
32+
} else {
33+
files.push(next);
34+
}
35+
}
36+
return files;
37+
}

packages/hardhat-forge/test/project.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { assert } from "chai";
2-
import { useEnvironment } from "./helpers";
2+
import path from "path";
3+
import { useEnvironment, getAllFiles } from "./helpers";
34

45
describe("Integration tests", function () {
56
this.timeout(300000);
@@ -34,5 +35,18 @@ describe("Integration tests", function () {
3435
assert.exists(contract.contractName);
3536
assert.exists(contract.sourceName);
3637
});
38+
39+
it("Should write artifacts to disk", async function () {
40+
const artifacts = await this.hre.artifacts.getArtifactPaths();
41+
const files = await getAllFiles(this.hre.config.paths.artifacts);
42+
assert.equal(artifacts.length, files.length);
43+
44+
for (const file of files) {
45+
const name = path.basename(file);
46+
assert(artifacts.map((a) => path.basename(a)).includes(name));
47+
const artifact = require(file);
48+
assert.equal(artifact.contractName, path.basename(name, ".json"));
49+
}
50+
});
3751
});
3852
});

0 commit comments

Comments
 (0)