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

Commit 73c4e56

Browse files
committed
feat: Artifacts.getBuildInfo
Implement a naive `getBuildInfo` function. This is useful for tooling that integrates more deeply with the hardhat ecosystem. Note that this implementation is not 100% with the output that the hardhat compiler toolchain outputs, but the output is good enough to get more tooling to be compatible.
1 parent 7e193d4 commit 73c4e56

5 files changed

Lines changed: 105 additions & 6 deletions

File tree

.changeset/tame-otters-sing.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+
Implement `Artifacts.getBuildInfo`

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

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,86 @@ export class ForgeArtifacts implements IArtifacts {
9999
return paths.map((p) => this._getFullyQualifiedNameFromPath(p)).sort();
100100
}
101101

102+
/**
103+
* Dynamically generate a build artifact for a contract.
104+
* In practice, hardhat build artifacts are decorated
105+
* with additional fields on top of the `BuildInfo`
106+
* type. Fields that foundry cannot fill in are currently
107+
* left blank. `extra_output` must be configured for some
108+
* fields to be populated
109+
*/
102110
public async getBuildInfo(
103-
_fullyQualifiedName: string
111+
fullyQualifiedName: string
104112
): Promise<BuildInfo | undefined> {
105-
return undefined;
113+
const artifactPath = await this._getArtifactPath(fullyQualifiedName);
114+
try {
115+
const forgeArtifact = (await fsExtra.readJson(
116+
artifactPath
117+
)) as ForgeArtifact;
118+
119+
if (!forgeArtifact.ast) {
120+
throw new Error("Must compile with ast");
121+
}
122+
123+
const relativePath = forgeArtifact.ast.absolutePath;
124+
125+
return {
126+
_format: "hh-sol-build-info-1",
127+
id: "",
128+
solcVersion: "",
129+
solcLongVersion: "",
130+
input: {
131+
language: "",
132+
sources: {},
133+
settings: {
134+
optimizer: {},
135+
metadata: { useLiteralContent: true },
136+
outputSelection: {},
137+
evmVersion: "",
138+
libraries: {},
139+
},
140+
},
141+
output: {
142+
sources: {
143+
[fullyQualifiedName]: {
144+
id: 0,
145+
ast: forgeArtifact.ast,
146+
},
147+
},
148+
contracts: {
149+
[relativePath]: {
150+
[fullyQualifiedName]: {
151+
abi: forgeArtifact.abi,
152+
devdoc: forgeArtifact.devdoc,
153+
metadata: forgeArtifact.metadata,
154+
storageLayout: forgeArtifact.storageLayout,
155+
userdoc: forgeArtifact.userdoc,
156+
evm: {
157+
bytecode: {
158+
object: forgeArtifact.bytecode.object!,
159+
opcodes: "",
160+
sourceMap: forgeArtifact.bytecode.sourceMap!,
161+
linkReferences: forgeArtifact.bytecode.linkReferences,
162+
immutableReferences: {},
163+
},
164+
deployedBytecode: {
165+
object: forgeArtifact.deployedBytecode.object!,
166+
opcodes: "",
167+
sourceMap: forgeArtifact.deployedBytecode.sourceMap!,
168+
linkReferences:
169+
forgeArtifact.deployedBytecode.linkReferences,
170+
immutableReferences: {},
171+
},
172+
methodIdentifiers: forgeArtifact.methodIdentifiers,
173+
},
174+
},
175+
},
176+
},
177+
},
178+
} as any;
179+
} catch (e) {
180+
return undefined;
181+
}
106182
}
107183

108184
public async getArtifactPaths(): Promise<string[]> {

packages/hardhat-forge/test/fixture-projects/hardhat-project/foundry.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ src = 'src'
33
out = 'out'
44
libs = ['lib']
55

6-
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
6+
extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout']
7+
8+
# See more config options https://github.com/foundry-rs/foundry/tree/master/config

packages/hardhat-forge/test/fixture-projects/hardhat-project/src/Contract.sol

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
pragma solidity ^0.8.13;
33

44
contract Contract {
5-
6-
function example() public {}
7-
5+
uint256 public bar;
6+
function example() public {}
87
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,22 @@ describe("Integration tests", function () {
4848
assert.equal(artifact.contractName, path.basename(name, ".json"));
4949
}
5050
});
51+
52+
it("Should return build info", async function () {
53+
const info = await this.hre.artifacts.getBuildInfo("Contract");
54+
assert.exists(info);
55+
const contract = info?.output.contracts["src/Contract.sol"].Contract!;
56+
assert.exists(contract);
57+
assert.exists(contract.abi);
58+
assert.exists((contract as any).devdoc);
59+
assert.exists((contract as any).metadata);
60+
assert.exists((contract as any).storageLayout);
61+
assert.exists((contract as any).userdoc);
62+
assert.exists(contract.evm);
63+
assert.exists(contract.evm.bytecode);
64+
assert.exists(contract.evm.bytecode.object);
65+
assert.exists(contract.evm.deployedBytecode);
66+
assert.exists(contract.evm.deployedBytecode.object);
67+
});
5168
});
5269
});

0 commit comments

Comments
 (0)