Files

142 lines
4.5 KiB
TypeScript

import { HardhatUserConfig, subtask } from "hardhat/config";
import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from "hardhat/builtin-tasks/task-names";
import "@nomicfoundation/hardhat-toolbox";
import "@nomicfoundation/hardhat-verify";
import path from "path";
import { promises as fs } from "fs";
import dotenv from 'dotenv';
dotenv.config();
// Test-only contracts (mocks, harnesses, stubs) live OUTSIDE `paths.sources`
// — they are deliberately NOT compiled into the deployment artifact tree.
// Hardhat tests need them, so when an env var or test runner is active we
// add the `test-contracts/` directory back via a one-shot subtask override.
//
// The decomplection: `contracts/` is production source. `test-contracts/`
// is test-only. The gate is the env var; production CI/CD never sets it.
// This closes Red HIGH #8: `MockVerifier(POLICY_STARK_FRI_SHA3_PQ)` (spoofed
// policy id, accepts any input) no longer ships in deployment artifacts.
//
// Red round 5 finding B6 (LOW): the previous gate accepted ANY truthy
// `npm_lifecycle_event === "test"` — including the parent-monorepo case
// of `pnpm -w test` propagating that env into a `pnpm --filter ...
// hardhat compile` child. A production CI step running inside the same
// shell would silently include test contracts in the artifact set.
//
// Positive override `HARDHAT_PRODUCTION_BUILD=1` always WINS — it forces
// exclusion regardless of `HARDHAT_INCLUDE_TEST_CONTRACTS` or
// `npm_lifecycle_event`. Deploy CI/CD MUST set this env. See
// `contracts/README.md` (Production builds section).
const PRODUCTION_BUILD = process.env.HARDHAT_PRODUCTION_BUILD === "1";
const INCLUDE_TEST_CONTRACTS =
!PRODUCTION_BUILD &&
(process.env.HARDHAT_INCLUDE_TEST_CONTRACTS === "1" ||
process.env.npm_lifecycle_event === "test");
subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(
async (_args, _hre, runSuper) => {
const paths = (await runSuper()) as string[];
if (!INCLUDE_TEST_CONTRACTS) return paths;
const testDir = path.join(__dirname, "test-contracts");
try {
const entries = await fs.readdir(testDir);
const extras = entries
.filter((f) => f.endsWith(".sol"))
.map((f) => path.join(testDir, f));
return [...paths, ...extras];
} catch {
return paths;
}
}
);
const PRIVATE_KEY: string = process.env.PRIVATE_KEY || "0x0000000000000000000000000000000000000000000000000000000000000001";
const SEPOLIA_RPC: string = process.env.SEPOLIA_RPC || "";
const BASE_RPC: string = process.env.BASE_RPC || "";
const BSC_TESTNET_RPC: string = process.env.BSC_TESTNET_RPC || "";
const config: HardhatUserConfig = {
solidity: {
compilers: [
{
version: "0.8.20",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
{
version: "0.8.24",
settings: {
optimizer: {
enabled: true,
runs: 200
},
evmVersion: "cancun"
}
}
]
},
paths: {
sources: "./contracts",
tests: "./test",
cache: "./cache",
artifacts: "./artifacts",
// Exclude complex FHE contracts that require full refactoring
},
networks: {
hardhat: {
chainId: 31337
},
...(SEPOLIA_RPC && {
sepolia: {
url: SEPOLIA_RPC,
accounts: [PRIVATE_KEY],
}
}),
...(BSC_TESTNET_RPC && {
bsc_testnet: {
url: BSC_TESTNET_RPC,
accounts: [PRIVATE_KEY]
}
}),
...(BASE_RPC && {
base: {
url: BASE_RPC,
accounts: [PRIVATE_KEY]
}
}),
// Lux networks
lux_mainnet: {
url: process.env.LUX_MAINNET_RPC || "https://api.lux.network/v1/chain/C/rpc",
chainId: 96369,
accounts: PRIVATE_KEY !== "0x0000000000000000000000000000000000000000000000000000000000000001" ? [PRIVATE_KEY] : []
},
lux_testnet: {
url: process.env.LUX_TESTNET_RPC || "https://api.lux-test.network/v1/chain/C/rpc",
chainId: 96368,
accounts: PRIVATE_KEY !== "0x0000000000000000000000000000000000000000000000000000000000000001" ? [PRIVATE_KEY] : []
}
},
etherscan: {
apiKey: {
sepolia: process.env.ETHERSCAN_API_KEY || "",
bsc: process.env.BSCSCAN_API_KEY || ""
}
},
sourcify: {
enabled: true,
},
typechain: {
outDir: "typechain-types",
target: "ethers-v6",
dontOverrideCompile: true, // Skip typechain during compile - run separately if needed
discriminateTypes: true,
},
};
export default config;