Skip to content

Commit 65b67d3

Browse files
committed
re-enable contract verification with hardhat ignition
1 parent f5a835d commit 65b67d3

File tree

17 files changed

+115
-809
lines changed

17 files changed

+115
-809
lines changed

pnpm-lock.yaml

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

v-next/hardhat-ignition-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nomicfoundation/ignition-core",
3-
"version": "3.0.0-next.21",
3+
"version": "3.0.0-next.24",
44
"description": "Hardhat Ignition is a declarative system for deploying smart contracts on Ethereum. It enables you to define smart contract instances you want to deploy, and any operation you want to run on them. By taking over the deployment and execution, Hardhat Ignition lets you focus on your project instead of getting caught up in the deployment details.",
55
"homepage": "https://hardhat.org",
66
"repository": {

v-next/hardhat-ignition-core/src/types/verify.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { SolidityParameterType } from "./module.js";
2+
13
/**
24
* The configuration info needed to verify a contract on Etherscan on a given chain.
35
*
@@ -32,19 +34,17 @@ export interface SourceToLibraryToAddress {
3234
*/
3335
export interface VerifyInfo {
3436
address: string;
35-
compilerVersion: string;
36-
sourceCode: string;
37-
name: string;
38-
args: string;
37+
constructorArgs: SolidityParameterType[];
38+
libraries: Record<string, string>;
39+
contract: string;
3940
}
4041

4142
/**
4243
* The result of requesting the verification info for a deployment.
43-
* It returns the chainConfig followed by an array of VerifyInfo objects, one for each contract to be verified.
44-
* Alternatively, it returns null and the contract name if the contract used external artifacts that could not be resolved for verification.
44+
* It returns a VerifyInfo object for each contract to be verified.
45+
* Alternatively, it returns the contract name if the contract used
46+
* external artifacts that could not be resolved for verification.
4547
*
4648
* @beta
4749
*/
48-
export type VerifyResult =
49-
| [ChainConfig, VerifyInfo]
50-
| [_null: null, name: string];
50+
export type VerifyResult = VerifyInfo | string;
Lines changed: 10 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
1-
import type { DeploymentState } from "./internal/execution/types/deployment-state.js";
21
import type { DeploymentExecutionState } from "./internal/execution/types/execution-state.js";
3-
import type { Artifact, BuildInfo, CompilerInput } from "./types/artifact.js";
4-
import type {
5-
ChainConfig,
6-
SourceToLibraryToAddress,
7-
VerifyInfo,
8-
VerifyResult,
9-
} from "./types/verify.js";
10-
11-
import path from "node:path";
2+
import type { Artifact } from "./types/artifact.js";
3+
import type { VerifyInfo, VerifyResult } from "./types/verify.js";
124

135
import { HardhatError } from "@nomicfoundation/hardhat-errors";
146
import { FileNotFoundError } from "@nomicfoundation/hardhat-utils/fs";
15-
import { analyze } from "@nomicfoundation/solidity-analyzer";
167

17-
import { builtinChains } from "./internal/chain-config.js";
188
import { FileDeploymentLoader } from "./internal/deployment-loader/file-deployment-loader.js";
19-
import { encodeDeploymentArguments } from "./internal/execution/abi.js";
209
import { loadDeploymentState } from "./internal/execution/deployment-state-helpers.js";
2110
import { ExecutionResultType } from "./internal/execution/types/execution-result.js";
2211
import {
@@ -30,14 +19,11 @@ import { findExecutionStatesByType } from "./internal/views/find-execution-state
3019
* Retrieve the information required to verify all contracts from a deployment on Etherscan.
3120
*
3221
* @param deploymentDir - the file directory of the deployment
33-
* @param customChains - an array of custom chain configurations
3422
*
3523
* @beta
3624
*/
3725
export async function* getVerificationInformation(
3826
deploymentDir: string,
39-
customChains: ChainConfig[] = [],
40-
includeUnrelatedContracts = false,
4127
): AsyncGenerator<VerifyResult> {
4228
const deploymentLoader = new FileDeploymentLoader(deploymentDir);
4329

@@ -52,8 +38,6 @@ export async function* getVerificationInformation(
5238
);
5339
}
5440

55-
const chainConfig = resolveChainConfig(deploymentState, customChains);
56-
5741
const deploymentExStates = findExecutionStatesByType(
5842
ExecutionSateType.DEPLOYMENT_EXECUTION_STATE,
5943
deploymentState,
@@ -72,85 +56,25 @@ export async function* getVerificationInformation(
7256
const verifyInfo = await convertExStateToVerifyInfo(
7357
exState,
7458
deploymentLoader,
75-
includeUnrelatedContracts,
7659
);
7760

7861
if (typeof verifyInfo === "string") {
79-
yield [null, verifyInfo];
62+
yield verifyInfo;
8063
continue;
8164
}
8265

83-
const verifyResult: VerifyResult = [chainConfig, verifyInfo];
84-
85-
yield verifyResult;
86-
}
87-
}
88-
89-
function resolveChainConfig(
90-
deploymentState: DeploymentState,
91-
customChains: ChainConfig[],
92-
) {
93-
// implementation note:
94-
// if a user has set a custom chain with the same chainId as a builtin chain,
95-
// the custom chain will be used instead of the builtin chain
96-
const chainConfig = [...customChains, ...builtinChains].find(
97-
(c) => c.chainId === deploymentState.chainId,
98-
);
99-
100-
if (chainConfig === undefined) {
101-
throw new HardhatError(
102-
HardhatError.ERRORS.IGNITION.VERIFY.UNSUPPORTED_CHAIN,
103-
{
104-
chainId: deploymentState.chainId,
105-
},
106-
);
107-
}
108-
109-
return chainConfig;
110-
}
111-
112-
export function getImportSourceNames(
113-
sourceName: string,
114-
buildInfo: BuildInfo,
115-
visited: Record<string, boolean> = {},
116-
): string[] {
117-
if (visited[sourceName]) {
118-
return [];
66+
yield verifyInfo;
11967
}
120-
121-
visited[sourceName] = true;
122-
123-
const contractSource = buildInfo.input.sources[sourceName].content;
124-
const { imports } = analyze(contractSource);
125-
126-
const importSources = imports.map((i) => {
127-
if (/^\.\.?[\/|\\]/.test(i)) {
128-
return path.join(path.dirname(sourceName), i).replaceAll("\\", "/");
129-
}
130-
131-
return i;
132-
});
133-
134-
return [
135-
...importSources,
136-
...importSources.flatMap((i) =>
137-
getImportSourceNames(i, buildInfo, visited),
138-
),
139-
];
14068
}
14169

14270
async function convertExStateToVerifyInfo(
14371
exState: DeploymentExecutionState,
14472
deploymentLoader: FileDeploymentLoader,
145-
includeUnrelatedContracts: boolean = false,
14673
): Promise<VerifyInfo | string> {
147-
let result: [BuildInfo, Artifact];
74+
let artifact: Artifact;
14875

14976
try {
150-
result = await Promise.all([
151-
deploymentLoader.readBuildInfo(exState.artifactId),
152-
deploymentLoader.loadArtifact(exState.artifactId),
153-
]);
77+
artifact = await deploymentLoader.loadArtifact(exState.artifactId);
15478
} catch (e) {
15579
assertIgnitionInvariant(
15680
e instanceof FileNotFoundError,
@@ -164,8 +88,6 @@ async function convertExStateToVerifyInfo(
16488
return exState.artifactId;
16589
}
16690

167-
const [buildInfo, artifact] = result;
168-
16991
const { contractName, constructorArgs, libraries } = exState;
17092

17193
assertIgnitionInvariant(
@@ -174,78 +96,12 @@ async function convertExStateToVerifyInfo(
17496
`Deployment execution state ${exState.id} should have a successful result to retrieve address`,
17597
);
17698

177-
const sourceCode = prepareInputBasedOn(buildInfo, artifact, libraries);
178-
179-
if (!includeUnrelatedContracts) {
180-
const sourceNames = [
181-
artifact.sourceName,
182-
...getImportSourceNames(artifact.sourceName, buildInfo),
183-
];
184-
185-
for (const source of Object.keys(sourceCode.sources)) {
186-
if (!sourceNames.includes(source)) {
187-
delete sourceCode.sources[source];
188-
}
189-
}
190-
}
191-
192-
const verifyInfo = {
99+
const verifyInfo: VerifyInfo = {
100+
constructorArgs,
101+
libraries,
193102
address: exState.result.address,
194-
compilerVersion: buildInfo.solcLongVersion.startsWith("v")
195-
? buildInfo.solcLongVersion
196-
: `v${buildInfo.solcLongVersion}`,
197-
sourceCode: JSON.stringify(sourceCode),
198-
name: `${artifact.sourceName}:${contractName}`,
199-
args: encodeDeploymentArguments(artifact, constructorArgs),
103+
contract: `${artifact.sourceName}:${contractName}`,
200104
};
201105

202106
return verifyInfo;
203107
}
204-
205-
function prepareInputBasedOn(
206-
buildInfo: BuildInfo,
207-
artifact: Artifact,
208-
libraries: Record<string, string>,
209-
): CompilerInput {
210-
const sourceToLibraryAddresses = resolveLibraryInfoForArtifact(
211-
artifact,
212-
libraries,
213-
);
214-
215-
if (sourceToLibraryAddresses === null) {
216-
return buildInfo.input;
217-
}
218-
219-
const { input } = buildInfo;
220-
input.settings.libraries = sourceToLibraryAddresses;
221-
222-
return input;
223-
}
224-
225-
function resolveLibraryInfoForArtifact(
226-
artifact: Artifact,
227-
libraries: Record<string, string>,
228-
): SourceToLibraryToAddress | null {
229-
const sourceToLibraryToAddress: SourceToLibraryToAddress = {};
230-
231-
for (const [sourceName, refObj] of Object.entries(artifact.linkReferences)) {
232-
for (const [libName] of Object.entries(refObj)) {
233-
sourceToLibraryToAddress[sourceName] ??= {};
234-
235-
const libraryAddress = libraries[libName];
236-
237-
assertIgnitionInvariant(
238-
libraryAddress !== undefined,
239-
`Could not find address for library ${libName}`,
240-
);
241-
242-
sourceToLibraryToAddress[sourceName][libName] = libraryAddress;
243-
}
244-
}
245-
246-
if (Object.entries(sourceToLibraryToAddress).length === 0) {
247-
return null;
248-
}
249-
250-
return sourceToLibraryToAddress;
251-
}

v-next/hardhat-ignition-core/test/mocks/verify/external-artifacts/artifacts/LockModule#Basic.json

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)