Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/tiny-mangos-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"hardhat": patch
---

Update the default outputSelection setting of solc to decrease the artifacts size.

NOTE: This change can lead to build info ids changing, despite compilation output's bytecodes being identical.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ResolvedFileType,
type ResolvedFile,
} from "../../../../types/solidity.js";
import { DEFAULT_OUTPUT_SELECTION } from "../constants.js";

import { getEvmVersionFromSolcVersion } from "./solc-info.js";

Expand Down Expand Up @@ -130,19 +131,14 @@ export class CompilationJobImplementation implements CompilationJob {
// from other files (e.g. new Foo()), and it won't output its bytecode if
// it's not asked for. This would prevent EDR from doing any runtime
// analysis.
const outputSelection = await deepClone(settings.outputSelection ?? {});
const outputSelection: CompilerInput["settings"]["outputSelection"] =
await deepClone(settings.outputSelection ?? {});
outputSelection["*"] ??= {};
outputSelection["*"][""] ??= [];
outputSelection["*"]["*"] ??= [];

outputSelection["*"][""].push("ast");
outputSelection["*"]["*"].push(
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
);
outputSelection["*"][""].push(...DEFAULT_OUTPUT_SELECTION["*"][""]);
outputSelection["*"]["*"].push(...DEFAULT_OUTPUT_SELECTION["*"]["*"]);

const sources: { [sourceName: string]: { content: string } } = {};

Expand Down
14 changes: 2 additions & 12 deletions packages/hardhat/src/internal/builtin-plugins/solidity/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
hasOfficialArm64Build,
missesSomeOfficialNativeBuilds,
} from "./build-system/solc-info.js";
import { DEFAULT_OUTPUT_SELECTION } from "./constants.js";

/**
* The top-level type SolidityUserConfig is a union type too complex for
Expand Down Expand Up @@ -515,18 +516,7 @@ function resolveSolidityCompilerConfig(
production: boolean = false,
): SolidityCompilerConfig {
const defaultSettings: SolidityCompilerConfig["settings"] = {
outputSelection: {
"*": {
"": ["ast"],
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
],
},
},
outputSelection: DEFAULT_OUTPUT_SELECTION,
};

if (production && isSolcSolidityCompilerUserConfig(compilerConfig)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { CompilerInput } from "../../../types/solidity.js";

export const DEFAULT_OUTPUT_SELECTION: CompilerInput["settings"]["outputSelection"] =
{
"*": {
"": ["ast"],
"*": [
"abi",
"evm.bytecode.linkReferences",
"evm.bytecode.object",
"evm.bytecode.opcodes",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.immutableReferences",
"evm.deployedBytecode.linkReferences",
"evm.deployedBytecode.object",
"evm.deployedBytecode.opcodes",
"evm.deployedBytecode.sourceMap",
"evm.methodIdentifiers",
],
Comment on lines +7 to +19
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default outputSelection now uses granular selectors (e.g. evm.deployedBytecode.immutableReferences, evm.bytecode.sourceMap, etc.). Since Hardhat supports compiling a wide range of solc versions (including older 0.4.x/0.5.x via solc-js), some of these selector paths may not be accepted by older compilers. Please add a regression test that compiles with the oldest supported solc version using the default settings (or gate/fallback the selector list by solc version) so compilation doesn’t fail on older versions.

Suggested change
"*": [
"abi",
"evm.bytecode.linkReferences",
"evm.bytecode.object",
"evm.bytecode.opcodes",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.immutableReferences",
"evm.deployedBytecode.linkReferences",
"evm.deployedBytecode.object",
"evm.deployedBytecode.opcodes",
"evm.deployedBytecode.sourceMap",
"evm.methodIdentifiers",
],
"*": ["abi", "evm"],

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, i added tests for this

},
};
Original file line number Diff line number Diff line change
Expand Up @@ -541,10 +541,16 @@ describe("CompilationJobImplementation", () => {
"*": {
"*": [
"abi",
"evm.bytecode",
Comment thread
schaable marked this conversation as resolved.
"evm.deployedBytecode",
"evm.bytecode.linkReferences",
"evm.bytecode.object",
"evm.bytecode.opcodes",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.immutableReferences",
"evm.deployedBytecode.linkReferences",
"evm.deployedBytecode.object",
"evm.deployedBytecode.opcodes",
"evm.deployedBytecode.sourceMap",
"evm.methodIdentifiers",
"metadata",
"storageLayout",
],
"": ["ast"],
Expand All @@ -560,7 +566,13 @@ describe("CompilationJobImplementation", () => {
settings: {
outputSelection: {
"*": {
"*": ["storageLayout", "storageLayout", "abi", "abi"],
"*": [
"storageLayout",
"evm.bytecode.object",
Comment thread
schaable marked this conversation as resolved.
"storageLayout",
"abi",
"abi",
],
},
},
},
Expand All @@ -573,10 +585,16 @@ describe("CompilationJobImplementation", () => {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.bytecode.linkReferences",
"evm.bytecode.object",
"evm.bytecode.opcodes",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.immutableReferences",
"evm.deployedBytecode.linkReferences",
"evm.deployedBytecode.object",
"evm.deployedBytecode.opcodes",
"evm.deployedBytecode.sourceMap",
"evm.methodIdentifiers",
"metadata",
"storageLayout",
],
"": ["ast"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import type { CompilerOutput } from "../../../../../src/types/solidity.js";

import assert from "node:assert/strict";
import path from "node:path";
import { describe, it } from "node:test";

import { gte } from "semver";

import { createHardhatRuntimeEnvironment } from "../../../../../src/internal/hre-initialization.js";

import { useTestProjectTemplate } from "./resolver/helpers.js";

const FIRST_VERSION_WITH_IMMUTABLE_REFERENCES = "0.6.5";

const CONTRACTS: Record<string, string> = {
// Oldest version supported by hardhat
"0.4.11": `pragma solidity ^0.4.11;\ncontract Foo {}`,
// Last version without immutable references
"0.6.4": `pragma solidity ^0.6.4;\ncontract Foo {}`,
// First version with immutable references
"0.6.5": [
"pragma solidity ^0.6.5;",
"contract Foo {",
" uint256 public immutable x;",
" constructor() public { x = 1; }",
"}",
].join("\n"),
// Modern version
"0.8.28": [
"// SPDX-License-Identifier: UNLICENSED",
"pragma solidity ^0.8.0;",
"contract Foo {",
" uint256 public immutable x;",
" constructor() { x = 1; }",
"}",
].join("\n"),
};

/**
* Returns the first contract output from a CompilerOutput.
*/
function getContractOutput(output: CompilerOutput) {
assert(output.contracts !== undefined, "Expected contracts in output");

const sourceEntries = Object.values(output.contracts);
assert(sourceEntries.length > 0, "Expected at least one source in output");

const contractEntries = Object.values(sourceEntries[0]);
assert(
contractEntries.length > 0,
"Expected at least one contract in output",
);

return contractEntries[0];
}

describe(
"Default output selection compatibility across solc versions",
{ skip: process.env.HARDHAT_DISABLE_SLOW_TESTS === "true" },
() => {
for (const [version, contractSource] of Object.entries(CONTRACTS)) {
it(`should produce expected output fields with solc ${version}`, async () => {
await using project = await useTestProjectTemplate({
name: "output-selection-test",
version: "1.0.0",
files: {
"contracts/Foo.sol": contractSource,
},
});

const hre = await createHardhatRuntimeEnvironment(
{ solidity: { version } },
{},
project.path,
);

const rootFilePath = path.join(project.path, "contracts/Foo.sol");

const jobsResult = await hre.solidity.getCompilationJobs(
[rootFilePath],
{ force: true, quiet: true },
);

assert(jobsResult.success, `getCompilationJobs failed for ${version}`);

const compilationJob = jobsResult.compilationJobsPerFile
.values()
.next().value;
assert(compilationJob !== undefined, "Expected a compilation job");

const { output } = await hre.solidity.runCompilationJob(
compilationJob,
{ quiet: true },
);

const errors = (output.errors ?? []).filter(
(e) => e.severity === "error",
);
assert.equal(
errors.length,
0,
`Compilation errors with solc ${version}: ${errors.map((e) => e.message).join(", ")}`,
);

const contract = getContractOutput(output);

assert(contract.abi !== undefined, "Expected abi in output");

assert(contract.evm !== undefined, "Expected evm in output");

assert(
contract.evm.bytecode !== undefined,
"Expected evm.bytecode in output",
);
assert(
typeof contract.evm.bytecode.object === "string",
"Expected evm.bytecode.object",
);
assert(
typeof contract.evm.bytecode.opcodes === "string",
"Expected evm.bytecode.opcodes",
);
assert(
typeof contract.evm.bytecode.sourceMap === "string",
"Expected evm.bytecode.sourceMap",
);
assert(
contract.evm.bytecode.linkReferences !== undefined,
"Expected evm.bytecode.linkReferences",
);

assert(
contract.evm.deployedBytecode !== undefined,
"Expected evm.deployedBytecode in output",
);
assert(
typeof contract.evm.deployedBytecode.object === "string",
"Expected evm.deployedBytecode.object",
);
assert(
typeof contract.evm.deployedBytecode.opcodes === "string",
"Expected evm.deployedBytecode.opcodes",
);
assert(
typeof contract.evm.deployedBytecode.sourceMap === "string",
"Expected evm.deployedBytecode.sourceMap",
);
assert(
contract.evm.deployedBytecode.linkReferences !== undefined,
"Expected evm.deployedBytecode.linkReferences",
);

assert(
contract.evm.methodIdentifiers !== undefined,
"Expected evm.methodIdentifiers in output",
);

const supportsImmutables = gte(
version,
FIRST_VERSION_WITH_IMMUTABLE_REFERENCES,
);

if (supportsImmutables) {
assert(
contract.evm.deployedBytecode.immutableReferences !== undefined,
`Expected evm.deployedBytecode.immutableReferences in solc ${version} output`,
);
} else {
assert.equal(
contract.evm.deployedBytecode.immutableReferences,
undefined,
`Did not expect evm.deployedBytecode.immutableReferences in solc ${version} output`,
);
}
});
}
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { RawStaticCallResult } from "../../src/internal/execution/types/jsonrpc.
// On Linux ARM64 we download from a mirror that does not provide the long version, hence the known build info id has to change when running the test suite on that platform.
const buildInfoId =
os.platform() === "linux" && os.arch() === "arm64"
? "solc-0_8_19-d17b87acbe94849750bc6495e7e18cd2b1dc3d73"
: "solc-0_8_19-fa69743fd6914c0dd508b989815c073281a7e58e";
? "solc-0_8_19-137efa74d09076ba20821c90499e30d7337016be"
: "solc-0_8_19-b38bcc141d1254d1ac323f4e7ddd61668a74da0b";

export const staticCallResultFixtures: {
[contractName: string]: { [functionName: string]: RawStaticCallResult };
Expand Down
Loading