Skip to content

Commit

Permalink
add includeUnrelatedContracts flag and update for global imports
Browse files Browse the repository at this point in the history
  • Loading branch information
zoeyTM committed Apr 2, 2024
1 parent 1118c96 commit 7752825
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 68 deletions.
35 changes: 22 additions & 13 deletions packages/core/src/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import {
*/
export async function* getVerificationInformation(
deploymentDir: string,
customChains: ChainConfig[] = []
customChains: ChainConfig[] = [],
includeUnrelatedContracts = false
): AsyncGenerator<VerifyResult> {
const deploymentLoader = new FileDeploymentLoader(deploymentDir);

Expand Down Expand Up @@ -61,7 +62,8 @@ export async function* getVerificationInformation(
for (const exState of deploymentExStates) {
const verifyInfo = await convertExStateToVerifyInfo(
exState,
deploymentLoader
deploymentLoader,
includeUnrelatedContracts
);

const verifyResult: VerifyResult = [chainConfig, verifyInfo];
Expand Down Expand Up @@ -97,9 +99,13 @@ function getImportSourceNames(
const contractSource = buildInfo.input.sources[sourceName].content;
const { imports } = analyze(contractSource);

const importSources = imports.map((i) =>
path.join(path.dirname(sourceName), i).replaceAll("\\", "/")
);
const importSources = imports.map((i) => {
if (/^\.\.?[\/|\\]/.test(i)) {
return path.join(path.dirname(sourceName), i).replaceAll("\\", "/");
}

return i;
});

return [
...importSources,
Expand All @@ -109,7 +115,8 @@ function getImportSourceNames(

async function convertExStateToVerifyInfo(
exState: DeploymentExecutionState,
deploymentLoader: FileDeploymentLoader
deploymentLoader: FileDeploymentLoader,
includeUnrelatedContracts: boolean = false
) {
const [buildInfo, artifact] = await Promise.all([
deploymentLoader.readBuildInfo(exState.artifactId),
Expand All @@ -126,14 +133,16 @@ async function convertExStateToVerifyInfo(

const sourceCode = prepareInputBasedOn(buildInfo, artifact, libraries);

const sourceNames = [
artifact.sourceName,
...getImportSourceNames(artifact.sourceName, buildInfo),
];
if (!includeUnrelatedContracts) {
const sourceNames = [
artifact.sourceName,
...getImportSourceNames(artifact.sourceName, buildInfo),
];

for (const source of Object.keys(sourceCode.sources)) {
if (!sourceNames.includes(source)) {
delete sourceCode.sources[source];
for (const source of Object.keys(sourceCode.sources)) {
if (!sourceNames.includes(source)) {
delete sourceCode.sources[source];
}
}
}

Expand Down
42 changes: 42 additions & 0 deletions packages/core/test/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,46 @@ describe("verify", () => {
assert.deepEqual(actualSources, expectedSources);
}
});

it("should yield a verify result containing all available contracts when `includeUnrelatedContracts` is enabled", async () => {
const expectedResultMap: { [k: string]: string[] } = {
"contracts/TestA.sol:TestA": [
"contracts/TestA.sol",
"contracts/TestB.sol",
"contracts/TestC.sol",
"contracts/TestD.sol",
],
"contracts/TestB.sol:TestB": [
"contracts/TestA.sol",
"contracts/TestB.sol",
"contracts/TestC.sol",
"contracts/TestD.sol",
],
"contracts/TestC.sol:TestC": [
"contracts/TestA.sol",
"contracts/TestB.sol",
"contracts/TestC.sol",
"contracts/TestD.sol",
],
"contracts/TestD.sol:TestD": [
"contracts/TestA.sol",
"contracts/TestB.sol",
"contracts/TestC.sol",
"contracts/TestD.sol",
],
};

const deploymentDir = path.join(__dirname, "mocks", "verify", "min-input");

for await (const [, info] of getVerificationInformation(
deploymentDir,
undefined,
true
)) {
const expectedSources = expectedResultMap[info.name];
const actualSources = Object.keys(JSON.parse(info.sourceCode).sources);

assert.deepEqual(actualSources, expectedSources);
}
});
});
134 changes: 79 additions & 55 deletions packages/hardhat-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,82 +384,106 @@ ignitionScope

ignitionScope
.task("verify")
.addFlag(
"includeUnrelatedContracts",
"Include all compiled contracts in the verification"
)
.addPositionalParam("deploymentId", "The id of the deployment to verify")
.setDescription(
"Verify contracts from a deployment against the configured block explorers"
)
.setAction(async ({ deploymentId }: { deploymentId: string }, hre) => {
const { getVerificationInformation } = await import(
"@nomicfoundation/ignition-core"
);

const deploymentDir = path.join(
hre.config.paths.ignition,
"deployments",
deploymentId
);
.setAction(
async (
{
deploymentId,
includeUnrelatedContracts = false,
}: { deploymentId: string; includeUnrelatedContracts: boolean },
hre
) => {
const { getVerificationInformation } = await import(
"@nomicfoundation/ignition-core"
);

if (
hre.config.etherscan === undefined ||
hre.config.etherscan.apiKey === undefined ||
hre.config.etherscan.apiKey === ""
) {
throw new NomicLabsHardhatPluginError(
"@nomicfoundation/hardhat-ignition",
"No etherscan API key configured"
const deploymentDir = path.join(
hre.config.paths.ignition,
"deployments",
deploymentId
);
}

try {
for await (const [
chainConfig,
contractInfo,
] of getVerificationInformation(
deploymentDir,
hre.config.etherscan.customChains
)) {
const apiKeyAndUrls = getApiKeyAndUrls(
hre.config.etherscan.apiKey,
chainConfig
if (
hre.config.etherscan === undefined ||
hre.config.etherscan.apiKey === undefined ||
hre.config.etherscan.apiKey === ""
) {
throw new NomicLabsHardhatPluginError(
"@nomicfoundation/hardhat-ignition",
"No etherscan API key configured"
);
}

const instance = new Etherscan(...apiKeyAndUrls);

console.log(
`Verifying contract "${contractInfo.name}" for network ${chainConfig.network}...`
);
try {
for await (const [
chainConfig,
contractInfo,
] of getVerificationInformation(
deploymentDir,
hre.config.etherscan.customChains,
includeUnrelatedContracts
)) {
const apiKeyAndUrls = getApiKeyAndUrls(
hre.config.etherscan.apiKey,
chainConfig
);

const result = await verifyEtherscanContract(instance, contractInfo);
const instance = new Etherscan(...apiKeyAndUrls);

if (result.type === "success") {
console.log(
`Successfully verified contract "${contractInfo.name}" for network ${chainConfig.network}:\n - ${result.contractURL}`
`Verifying contract "${contractInfo.name}" for network ${chainConfig.network}...`
);
console.log("");
} else {
if (/already verified/gi.test(result.reason.message)) {
const contractURL = instance.getContractUrl(contractInfo.address);

const result = await verifyEtherscanContract(instance, contractInfo);

if (result.type === "success") {
console.log(
`Contract ${contractInfo.name} already verified on network ${chainConfig.network}:\n - ${contractURL}`
`Successfully verified contract "${contractInfo.name}" for network ${chainConfig.network}:\n - ${result.contractURL}`
);
console.log("");
continue;
} else {
throw new NomicLabsHardhatPluginError(
"hardhat-ignition",
result.reason.message
);
if (/already verified/gi.test(result.reason.message)) {
const contractURL = instance.getContractUrl(contractInfo.address);
console.log(
`Contract ${contractInfo.name} already verified on network ${chainConfig.network}:\n - ${contractURL}`
);
console.log("");
continue;
} else {
if (!includeUnrelatedContracts) {
throw new NomicLabsHardhatPluginError(
"hardhat-ignition",
`Verification failed. Please run \`hardhat ignition verify ${deploymentId} --include-unrelated-contracts\` to attempt verifying all contracts.`
);
} else {
throw new NomicLabsHardhatPluginError(
"hardhat-ignition",
result.reason.message
);
}
}
}
}
}
} catch (e) {
if (e instanceof IgnitionError && shouldBeHardhatPluginError(e)) {
throw new NomicLabsHardhatPluginError("hardhat-ignition", e.message, e);
}
} catch (e) {
if (e instanceof IgnitionError && shouldBeHardhatPluginError(e)) {
throw new NomicLabsHardhatPluginError(
"hardhat-ignition",
e.message,
e
);
}

throw e;
throw e;
}
}
});
);

async function resolveParametersFromModuleName(
moduleName: string,
Expand Down

0 comments on commit 7752825

Please sign in to comment.