From 2caa372b8335bc285718bc585559b3afc275ad8f Mon Sep 17 00:00:00 2001 From: Vagabond Date: Sun, 18 Oct 2026 16:58:07 +0700 Subject: [PATCH] feat(cli): generate deployment scripts from compose config --- .changeset/config-driven-deploy-scripts.md | 5 + .../foundryAdapter/adapter.ts | 10 +- .../hardhatAdapter/adapter.ts | 18 +- .../hardhatAdapter/helpers.ts | 19 + .../adapters/IFrameworkAdapter/interface.ts | 6 + cli/src/modules/deployGeneration/model.ts | 3 +- cli/src/modules/deployGeneration/renderers.ts | 22 +- cli/src/modules/deployGeneration/types.ts | 6 +- cli/src/modules/deployScript/README.md | 19 + cli/src/modules/deployScript/contracts.ts | 28 + cli/src/modules/deployScript/model.ts | 78 + cli/src/modules/deployScript/module.ts | 57 + cli/src/modules/deployScript/project.ts | 70 + cli/src/modules/deployScript/state.ts | 11 + cli/src/modules/deployScript/types.ts | 32 + cli/src/modules/validation/project.ts | 10 +- cli/src/pipelines/deployScriptPipeline.ts | 41 + cli/src/templates/deploy/foundry-deploy.sol | 11 +- .../templates/deploy/hardhat-ethers-deploy.ts | 2 +- .../templates/deploy/hardhat-viem-deploy.ts | 2 +- .../hardhatAdapter/deployment.test.ts | 42 + .../hardhatAdapter/deploymentHarness.ts | 19 + cli/test/modules/deployScript/harness.ts | 55 + cli/test/modules/deployScript/module.test.ts | 52 + .../deployScriptPipeline.test.ts | 72 + .../fixtures/CustomDiamond.sol | 21 + .../fixtures/LocalFacet.sol | 14 + .../fixtures/PackageFacet.sol | 12 + .../fixtures/expected/Deploy.s.sol | 34 + .../fixtures/expected/deploy-ethers.ts.txt | 34 + .../fixtures/expected/deploy-viem.ts.txt | 31 + .../fixtures/helpers/CounterMod.sol | 6 + .../pipelines/deployScriptPipeline/harness.ts | 70 + .../project/package-lock.json | 2561 +++++++++++++++++ .../deployScriptPipeline/project/package.json | 10 + cli/test/pipelines/initPipeline/harness.ts | 2 + 36 files changed, 3464 insertions(+), 21 deletions(-) create mode 100644 .changeset/config-driven-deploy-scripts.md create mode 100644 cli/src/modules/deployScript/README.md create mode 100644 cli/src/modules/deployScript/contracts.ts create mode 100644 cli/src/modules/deployScript/model.ts create mode 100644 cli/src/modules/deployScript/module.ts create mode 100644 cli/src/modules/deployScript/project.ts create mode 100644 cli/src/modules/deployScript/state.ts create mode 100644 cli/src/modules/deployScript/types.ts create mode 100644 cli/src/pipelines/deployScriptPipeline.ts create mode 100644 cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deployment.test.ts create mode 100644 cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deploymentHarness.ts create mode 100644 cli/test/modules/deployScript/harness.ts create mode 100644 cli/test/modules/deployScript/module.test.ts create mode 100644 cli/test/pipelines/deployScriptPipeline/deployScriptPipeline.test.ts create mode 100644 cli/test/pipelines/deployScriptPipeline/fixtures/CustomDiamond.sol create mode 100644 cli/test/pipelines/deployScriptPipeline/fixtures/LocalFacet.sol create mode 100644 cli/test/pipelines/deployScriptPipeline/fixtures/PackageFacet.sol create mode 100644 cli/test/pipelines/deployScriptPipeline/fixtures/expected/Deploy.s.sol create mode 100644 cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-ethers.ts.txt create mode 100644 cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-viem.ts.txt create mode 100644 cli/test/pipelines/deployScriptPipeline/fixtures/helpers/CounterMod.sol create mode 100644 cli/test/pipelines/deployScriptPipeline/harness.ts create mode 100644 cli/test/pipelines/deployScriptPipeline/project/package-lock.json create mode 100644 cli/test/pipelines/deployScriptPipeline/project/package.json diff --git a/.changeset/config-driven-deploy-scripts.md b/.changeset/config-driven-deploy-scripts.md new file mode 100644 index 00000000..9a708560 --- /dev/null +++ b/.changeset/config-driven-deploy-scripts.md @@ -0,0 +1,5 @@ +--- +"@perfect-abstractions/compose-cli": minor +--- + +Add deployment script generation from compose.json with selected-diamond validation, local and package facets, framework-native contract references, and typed deployment artifacts. diff --git a/cli/src/adapters/IFrameworkAdapter/foundryAdapter/adapter.ts b/cli/src/adapters/IFrameworkAdapter/foundryAdapter/adapter.ts index e28a2c9d..d6139a9f 100644 --- a/cli/src/adapters/IFrameworkAdapter/foundryAdapter/adapter.ts +++ b/cli/src/adapters/IFrameworkAdapter/foundryAdapter/adapter.ts @@ -6,7 +6,7 @@ import { IFrameworkAdapter, SolidityAstSource, } from "../interface"; -import { writeFileIfMissing } from "../../../utils/files"; +import { writeFileIfMissing, toPosixPath } from "../../../utils/files"; import { runCommand } from "../../../utils/exec"; import { composePackageSubpath, @@ -38,6 +38,14 @@ const adapter: IFrameworkAdapter = { await runCommand("forge", ["build"], { cwd: projectRoot }); }, + async getDeploymentToolbox(): Promise { + return null; + }, + + async getDeploymentContractReference(projectRoot: string, sourcePath: string, contractName: string): Promise { + return `${toPosixPath(path.relative(projectRoot, sourcePath))}:${contractName}`; + }, + async resolveSoliditySourcePath(ctx: ComposeContext, sourcePath: string): Promise { if (path.isAbsolute(sourcePath)) return sourcePath; diff --git a/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/adapter.ts b/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/adapter.ts index 312bcdf0..ff029799 100644 --- a/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/adapter.ts +++ b/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/adapter.ts @@ -15,7 +15,7 @@ import { import { ScaffoldingModule } from "../../../modules/scaffolding/module"; import { CLI_ROOT } from "../../../utils/cliRoot"; import { isSourceUnitAst, listJsonFiles, uniqueAstSources } from "../../../utils/solidityAst"; -import { resolveHardhatAstSourcePath } from "./helpers"; +import { resolveHardhatAstSourcePath, resolveDeploymentContractReference } from "./helpers"; /** Framework adapter for Hardhat-based Diamond projects. */ const adapter: IFrameworkAdapter = { @@ -39,6 +39,22 @@ const adapter: IFrameworkAdapter = { await runCommand("npx", ["hardhat", "compile"], { cwd: projectRoot }); }, + async getDeploymentToolbox(projectRoot: string): Promise<"ethers" | "viem"> { + const manifest = JSON.parse(await fs.readFile(path.join(projectRoot, "package.json"), "utf8")) as { + dependencies?: Record; + devDependencies?: Record; + }; + const packages = { ...manifest.dependencies, ...manifest.devDependencies }; + const ethers = Boolean(packages["@nomicfoundation/hardhat-ethers"] || packages["@nomicfoundation/hardhat-toolbox-mocha-ethers"] || packages["@nomicfoundation/hardhat-toolbox"]); + const viem = Boolean(packages["@nomicfoundation/hardhat-viem"] || packages["@nomicfoundation/hardhat-toolbox-viem"]); + if (ethers === viem) throw new Error("Cannot determine the Hardhat deployment toolbox. Specify ethers or viem explicitly."); + return viem ? "viem" : "ethers"; + }, + + async getDeploymentContractReference(projectRoot: string, sourcePath: string, contractName: string): Promise { + return resolveDeploymentContractReference(projectRoot, adapter.getArtifactDir(projectRoot), sourcePath, contractName); + }, + async resolveSoliditySourcePath(ctx: ComposeContext, sourcePath: string): Promise { if (path.isAbsolute(sourcePath)) return sourcePath; diff --git a/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/helpers.ts b/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/helpers.ts index 3d42ab4b..4efc7a1d 100644 --- a/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/helpers.ts +++ b/cli/src/adapters/IFrameworkAdapter/hardhatAdapter/helpers.ts @@ -1,4 +1,23 @@ import path from "node:path"; +import fs from "node:fs/promises"; +import { listJsonFiles } from "../../../utils/solidityAst"; + +/** Resolve an artifact by its compiler source identity, including npm source aliases. */ +export async function resolveDeploymentContractReference(projectRoot: string, artifactsRoot: string, sourcePath: string, contractName: string): Promise { + const normalize = (value: string): string => process.platform === "win32" ? path.resolve(value).toLowerCase() : path.resolve(value); + const matches = new Set(); + for (const file of await listJsonFiles(artifactsRoot)) { + if (path.basename(file) !== `${contractName}.json`) continue; + const artifact = JSON.parse(await fs.readFile(file, "utf8")) as { sourceName?: string; inputSourceName?: string; contractName?: string }; + if (artifact.contractName !== contractName || !artifact.sourceName) continue; + const compilerSource = artifact.inputSourceName ?? artifact.sourceName; + if (normalize(resolveHardhatAstSourcePath(projectRoot, compilerSource)) === normalize(sourcePath)) { + matches.add(`${artifact.sourceName}:${contractName}`); + } + } + if (matches.size !== 1) throw new Error(`Deployment artifact not found or ambiguous: ${sourcePath}:${contractName}`); + return [...matches][0]; +} /** Converts a Hardhat compiler source name into its readable filesystem path. */ export function resolveHardhatAstSourcePath(projectRoot: string, sourceName: string): string { diff --git a/cli/src/adapters/IFrameworkAdapter/interface.ts b/cli/src/adapters/IFrameworkAdapter/interface.ts index 8a5fcff9..4e6971cb 100644 --- a/cli/src/adapters/IFrameworkAdapter/interface.ts +++ b/cli/src/adapters/IFrameworkAdapter/interface.ts @@ -43,6 +43,12 @@ export interface IFrameworkAdapter { /** Compile explicit Solidity entrypoints and return every unique source unit AST. */ compileAst(ctx: ComposeContext, sourcePaths: string[]): Promise; + /** Detect the deployment API installed in a Hardhat project, or null for Foundry. */ + getDeploymentToolbox(projectRoot: string): Promise<"ethers" | "viem" | null>; + + /** Resolve the compiled contract identity used by the framework's deployment API. */ + getDeploymentContractReference(projectRoot: string, sourcePath: string, contractName: string): Promise; + /** * Resolve a catalog Solidity path to a readable local file. * diff --git a/cli/src/modules/deployGeneration/model.ts b/cli/src/modules/deployGeneration/model.ts index 98237048..a3a8dd23 100644 --- a/cli/src/modules/deployGeneration/model.ts +++ b/cli/src/modules/deployGeneration/model.ts @@ -79,7 +79,6 @@ export function resolveDeployGenerationModel( facetName: facet.name, contractName: scaffoldEntry.contractName, importPath, - source: facet.source, origin: scaffoldEntry.origin, group: classifyDeployGroup(facet.source), }; @@ -92,6 +91,8 @@ export function resolveDeployGenerationModel( return { outputPath: path.join(scriptRoot, outputFileName), + projectRoot, + diamond: { contractName: "Diamond", importPath: `${ctx.param.framework === "hardhat" ? "contracts" : "src"}/Diamond.sol` }, facets, }; } diff --git a/cli/src/modules/deployGeneration/renderers.ts b/cli/src/modules/deployGeneration/renderers.ts index e054f51f..bfd9f496 100644 --- a/cli/src/modules/deployGeneration/renderers.ts +++ b/cli/src/modules/deployGeneration/renderers.ts @@ -1,6 +1,14 @@ import { DeployFacetEntry, DeployGenerationModel } from "./types"; import { toCamelCase } from "../../utils/strings"; import { loadTemplate } from "../../utils/codegen"; +import path from "node:path"; +import { toPosixPath, toRelativeImport } from "../../utils/files"; + +function scriptImport(model: DeployGenerationModel, importPath: string): string { + return toRelativeImport(toPosixPath(path.relative( + path.dirname(model.outputPath), path.resolve(model.projectRoot, importPath), + ))); +} /** * Renders a Foundry (Solidity) deploy script that deploys a Diamond proxy @@ -14,8 +22,8 @@ export async function renderFoundryDeployScript(model: DeployGenerationModel): P const imports = model.facets .map((facet) => { - const importPath = facet.origin === "local" - ? `../${facet.importPath}` + const importPath = facet.origin === "local" || !facet.importPath.startsWith("@") + ? scriptImport(model, facet.importPath) : facet.importPath; return `import {${facet.contractName}} from "${importPath}";`; }) @@ -35,10 +43,12 @@ export async function renderFoundryDeployScript(model: DeployGenerationModel): P const libraryLines = libraryFacets.map(renderDeployLine).join("\n"); return template + .replaceAll("{{DIAMOND_NAME}}", model.diamond.contractName) + .replace("{{DIAMOND_IMPORT}}", scriptImport(model, model.diamond.importPath)) .replace("{{IMPORTS}}", imports) .replace("{{FACET_COUNT}}", String(model.facets.length)) .replace("{{BASE_LINES}}", baseLines) - .replace("{{LIBRARY_LINES}}", libraryLines); + .replace("{{LIBRARY_SECTION}}", libraryLines ? `\n\n /* Library facet generation. */\n${libraryLines}` : ""); } /** @@ -49,7 +59,7 @@ export async function renderFoundryDeployScript(model: DeployGenerationModel): P */ function renderHardhatEthersFacetDeploy(facet: DeployFacetEntry): string { const variableName = toCamelCase(facet.contractName) || "facet"; - return ` const ${variableName} = await ethers.deployContract("${facet.contractName}"); + return ` const ${variableName} = await ethers.deployContract("${facet.deploymentReference ?? `${facet.importPath}:${facet.contractName}`}"); await ${variableName}.waitForDeployment(); console.log("${facet.contractName}:", await ${variableName}.getAddress()); facets.push(await ${variableName}.getAddress());`; @@ -63,7 +73,7 @@ function renderHardhatEthersFacetDeploy(facet: DeployFacetEntry): string { */ function renderHardhatViemFacetDeploy(facet: DeployFacetEntry): string { const variableName = toCamelCase(facet.contractName) || "facet"; - return ` const ${variableName} = await viem.deployContract("${facet.contractName}"); + return ` const ${variableName} = await viem.deployContract("${facet.deploymentReference ?? `${facet.importPath}:${facet.contractName}`}"); console.log("${facet.contractName}:", ${variableName}.address); facets.push(${variableName}.address);`; } @@ -105,6 +115,7 @@ export async function renderHardhatEthersDeployScript(model: DeployGenerationMod ]); return template + .replace("{{DIAMOND_REFERENCE}}", model.diamond.deploymentReference ?? `${toPosixPath(model.diamond.importPath)}:${model.diamond.contractName}`) .replace("{{BASE_LINES}}", baseLines) .replace("{{LIBRARY_LINES}}", libraryLines); } @@ -122,6 +133,7 @@ export async function renderHardhatViemDeployScript(model: DeployGenerationModel ]); return template + .replace("{{DIAMOND_REFERENCE}}", model.diamond.deploymentReference ?? `${toPosixPath(model.diamond.importPath)}:${model.diamond.contractName}`) .replace("{{BASE_LINES}}", baseLines) .replace("{{LIBRARY_LINES}}", libraryLines); } diff --git a/cli/src/modules/deployGeneration/types.ts b/cli/src/modules/deployGeneration/types.ts index d13617c3..3af25360 100644 --- a/cli/src/modules/deployGeneration/types.ts +++ b/cli/src/modules/deployGeneration/types.ts @@ -1,4 +1,4 @@ -import { FacetOrigin, SelectedFacetSource } from "../scaffolding/types"; +import { FacetOrigin } from "../scaffolding/types"; export type DeployFacetGroup = "base" | "library"; @@ -6,12 +6,14 @@ export type DeployFacetEntry = { facetName: string; contractName: string; importPath: string; - source: SelectedFacetSource; origin: FacetOrigin; group: DeployFacetGroup; + deploymentReference?: string; }; export type DeployGenerationModel = { outputPath: string; + projectRoot: string; + diamond: { contractName: string; importPath: string; deploymentReference?: string }; facets: DeployFacetEntry[]; }; diff --git a/cli/src/modules/deployScript/README.md b/cli/src/modules/deployScript/README.md new file mode 100644 index 00000000..fb062a0f --- /dev/null +++ b/cli/src/modules/deployScript/README.md @@ -0,0 +1,19 @@ +# Deployment Script Generation + +`DeployScriptPipeline.execute(ctx)` generates a deployment script from the selected diamond in `compose.json`. It is the generation workflow for the future `compose deploy` command, not an execution or confirmation workflow. + +Inputs in `ctx.param`: + +- `projectRoot`: search for `compose.json` here or in an ancestor directory. +- `diamond`: diamond key, required when several diamonds exist unless selected interactively. +- `chain`: chain key, defaults to `local`. +- `toolbox`: optional Hardhat `ethers` or `viem` override. Otherwise the framework adapter detects the installed deployment plugin. +- `yes`: disable interactive diamond selection. + +The pipeline loads the selected local/package facets, runs `ValidatePipeline` in a scoped child context, checks compiled constructor signatures, and uses the shared deploy renderers. Validation includes the existing on-chain checks when `compose.lock` contains a deployment for the selected diamond. The parent retains the child result under `ctx.state.deployValidation`. + +Scripts are written exclusively under `compose-scripts//` with timestamped, unique filenames. Foundry imports are relative to the generated script. Hardhat contract references come from compiled artifacts, including package source names. + +`ctx.state.deployScript` and `ctx.state.deployScriptPipeline` return a `DeployScriptArtifact`: script path, selected diamond, source and artifact contract identities, facet identities, chain, framework/toolbox, and source-AST expected selectors. Missing export evidence is represented as `null`. This artifact describes intended deployment and is not a transaction receipt or proof that runtime selectors match. + +The generator does not change Solidity source, `compose.json`, or `compose.lock`, and does not broadcast transactions. Constructor initialization already in the diamond source is preserved and runs when the script is executed. Supported constructors take no arguments for facets and one `address[]` argument for the diamond. Other constructor shapes and explicit `init` configuration are rejected until their configuration schema is defined. diff --git a/cli/src/modules/deployScript/contracts.ts b/cli/src/modules/deployScript/contracts.ts new file mode 100644 index 00000000..c9da9e95 --- /dev/null +++ b/cli/src/modules/deployScript/contracts.ts @@ -0,0 +1,28 @@ +import type { SolidityAstSource } from "../../adapters/IFrameworkAdapter/interface"; +import { matchesAstSource } from "../validation/astIdentity"; +import type { DeployContract, DeployProject } from "./types"; + +type Node = Record; + +/** Check supported constructor shapes before emitting a script with implicit arguments. */ +export function validateDeployConstructors(project: DeployProject, sources: SolidityAstSource[]): void { + const check = (identity: DeployContract, diamond: boolean): void => { + const matches = sources.filter((source) => matchesAstSource(source.sourceName, identity.sourcePath)) + .flatMap((source) => source.ast.nodes ?? []) + .filter((node): node is Node => Boolean(node) && typeof node === "object") + .filter((node) => node.nodeType === "ContractDefinition" && node.name === identity.contractName); + if (matches.length !== 1) throw new Error(`Contract not found or ambiguous in compiler AST: ${identity.reference}`); + const definition = matches[0]; + if (definition.abstract === true || definition.contractKind !== "contract") throw new Error(`Contract is not deployable: ${identity.reference}`); + const nodes = (definition.nodes ?? []) as Node[]; + const constructor = nodes.find((node) => node.nodeType === "FunctionDefinition" && node.kind === "constructor"); + const parameters = (constructor?.parameters as { parameters?: Node[] } | undefined)?.parameters ?? []; + const type = parameters[0]?.typeDescriptions as { typeString?: string } | undefined; + const supported = diamond + ? parameters.length === 1 && /^address\[\]( memory)?$/.test(type?.typeString ?? "") + : parameters.length === 0; + if (!supported) throw new Error(`Unsupported constructor for ${identity.reference}. Expected ${diamond ? "one address[] facet argument" : "no arguments"}.`); + }; + check(project.diamond, true); + project.facets.forEach((facet) => check(facet, false)); +} diff --git a/cli/src/modules/deployScript/model.ts b/cli/src/modules/deployScript/model.ts new file mode 100644 index 00000000..961ea6b8 --- /dev/null +++ b/cli/src/modules/deployScript/model.ts @@ -0,0 +1,78 @@ +import path from "node:path"; +import { randomUUID } from "node:crypto"; +import type { IHashingAdapter } from "../../adapters/IHashingAdapter/interface"; +import { toPosixPath } from "../../utils/files"; +import type { DeployGenerationModel } from "../deployGeneration/types"; +import { matchesAstSource } from "../validation/astIdentity"; +import type { FacetScanResult } from "../validation/types"; +import type { DeployProject, DeployScriptArtifact } from "./types"; + +export type DeploymentReferences = { diamond: string; facets: string[] }; + +/** Build the renderer model from the selected composition and framework identities. */ +export function buildDeployScriptModel( + project: DeployProject, + references: DeploymentReferences, + generatedAt: string, +): DeployGenerationModel { + const safeName = project.diamondName.replace(/[^A-Za-z0-9_-]/g, "_") || "diamond"; + const extension = project.framework === "foundry" ? "s.sol" : "ts"; + const filename = `${generatedAt.replace(/[-:.]/g, "")}-deploy-${safeName}-${randomUUID().slice(0, 8)}.${extension}`; + return { + outputPath: path.join(project.projectRoot, "compose-scripts", project.chain.key, filename), + projectRoot: project.projectRoot, + diamond: { + contractName: project.diamond.contractName, + importPath: project.diamond.reference.slice(0, project.diamond.reference.lastIndexOf(":")), + deploymentReference: references.diamond, + }, + facets: project.facets.map((facet, index) => ({ + facetName: facet.name, + contractName: facet.contractName, + origin: facet.origin, + group: "base", + importPath: toPosixPath(path.relative(project.projectRoot, facet.sourcePath)), + deploymentReference: references.facets[index], + })), + }; +} + +/** Attach source-side selector evidence without implying that the script has executed. */ +export function buildDeployScriptArtifact( + project: DeployProject, + references: DeploymentReferences, + model: DeployGenerationModel, + generatedAt: string, + toolbox: DeployScriptArtifact["toolbox"], + scans: FacetScanResult[], + hashing: IHashingAdapter, +): DeployScriptArtifact { + return { + kind: "deployment-script", + outputPath: model.outputPath, + generatedAt, + composeJsonPath: project.composeJsonPath, + diamondName: project.diamondName, + diamond: { ...project.diamond, artifactReference: references.diamond }, + chain: project.chain, + framework: project.framework, + toolbox, + selectorEvidence: "source-ast", + facets: project.facets.map((facet, index) => { + const scan = scans.find((candidate) => + candidate.facetName === facet.contractName && matchesAstSource(candidate.path, facet.sourcePath), + ); + if (!scan) throw new Error(`Missing selector evidence for ${facet.reference}.`); + return { + name: facet.name, + reference: facet.reference, + sourcePath: facet.sourcePath, + contractName: facet.contractName, + artifactReference: references.facets[index], + expectedSelectors: scan.hasExportSelectorsFunction + ? scan.exportedSelectors.map((signature) => hashing.keccak256(signature).slice(0, 10)) + : null, + }; + }), + }; +} diff --git a/cli/src/modules/deployScript/module.ts b/cli/src/modules/deployScript/module.ts new file mode 100644 index 00000000..ba92df60 --- /dev/null +++ b/cli/src/modules/deployScript/module.ts @@ -0,0 +1,57 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import type { ComposeContext } from "../../context/types"; +import type { IFrameworkAdapter } from "../../adapters/IFrameworkAdapter/interface"; +import type { IHashingAdapter } from "../../adapters/IHashingAdapter/interface"; +import type { FacetScanResult } from "../validation/types"; +import { + renderFoundryDeployScript, renderHardhatEthersDeployScript, renderHardhatViemDeployScript, +} from "../deployGeneration/renderers"; +import { loadDeployProject } from "./project"; +import { validateDeployConstructors } from "./contracts"; +import { getDeployProject } from "./state"; +import { buildDeployScriptModel, buildDeployScriptArtifact } from "./model"; + +export const DeployScriptModule = { + async loadProject(ctx: ComposeContext): Promise { + const project = await loadDeployProject(ctx); + ctx.param.projectRoot = project.projectRoot; + ctx.param.framework = project.framework; + ctx.param.diamond = project.diamondName; + ctx.state.deployProject = { success: true, result: project, error: null }; + return ctx; + }, + + async checkContracts(ctx: ComposeContext, adapter: IFrameworkAdapter): Promise { + const project = getDeployProject(ctx); + const sources = await adapter.compileAst(ctx, [project.diamond.sourcePath, ...project.facets.map((facet) => facet.sourcePath)]); + validateDeployConstructors(project, sources); + ctx.state.deployContracts = { success: true, result: { checkedContracts: project.facets.length + 1 }, error: null }; + return ctx; + }, + + async generate(ctx: ComposeContext, adapter: IFrameworkAdapter, hashing: IHashingAdapter, scans: FacetScanResult[]): Promise { + if (!ctx.state.deployContracts?.success) throw new Error("Check deployment contracts before generating a script."); + const project = getDeployProject(ctx); + let toolbox: "ethers" | "viem" | null = null; + if (project.framework === "hardhat") { + if (ctx.param.toolbox !== undefined && ctx.param.toolbox !== "ethers" && ctx.param.toolbox !== "viem") { + throw new Error("Hardhat toolbox must be ethers or viem."); + } + toolbox = ctx.param.toolbox as "ethers" | "viem" | undefined ?? await adapter.getDeploymentToolbox(project.projectRoot); + if (!toolbox) throw new Error("Cannot determine the Hardhat deployment toolbox."); + } + const generatedAt = new Date().toISOString(); + const diamondReference = await adapter.getDeploymentContractReference(project.projectRoot, project.diamond.sourcePath, project.diamond.contractName); + const facetReferences = await Promise.all(project.facets.map((facet) => adapter.getDeploymentContractReference(project.projectRoot, facet.sourcePath, facet.contractName))); + const references = { diamond: diamondReference, facets: facetReferences }; + const model = buildDeployScriptModel(project, references, generatedAt); + const source = project.framework === "foundry" ? await renderFoundryDeployScript(model) + : toolbox === "viem" ? await renderHardhatViemDeployScript(model) : await renderHardhatEthersDeployScript(model); + const artifact = buildDeployScriptArtifact(project, references, model, generatedAt, toolbox, scans, hashing); + await fs.mkdir(path.dirname(model.outputPath), { recursive: true }); + await fs.writeFile(model.outputPath, source, { encoding: "utf8", flag: "wx" }); + ctx.state.deployScript = { success: true, result: artifact, error: null }; + return ctx; + }, +}; diff --git a/cli/src/modules/deployScript/project.ts b/cli/src/modules/deployScript/project.ts new file mode 100644 index 00000000..d2772c12 --- /dev/null +++ b/cli/src/modules/deployScript/project.ts @@ -0,0 +1,70 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import type { ComposeContext } from "../../context/types"; +import { findFileAncestor, toPosixPath } from "../../utils/files"; +import { loadPrompts, selectTheme } from "../../utils/inquirer"; +import { resolveComposeProjectFacetSources } from "../validation/projectSourceResolution"; +import type { DeployContract, DeployProject } from "./types"; + +function object(value: unknown, label: string): Record { + if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object.`); + return value as Record; +} + +function contract(projectRoot: string, reference: unknown): DeployContract { + if (typeof reference !== "string") throw new Error("Contract reference must be path.sol:ContractName."); + const separator = reference.lastIndexOf(":"); + const source = reference.slice(0, separator); + const contractName = reference.slice(separator + 1); + if (separator <= 0 || !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(contractName)) { + throw new Error(`Invalid contract reference: ${reference}. Expected path.sol:ContractName.`); + } + const sourcePath = path.resolve(projectRoot, source); + return { reference: `${toPosixPath(path.relative(projectRoot, sourcePath))}:${contractName}`, sourcePath, contractName }; +} + +/** Resolve only the requested diamond, without depending on init or scaffold state. */ +export async function loadDeployProject(ctx: ComposeContext): Promise { + const composeJsonPath = await findFileAncestor(path.resolve(String(ctx.param.projectRoot ?? process.cwd())), "compose.json"); + if (!composeJsonPath) throw new Error("compose.json not found. Run 'compose init' first."); + const config = object(JSON.parse(await fs.readFile(composeJsonPath, "utf8")), "compose.json"); + const projectRoot = path.dirname(composeJsonPath); + const framework = config.framework; + if (framework !== "foundry" && framework !== "hardhat") throw new Error("compose.json must specify foundry or hardhat."); + const diamonds = object(config.diamonds, "diamonds"); + const names = Object.keys(diamonds); + let diamondName = ctx.param.diamond; + if (diamondName === undefined && names.length === 1) diamondName = names[0]; + if (diamondName === undefined && names.length > 1 && process.stdin.isTTY && process.stdout.isTTY && !ctx.param.yes) { + diamondName = await (await loadPrompts()).select({ + message: "Select the diamond to generate a deployment script for:", + choices: names.map((name) => ({ name, value: name })), theme: selectTheme, + }); + } + if (typeof diamondName !== "string" || !Object.hasOwn(diamonds, diamondName)) { + throw new Error(`Specify a diamond from compose.json. Available: ${names.join(", ") || "none"}.`); + } + const selected = object(diamonds[diamondName], `Diamond ${diamondName}`); + if (selected.init !== undefined) throw new Error("Diamond init configuration is not supported yet. Keep initialization in the contract constructor."); + const entries = Object.entries(object(selected.facets, "facets")); + if (entries.length === 0) throw new Error(`Diamond '${diamondName}' has no facets.`); + const facets: DeployProject["facets"] = []; + for (const [name, raw] of entries) { + const facet = object(raw, `Facet ${name}`); + if (facet.source === "local") { + facets.push({ ...contract(projectRoot, facet.contract), name, origin: "local" }); + } else if (facet.source === "package") { + if (typeof facet.package !== "string" || !facet.package.trim() || typeof facet.contract !== "string") { + throw new Error(`Package facet '${name}' must specify package and contract.`); + } + const contractName = facet.contract.includes(":") ? facet.contract.slice(facet.contract.lastIndexOf(":") + 1) : facet.contract; + const [resolved] = await resolveComposeProjectFacetSources(projectRoot, [{ contractName, packageName: facet.package }]); + facets.push({ ...contract(projectRoot, `${resolved.sourcePath}:${contractName}`), name, origin: "package" }); + } else throw new Error(`Unsupported facet source for '${name}': ${String(facet.source)}.`); + } + const key = ctx.param.chain ?? "local"; + if (typeof key !== "string" || !/^[A-Za-z0-9_-]+$/.test(key)) throw new Error("Invalid deployment chain key."); + const chain = object(object(config.chains, "chains")[key], `Chain ${key}`); + if (!Number.isSafeInteger(chain.chainId) || Number(chain.chainId) <= 0) throw new Error(`Invalid chainId for '${key}'.`); + return { projectRoot, composeJsonPath, framework, diamondName, diamond: contract(projectRoot, selected.contract), facets, chain: { key, chainId: Number(chain.chainId) } }; +} diff --git a/cli/src/modules/deployScript/state.ts b/cli/src/modules/deployScript/state.ts new file mode 100644 index 00000000..e5554f73 --- /dev/null +++ b/cli/src/modules/deployScript/state.ts @@ -0,0 +1,11 @@ +import type { ComposeContext, ModuleState } from "../../context/types"; +import type { DeployProject } from "./types"; + +/** Read the deployment project prepared by this module. */ +export function getDeployProject(ctx: ComposeContext): DeployProject { + const state = ctx.state.deployProject as ModuleState | undefined; + if (!state?.success || !state.result) { + throw new Error("Load the deployment project before generating a script."); + } + return state.result; +} diff --git a/cli/src/modules/deployScript/types.ts b/cli/src/modules/deployScript/types.ts new file mode 100644 index 00000000..05627d46 --- /dev/null +++ b/cli/src/modules/deployScript/types.ts @@ -0,0 +1,32 @@ +import type { DeployFacetEntry } from "../deployGeneration/types"; + +export type DeployContract = { + reference: string; + sourcePath: string; + contractName: string; +}; + +export type DeployProject = { + projectRoot: string; + composeJsonPath: string; + framework: "foundry" | "hardhat"; + diamondName: string; + diamond: DeployContract; + facets: (DeployContract & { name: string; origin: DeployFacetEntry["origin"] })[]; + chain: { key: string; chainId: number }; +}; + +/** Source-side deployment plan. This is not a receipt or proof of execution. */ +export type DeployScriptArtifact = { + kind: "deployment-script"; + outputPath: string; + generatedAt: string; + composeJsonPath: string; + diamondName: string; + diamond: DeployContract & { artifactReference: string }; + facets: (DeployContract & { name: string; artifactReference: string; expectedSelectors: string[] | null })[]; + chain: DeployProject["chain"]; + framework: DeployProject["framework"]; + toolbox: "ethers" | "viem" | null; + selectorEvidence: "source-ast"; +}; diff --git a/cli/src/modules/validation/project.ts b/cli/src/modules/validation/project.ts index 5e655053..bcddbd25 100644 --- a/cli/src/modules/validation/project.ts +++ b/cli/src/modules/validation/project.ts @@ -74,7 +74,13 @@ export async function loadValidationProject( const pendingFacets: PendingFacet[] = []; const composeFacets: ComposeProjectFacet[] = []; const userFacets: UserProjectFacet[] = []; - for (const [diamondName, diamond] of Object.entries(composeJson.diamonds ?? {})) { + const configuredDiamonds = Object.entries(composeJson.diamonds ?? {}); + const selectedDiamond = ctx.param.diamond; + if (selectedDiamond !== undefined && !configuredDiamonds.some(([name]) => name === selectedDiamond)) { + throw new Error(`Diamond '${String(selectedDiamond)}' was not found in compose.json.`); + } + for (const [diamondName, diamond] of configuredDiamonds) { + if (selectedDiamond !== undefined && diamondName !== selectedDiamond) continue; const diamondReference = typeof diamond.contract === "string" ? diamond.contract : ""; const diamondSourcePath = diamondReference.split(":")[0]; if (!diamondSourcePath) { @@ -89,7 +95,7 @@ export async function loadValidationProject( const separatorIndex = contractReference.lastIndexOf(":"); const contractName = separatorIndex >= 0 ? contractReference.slice(separatorIndex + 1) - : facetAlias; + : facet.source === "package" ? contractReference || facetAlias : facetAlias; if (!contractName) continue; if (facet.source === "package") { diff --git a/cli/src/pipelines/deployScriptPipeline.ts b/cli/src/pipelines/deployScriptPipeline.ts new file mode 100644 index 00000000..97385c9f --- /dev/null +++ b/cli/src/pipelines/deployScriptPipeline.ts @@ -0,0 +1,41 @@ +import { Context } from "../context/context"; +import type { ComposeContext, ChildPipelineState, ModuleState } from "../context/types"; +import type { DeployScriptArtifact } from "../modules/deployScript/types"; +import type { IFrameworkAdapter } from "../adapters/IFrameworkAdapter/interface"; +import { DeployScriptModule } from "../modules/deployScript/module"; +import { getDeployProject } from "../modules/deployScript/state"; +import { ValidationModule } from "../modules/validation/module"; +import { DependencyKey } from "../resolver/dependencyKey"; +import { DependencyResolver } from "../resolver/dependencyResolver"; +import { ValidatePipeline } from "./validatePipeline"; + +/** Generate a deployment artifact without executing it or changing deployment state. */ +export const DeployScriptPipeline = { + async execute(ctx: ComposeContext): Promise { + ctx = await DeployScriptModule.loadProject(ctx); + const project = getDeployProject(ctx); + const framework = project.framework as DependencyKey.Foundry | DependencyKey.Hardhat; + const deps = await DependencyResolver.resolve([{ key: framework }, { key: DependencyKey.Hashing }]); + const adapter = deps[framework] as IFrameworkAdapter | undefined; + if (!adapter || !deps.hashing) throw new Error("Deployment framework and hashing adapters are required."); + const child = Context.create(); + child.param = { projectRoot: project.projectRoot, diamond: project.diamondName }; + const validation = await ValidatePipeline.execute(child); + ctx.state.deployValidation = { + success: validation.state.validatePipeline?.success === true, + state: validation.state, status: validation.status, + } as ChildPipelineState; + if (!ctx.state.deployValidation.success) { + ctx.status = { ...validation.status, success: false, stopped: true, failedAt: "deployValidation" }; + ctx.state.deployScriptPipeline = { success: false, result: null, error: validation.status.error }; + return ctx; + } + const scans = ValidationModule.getFacetScanState(validation)?.result?.facets; + if (!scans) throw new Error("Deployment generation requires source selector evidence from validation."); + ctx = await DeployScriptModule.checkContracts(ctx, adapter); + ctx = await DeployScriptModule.generate(ctx, adapter, deps.hashing, scans); + const generated = ctx.state.deployScript as ModuleState; + ctx.state.deployScriptPipeline = { success: true, result: generated.result, error: null }; + return ctx; + }, +}; diff --git a/cli/src/templates/deploy/foundry-deploy.sol b/cli/src/templates/deploy/foundry-deploy.sol index a38f5d5a..7ce1bae6 100644 --- a/cli/src/templates/deploy/foundry-deploy.sol +++ b/cli/src/templates/deploy/foundry-deploy.sol @@ -7,25 +7,22 @@ pragma solidity ^0.8.30; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; -import {Diamond} from "../src/Diamond.sol"; +import {{{DIAMOND_NAME}}} from "{{DIAMOND_IMPORT}}"; {{IMPORTS}} contract DeployScript is Script { function setUp() public {} - function run() public returns (Diamond diamond) { + function run() public returns ({{DIAMOND_NAME}} diamond) { vm.startBroadcast(); address[] memory facets = new address[]({{FACET_COUNT}}); /* Base facet generation. */ -{{BASE_LINES}} - - /* Library facet generation. */ -{{LIBRARY_LINES}} +{{BASE_LINES}}{{LIBRARY_SECTION}} /* Define diamond proxy. */ - diamond = new Diamond(facets); + diamond = new {{DIAMOND_NAME}}(facets); console.log("Diamond:", address(diamond)); vm.stopBroadcast(); diff --git a/cli/src/templates/deploy/hardhat-ethers-deploy.ts b/cli/src/templates/deploy/hardhat-ethers-deploy.ts index 919d384e..46a59a45 100644 --- a/cli/src/templates/deploy/hardhat-ethers-deploy.ts +++ b/cli/src/templates/deploy/hardhat-ethers-deploy.ts @@ -14,7 +14,7 @@ async function deploy() { {{LIBRARY_LINES}} // Define diamond proxy. - const diamond = await ethers.deployContract("Diamond", [facets]); + const diamond = await ethers.deployContract("{{DIAMOND_REFERENCE}}", [facets]); await diamond.waitForDeployment(); console.log("Diamond:", await diamond.getAddress()); diff --git a/cli/src/templates/deploy/hardhat-viem-deploy.ts b/cli/src/templates/deploy/hardhat-viem-deploy.ts index a15fbdeb..c2785b39 100644 --- a/cli/src/templates/deploy/hardhat-viem-deploy.ts +++ b/cli/src/templates/deploy/hardhat-viem-deploy.ts @@ -14,7 +14,7 @@ async function deploy() { {{LIBRARY_LINES}} // Define diamond proxy. - const diamond = await viem.deployContract("Diamond", [facets]); + const diamond = await viem.deployContract("{{DIAMOND_REFERENCE}}", [facets]); console.log("Diamond:", diamond.address); } diff --git a/cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deployment.test.ts b/cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deployment.test.ts new file mode 100644 index 00000000..3710dd81 --- /dev/null +++ b/cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deployment.test.ts @@ -0,0 +1,42 @@ +import path from "node:path"; +import { describe, expect, it } from "vitest"; +import { hardhatAdapter } from "../../../../src/adapters/IFrameworkAdapter/hardhatAdapter/adapter"; +import { createDeploymentMetadataHarness } from "./deploymentHarness"; + +describe("Hardhat deployment metadata", () => { + it.each([ + ["@nomicfoundation/hardhat-ethers", "ethers"], + ["@nomicfoundation/hardhat-toolbox-mocha-ethers", "ethers"], + ["@nomicfoundation/hardhat-viem", "viem"], + ["@nomicfoundation/hardhat-toolbox-viem", "viem"], + ])("detects %s", async (plugin, expected) => { + const harness = await createDeploymentMetadataHarness(); + try { + await harness.writePackages({ [plugin]: "1.0.0" }); + expect(await hardhatAdapter.getDeploymentToolbox(harness.projectRoot)).toBe(expected); + } finally { await harness.cleanup(); } + }); + + it("requires an explicit choice when both or neither deployment APIs are declared", async () => { + const harness = await createDeploymentMetadataHarness(); + try { + await harness.writePackages({}); + await expect(hardhatAdapter.getDeploymentToolbox(harness.projectRoot)).rejects.toThrow("Cannot determine"); + await harness.writePackages({ "@nomicfoundation/hardhat-ethers": "1", "@nomicfoundation/hardhat-viem": "1" }); + await expect(hardhatAdapter.getDeploymentToolbox(harness.projectRoot)).rejects.toThrow("Cannot determine"); + } finally { await harness.cleanup(); } + }); + + it("distinguishes equal contract names by compiler source path and resolves npm artifact aliases", async () => { + const harness = await createDeploymentMetadataHarness(); + try { + await harness.writeArtifact("contracts/a/Facet.sol", "project/contracts/a/Facet.sol"); + await harness.writeArtifact("contracts/b/Facet.sol", "project/contracts/b/Facet.sol"); + await harness.writeArtifact("@sample/facets/Facet.sol", "npm/@sample/facets@1.2.3/Facet.sol"); + const resolve = (source: string) => hardhatAdapter.getDeploymentContractReference(harness.projectRoot, path.join(harness.projectRoot, source), "Facet"); + expect(await resolve("contracts/b/Facet.sol")).toBe("contracts/b/Facet.sol:Facet"); + expect(await resolve("node_modules/@sample/facets/Facet.sol")).toBe("@sample/facets/Facet.sol:Facet"); + await expect(resolve("missing/Facet.sol")).rejects.toThrow("artifact not found or ambiguous"); + } finally { await harness.cleanup(); } + }); +}); diff --git a/cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deploymentHarness.ts b/cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deploymentHarness.ts new file mode 100644 index 00000000..3597f159 --- /dev/null +++ b/cli/test/adapters/IFrameworkAdapter/hardhatAdapter/deploymentHarness.ts @@ -0,0 +1,19 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; + +/** Files consumed by the adapter's deployment metadata methods. */ +export async function createDeploymentMetadataHarness() { + const projectRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-hardhat-deployment-")); + return { + projectRoot, + writePackages: (devDependencies: Record) => + fs.writeFile(path.join(projectRoot, "package.json"), JSON.stringify({ devDependencies })), + async writeArtifact(sourceName: string, inputSourceName: string, contractName = "Facet"): Promise { + const file = path.join(projectRoot, "artifacts", sourceName, `${contractName}.json`); + await fs.mkdir(path.dirname(file), { recursive: true }); + await fs.writeFile(file, JSON.stringify({ sourceName, inputSourceName, contractName })); + }, + cleanup: () => fs.rm(projectRoot, { recursive: true, force: true }), + }; +} diff --git a/cli/test/modules/deployScript/harness.ts b/cli/test/modules/deployScript/harness.ts new file mode 100644 index 00000000..8ef1448a --- /dev/null +++ b/cli/test/modules/deployScript/harness.ts @@ -0,0 +1,55 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { Context } from "../../../src/context/context"; +import type { DeployProject } from "../../../src/modules/deployScript/types"; +import type { SolidityAstSource } from "../../../src/adapters/IFrameworkAdapter/interface"; + +/** Minimal filesystem inputs for module actions, without pipeline or compiler setup. */ +export async function createDeployModuleHarness() { + const projectRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-deploy-module-")); + const packageRoot = path.join(projectRoot, "node_modules/sample-facets"); + await fs.mkdir(packageRoot, { recursive: true }); + await fs.writeFile(path.join(packageRoot, "PackageFacet.sol"), "contract PackageFacet {}\n"); + const config = { + framework: "foundry", + diamonds: { + Selected: { + contract: "src/proxy/Proxy.sol:CustomDiamond", + facets: { + LocalAlias: { source: "local", contract: "src/LocalFacet.sol:LocalFacet" }, + PackageAlias: { source: "package", package: "sample-facets", contract: "PackageFacet" }, + }, + }, + Unselected: { contract: "missing/Other.sol:Other", facets: {} }, + } as Record>, + chains: { local: { chainId: 31337, rpc: "http://127.0.0.1:8545" } }, + }; + const writeConfig = () => fs.writeFile(path.join(projectRoot, "compose.json"), JSON.stringify(config)); + await writeConfig(); + const ctx = Context.create(); + ctx.param = { projectRoot, diamond: "Selected", yes: true }; + return { ctx, projectRoot, config, writeConfig, cleanup: () => fs.rm(projectRoot, { recursive: true, force: true }) }; +} + +/** Compiler-shaped prerequisite data for focused constructor-policy tests. */ +export function constructorSources(project: DeployProject, unsupported: "facet" | "diamond"): SolidityAstSource[] { + return [project.diamond, ...project.facets].map((identity, index) => { + const types = index === 0 + ? unsupported === "diamond" ? ["address[] memory", "address"] : ["address[] memory"] + : unsupported === "facet" ? ["uint256"] : []; + return { + sourceName: identity.sourcePath, + ast: { + id: index * 10, nodeType: "SourceUnit", src: "0:0:0", + nodes: [{ + nodeType: "ContractDefinition", name: identity.contractName, contractKind: "contract", + nodes: [{ + nodeType: "FunctionDefinition", kind: "constructor", + parameters: { parameters: types.map((typeString) => ({ typeDescriptions: { typeString } })) }, + }], + }], + }, + }; + }); +} diff --git a/cli/test/modules/deployScript/module.test.ts b/cli/test/modules/deployScript/module.test.ts new file mode 100644 index 00000000..52b6855c --- /dev/null +++ b/cli/test/modules/deployScript/module.test.ts @@ -0,0 +1,52 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { describe, expect, it, vi } from "vitest"; +import { DeployScriptModule } from "../../../src/modules/deployScript/module"; +import { getDeployProject } from "../../../src/modules/deployScript/state"; +import { foundryAdapter } from "../../../src/adapters/IFrameworkAdapter/foundryAdapter/adapter"; +import { createDeployModuleHarness, constructorSources } from "./harness"; + +describe("DeployScriptModule", () => { + it("requires a selection for multi-diamond projects and rejects unknown chains or init configuration", async () => { + const harness = await createDeployModuleHarness(); + try { + delete harness.ctx.param.diamond; + await expect(DeployScriptModule.loadProject(harness.ctx)).rejects.toThrow("Specify a diamond"); + harness.ctx.param.diamond = "Selected"; + harness.ctx.param.chain = "../outside"; + await expect(DeployScriptModule.loadProject(harness.ctx)).rejects.toThrow("Invalid deployment chain key"); + harness.ctx.param.chain = "missing"; + await expect(DeployScriptModule.loadProject(harness.ctx)).rejects.toThrow("Chain missing must be an object"); + harness.ctx.param.chain = "local"; + const diamonds = harness.config.diamonds as Record>; + diamonds.Selected.init = { target: "something" }; + await harness.writeConfig(); + await expect(DeployScriptModule.loadProject(harness.ctx)).rejects.toThrow("init configuration is not supported"); + } finally { await harness.cleanup(); } + }); + + it("infers the only diamond and resolves the actual package contract rather than its config alias", async () => { + const harness = await createDeployModuleHarness(); + try { + delete (harness.config.diamonds as Record).Unselected; + delete harness.ctx.param.diamond; + await harness.writeConfig(); + const result = await DeployScriptModule.loadProject(harness.ctx); + expect(getDeployProject(result).diamondName).toBe("Selected"); + expect(getDeployProject(result).facets[1]).toMatchObject({ name: "PackageAlias", contractName: "PackageFacet", origin: "package" }); + } finally { await harness.cleanup(); } + }); + + it.each(["facet", "diamond"] as const)("rejects unsupported %s constructor arguments before writing a script", async (unsupported) => { + const harness = await createDeployModuleHarness(); + try { + await DeployScriptModule.loadProject(harness.ctx); + const adapter = { + ...foundryAdapter, + compileAst: vi.fn().mockResolvedValue(constructorSources(getDeployProject(harness.ctx), unsupported)), + }; + await expect(DeployScriptModule.checkContracts(harness.ctx, adapter)).rejects.toThrow("Unsupported constructor"); + await expect(fs.access(path.join(harness.projectRoot, "compose-scripts"))).rejects.toThrow(); + } finally { await harness.cleanup(); } + }); +}); diff --git a/cli/test/pipelines/deployScriptPipeline/deployScriptPipeline.test.ts b/cli/test/pipelines/deployScriptPipeline/deployScriptPipeline.test.ts new file mode 100644 index 00000000..9285af2a --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/deployScriptPipeline.test.ts @@ -0,0 +1,72 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; +import { DeployScriptPipeline } from "../../../src/pipelines/deployScriptPipeline"; +import type { ModuleState } from "../../../src/context/types"; +import type { DeployScriptArtifact } from "../../../src/modules/deployScript/types"; +import { HashingAdapter } from "../../../src/adapters/IHashingAdapter/adapter"; +import { runCommand } from "../../../src/utils/exec"; +import { createDeployHarness, prepareHardhatDeployProject } from "./harness"; + +describe("DeployScriptPipeline", () => { + it.each(["ethers", "viem"] as const)("runs the generated Hardhat %s script using the project's toolbox", async (toolbox) => { + const harness = await createDeployHarness("hardhat"); + try { + await prepareHardhatDeployProject(harness, toolbox); + const result = await DeployScriptPipeline.execute(harness.ctx); + const artifact = (result.state.deployScript as ModuleState).result!; + expect(result.state.deployScriptPipeline.success).toBe(true); + expect(artifact.toolbox).toBe(toolbox); + expect(artifact.diamond.contractName).toBe("CustomDiamond"); + expect(artifact.facets[1].artifactReference).toBe("sample-facets/PackageFacet.sol:PackageFacet"); + expect(await fs.readFile(artifact.outputPath, "utf8")).toBe( + await fs.readFile(path.join(__dirname, `fixtures/expected/deploy-${toolbox}.ts.txt`), "utf8"), + ); + await runCommand("npx", ["hardhat", "run", artifact.outputPath], { cwd: harness.projectRoot }); + await expect(fs.access(path.join(harness.projectRoot, "compose.lock"))).rejects.toThrow(); + } finally { await harness.cleanup(); } + }, 120_000); + + it("compiles and simulates a script for the selected diamond without changing source, config, or lock", async () => { + const harness = await createDeployHarness(); + try { + const diamondPath = path.join(harness.projectRoot, "src/proxy/Proxy.sol"); + const sourceBefore = await fs.readFile(diamondPath, "utf8"); + const configBefore = await fs.readFile(path.join(harness.projectRoot, "compose.json"), "utf8"); + const lockPath = path.join(harness.projectRoot, "compose.lock"); + const lock = JSON.stringify({ compose: "0.0.7", deployments: {} }); + await fs.writeFile(lockPath, lock); + const result = await DeployScriptPipeline.execute(harness.ctx); + const artifact = (result.state.deployScript as ModuleState).result!; + expect(result.state.deployScriptPipeline.success).toBe(true); + expect(artifact).toMatchObject({ kind: "deployment-script", diamondName: "Selected", framework: "foundry", toolbox: null, chain: { key: "local", chainId: 31337 } }); + expect(artifact.diamond.reference).toBe("src/proxy/Proxy.sol:CustomDiamond"); + expect(artifact.facets.map((facet) => [facet.name, facet.expectedSelectors])).toEqual([ + ["LocalAlias", [HashingAdapter.keccak256("nextValue(uint256)").slice(0, 10)]], + ["PackageAlias", [HashingAdapter.keccak256("packageValue()").slice(0, 10)]], + ]); + const script = await fs.readFile(artifact.outputPath, "utf8"); + expect(script).toBe(await fs.readFile(path.join(__dirname, "fixtures/expected/Deploy.s.sol"), "utf8")); + expect(script).toContain('import {CustomDiamond} from "../../src/proxy/Proxy.sol";'); + expect(script).toContain('import {LocalFacet} from "../../src/nested/counter/LocalFacet.sol";'); + expect(script).not.toContain("Unselected"); + await runCommand("forge", ["script", artifact.outputPath], { cwd: harness.projectRoot }); + expect(await fs.readFile(diamondPath, "utf8")).toBe(sourceBefore); + expect(await fs.readFile(path.join(harness.projectRoot, "compose.json"), "utf8")).toBe(configBefore); + expect(await fs.readFile(lockPath, "utf8")).toBe(lock); + } finally { await harness.cleanup(); } + }, 60_000); + + it("does not emit a script when the selected facets have selector collisions", async () => { + const harness = await createDeployHarness(); + try { + const packagePath = path.join(harness.projectRoot, "node_modules/sample-facets/PackageFacet.sol"); + const source = await fs.readFile(packagePath, "utf8"); + await fs.writeFile(packagePath, source.replaceAll("packageValue()", "nextValue(uint256 value)").replace("return 42;", "return value;").replace("this.packageValue.selector", "this.nextValue.selector")); + const result = await DeployScriptPipeline.execute(harness.ctx); + expect(result.status.success).toBe(false); + expect(result.state.deployScript).toBeUndefined(); + await expect(fs.access(path.join(harness.projectRoot, "compose-scripts"))).rejects.toThrow(); + } finally { await harness.cleanup(); } + }, 60_000); +}); diff --git a/cli/test/pipelines/deployScriptPipeline/fixtures/CustomDiamond.sol b/cli/test/pipelines/deployScriptPipeline/fixtures/CustomDiamond.sol new file mode 100644 index 00000000..5a36137c --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/fixtures/CustomDiamond.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract CustomDiamond { + bytes32 constant STORAGE_POSITION = keccak256("compose.deploy.fixture"); + + constructor(address[] memory facets) { + require(facets.length == 2, "Expected exactly the selected facets"); + bytes32 slot = STORAGE_POSITION; + assembly { + sstore(slot, mload(facets)) + } + } + + function facetCount() external view returns (uint256 count) { + bytes32 slot = STORAGE_POSITION; + assembly { + count := sload(slot) + } + } +} diff --git a/cli/test/pipelines/deployScriptPipeline/fixtures/LocalFacet.sol b/cli/test/pipelines/deployScriptPipeline/fixtures/LocalFacet.sol new file mode 100644 index 00000000..70aa659f --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/fixtures/LocalFacet.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {increment} from "./helpers/CounterMod.sol"; + +contract LocalFacet { + function nextValue(uint256 value) external pure returns (uint256) { + return increment(value); + } + + function exportSelectors() external pure returns (bytes memory) { + return abi.encodePacked(this.nextValue.selector); + } +} diff --git a/cli/test/pipelines/deployScriptPipeline/fixtures/PackageFacet.sol b/cli/test/pipelines/deployScriptPipeline/fixtures/PackageFacet.sol new file mode 100644 index 00000000..1592b583 --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/fixtures/PackageFacet.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract PackageFacet { + function packageValue() external pure returns (uint256) { + return 42; + } + + function exportSelectors() external pure returns (bytes memory) { + return abi.encodePacked(this.packageValue.selector); + } +} diff --git a/cli/test/pipelines/deployScriptPipeline/fixtures/expected/Deploy.s.sol b/cli/test/pipelines/deployScriptPipeline/fixtures/expected/Deploy.s.sol new file mode 100644 index 00000000..302bd73d --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/fixtures/expected/Deploy.s.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/* Compose + * https://compose.diamonds + */ + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {CustomDiamond} from "../../src/proxy/Proxy.sol"; +import {LocalFacet} from "../../src/nested/counter/LocalFacet.sol"; +import {PackageFacet} from "../../node_modules/sample-facets/PackageFacet.sol"; + +contract DeployScript is Script { + function setUp() public {} + + function run() public returns (CustomDiamond diamond) { + vm.startBroadcast(); + + address[] memory facets = new address[](2); + + /* Base facet generation. */ + facets[0] = address(new LocalFacet()); + console.log("LocalFacet:", facets[0]); + facets[1] = address(new PackageFacet()); + console.log("PackageFacet:", facets[1]); + + /* Define diamond proxy. */ + diamond = new CustomDiamond(facets); + console.log("Diamond:", address(diamond)); + + vm.stopBroadcast(); + } +} diff --git a/cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-ethers.ts.txt b/cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-ethers.ts.txt new file mode 100644 index 00000000..bff960a1 --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-ethers.ts.txt @@ -0,0 +1,34 @@ +import { network } from "hardhat"; + +const { ethers, networkName } = await network.create(); + +async function deploy() { + console.log(`Deploying Diamond to ${networkName}...`); + + const facets: string[] = []; + + // Base facet generation. + const localFacet = await ethers.deployContract("contracts/nested/counter/LocalFacet.sol:LocalFacet"); + await localFacet.waitForDeployment(); + console.log("LocalFacet:", await localFacet.getAddress()); + facets.push(await localFacet.getAddress()); + + const packageFacet = await ethers.deployContract("sample-facets/PackageFacet.sol:PackageFacet"); + await packageFacet.waitForDeployment(); + console.log("PackageFacet:", await packageFacet.getAddress()); + facets.push(await packageFacet.getAddress()); + + // Library facet generation. + + + // Define diamond proxy. + const diamond = await ethers.deployContract("contracts/proxy/Proxy.sol:CustomDiamond", [facets]); + await diamond.waitForDeployment(); + + console.log("Diamond:", await diamond.getAddress()); +} + +deploy().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-viem.ts.txt b/cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-viem.ts.txt new file mode 100644 index 00000000..7d539550 --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/fixtures/expected/deploy-viem.ts.txt @@ -0,0 +1,31 @@ +import { network } from "hardhat"; + +const { viem, networkName } = await network.create(); + +async function deploy() { + console.log(`Deploying Diamond to ${networkName}...`); + + const facets: `0x${string}`[] = []; + + // Base facet generation. + const localFacet = await viem.deployContract("contracts/nested/counter/LocalFacet.sol:LocalFacet"); + console.log("LocalFacet:", localFacet.address); + facets.push(localFacet.address); + + const packageFacet = await viem.deployContract("sample-facets/PackageFacet.sol:PackageFacet"); + console.log("PackageFacet:", packageFacet.address); + facets.push(packageFacet.address); + + // Library facet generation. + + + // Define diamond proxy. + const diamond = await viem.deployContract("contracts/proxy/Proxy.sol:CustomDiamond", [facets]); + + console.log("Diamond:", diamond.address); +} + +deploy().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/cli/test/pipelines/deployScriptPipeline/fixtures/helpers/CounterMod.sol b/cli/test/pipelines/deployScriptPipeline/fixtures/helpers/CounterMod.sol new file mode 100644 index 00000000..f9c90079 --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/fixtures/helpers/CounterMod.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +function increment(uint256 value) pure returns (uint256) { + return value + 1; +} diff --git a/cli/test/pipelines/deployScriptPipeline/harness.ts b/cli/test/pipelines/deployScriptPipeline/harness.ts new file mode 100644 index 00000000..396c25f5 --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/harness.ts @@ -0,0 +1,70 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { Context } from "../../../src/context/context"; +import type { ComposeContext } from "../../../src/context/types"; +import { runCommand } from "../../../src/utils/exec"; + +export type DeployHarness = { + ctx: ComposeContext; + projectRoot: string; + config: Record; + writeConfig(): Promise; + cleanup(): Promise; +}; + +export async function prepareHardhatDeployProject(harness: DeployHarness, toolbox: "ethers" | "viem"): Promise { + const template = path.join(__dirname, "project"); + try { await fs.access(path.join(template, "node_modules/hardhat/package.json")); } + catch { await runCommand("npm", ["ci", "--workspaces=false"], { cwd: template }); } + const dependencies = path.join(template, "node_modules"); + for (const entry of await fs.readdir(dependencies, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + await fs.symlink(path.join(dependencies, entry.name), path.join(harness.projectRoot, "node_modules", entry.name), process.platform === "win32" ? "junction" : "dir"); + } + const plugin = `@nomicfoundation/hardhat-${toolbox}`; + await fs.writeFile(path.join(harness.projectRoot, "package.json"), JSON.stringify({ private: true, type: "module", devDependencies: { hardhat: "3.8.0", [plugin]: "*" } })); + await fs.writeFile(path.join(harness.projectRoot, "hardhat.config.ts"), `import { defineConfig } from "hardhat/config"; +import plugin from "${plugin}"; +export default defineConfig({ plugins: [plugin], solidity: { version: "0.8.30", npmFilesToBuild: ["sample-facets/PackageFacet.sol"] } }); +`); +} + +export async function createDeployHarness(framework: "foundry" | "hardhat" = "foundry"): Promise { + const projectRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-deploy-script-")); + const sourceDir = framework === "foundry" ? "src" : "contracts"; + const fixtures = path.join(__dirname, "fixtures"); + const localDir = path.join(projectRoot, sourceDir, "nested", "counter"); + const diamondDir = path.join(projectRoot, sourceDir, "proxy"); + const packageDir = path.join(projectRoot, "node_modules", "sample-facets"); + await Promise.all([fs.mkdir(localDir, { recursive: true }), fs.mkdir(diamondDir, { recursive: true }), fs.mkdir(packageDir, { recursive: true })]); + await fs.copyFile(path.join(fixtures, "LocalFacet.sol"), path.join(localDir, "LocalFacet.sol")); + await fs.cp(path.join(fixtures, "helpers"), path.join(localDir, "helpers"), { recursive: true }); + await fs.copyFile(path.join(fixtures, "CustomDiamond.sol"), path.join(diamondDir, "Proxy.sol")); + await fs.copyFile(path.join(fixtures, "PackageFacet.sol"), path.join(packageDir, "PackageFacet.sol")); + await fs.writeFile(path.join(packageDir, "package.json"), JSON.stringify({ name: "sample-facets", version: "1.0.0", exports: { "./*": "./*" } })); + if (framework === "foundry") { + await fs.writeFile(path.join(projectRoot, "foundry.toml"), '[profile.default]\nsolc = "0.8.30"\noptimizer = true\n'); + await fs.mkdir(path.join(projectRoot, "lib"), { recursive: true }); + await fs.symlink(path.resolve(__dirname, "../../../../lib/forge-std"), path.join(projectRoot, "lib", "forge-std"), process.platform === "win32" ? "junction" : "dir"); + } + const config: Record = { + framework, + diamonds: { + Selected: { + contract: `${sourceDir}/proxy/Proxy.sol:CustomDiamond`, + facets: { + LocalAlias: { source: "local", contract: `${sourceDir}/nested/counter/LocalFacet.sol:LocalFacet` }, + PackageAlias: { source: "package", package: "sample-facets", contract: "PackageFacet" }, + }, + }, + Unselected: { contract: "missing/Other.sol:Other", facets: { Missing: { source: "local", contract: "missing/Facet.sol:Missing" } } }, + }, + chains: { local: { chainId: 31337, rpc: "http://127.0.0.1:8545" } }, + }; + const writeConfig = () => fs.writeFile(path.join(projectRoot, "compose.json"), JSON.stringify(config, null, 2)); + await writeConfig(); + const ctx = Context.create(); + ctx.param = { projectRoot: localDir, diamond: "Selected", chain: "local", yes: true }; + return { ctx, projectRoot, config, writeConfig, cleanup: () => fs.rm(projectRoot, { recursive: true, force: true }) }; +} diff --git a/cli/test/pipelines/deployScriptPipeline/project/package-lock.json b/cli/test/pipelines/deployScriptPipeline/project/package-lock.json new file mode 100644 index 00000000..b0c7143b --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/project/package-lock.json @@ -0,0 +1,2561 @@ +{ + "name": "compose-deploy-script-hardhat-fixture", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "compose-deploy-script-hardhat-fixture", + "devDependencies": { + "@nomicfoundation/hardhat-ethers": "4.0.3", + "@nomicfoundation/hardhat-viem": "3.0.9", + "hardhat": "3.8.0" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0.tgz", + "integrity": "sha512-dVfrB70L//W05s+s+/c6n52Fct+kVKoXYT+/CKL9ZsNdq/yLr5LaPNsvpVkQHP1JdAiOrubUzA/MwZIk4gRxAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.12.0", + "@nomicfoundation/edr-darwin-x64": "0.12.0", + "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0", + "@nomicfoundation/edr-linux-arm64-musl": "0.12.0", + "@nomicfoundation/edr-linux-x64-gnu": "0.12.0", + "@nomicfoundation/edr-linux-x64-musl": "0.12.0", + "@nomicfoundation/edr-win32-x64-msvc": "0.12.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0.tgz", + "integrity": "sha512-z/8jU2dgZjhY2iLtJ1DGi3t/N2xbmjgok9K3R0f7+UZxSSJ5LbXCFn5So33fVh47RzGzOqEB+Yk4SdyUq2odqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0.tgz", + "integrity": "sha512-F9RrA60mEtxfKFiGB7QsydoUwzz4ckoustVMFegcIKmjRxRVb1qrRYiAc9oQiKMdJWIZKDYsOpHABJ9Um4U/+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0.tgz", + "integrity": "sha512-EtGRZbh1d4BF/1SIG5rVrKQ9R0nuNvPgCYiU5fCmY3bojAFOUf4m7I2ezIhim1vb1QBlXmFaoFNPZFIdMltBGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0.tgz", + "integrity": "sha512-5gWtmKuVfftcO1OUbF/3KTPVSR6klC7RI9Z96G5lDO325jQhYqOG+hkvDPKtM+nbYf+A0veOndghqbUgAX+E4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0.tgz", + "integrity": "sha512-0Ty0fov3/NFL0dIshNTGCi06sjVzsgB7k+n9LAoj+57OsqP9X4e3P5XwjlTSNuyYshv8JdYMHqY+1ZIZ8SHsyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0.tgz", + "integrity": "sha512-e5du3t17vdB3tAY0kl3Ip1cu8CcwiaeJeUC4mMPmL91HDM//AQehqpyIP8upam4AeIl1H6FA3xIUIDA6VOZSxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0.tgz", + "integrity": "sha512-wD8YxhFdlY2IXb7uVrSF7VHartFKXEYeiE6ISJOV10Y7YOUE1IzfwB0QOdKtLUepwB+HXis+KRy4h22dWEbT0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/hardhat-errors": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-errors/-/hardhat-errors-3.1.2.tgz", + "integrity": "sha512-+2+Pr2jlXbcMMDtAjhHMTh2PW0TDTvmuJlxmbZ99lweYV00x2iN3JFsXUcF684obNHr/hxaEoNaL6pjZ8bbPGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-utils": "^4.4.0" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@noble/curves": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz", + "integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@nomicfoundation/hardhat-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-4.4.0.tgz", + "integrity": "sha512-fRaVVbPs+Az7K3B40x8jlPDM4o7jfgoTMpxNXjg2JrpxORKqQtf9YSv9HN9lZKFZecLIYwHT3U9RQEOrZBkAEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json-node": "^0.0.26", + "env-paths": "^4.0.0", + "ethereum-cryptography": "^3.0.0", + "fast-equals": "^6.0.0", + "json-stream-stringify": "^3.1.7", + "micro-eth-signer": "^0.19.0", + "rfdc": "^1.3.1", + "undici": "^7.29.0" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@streamparser/json": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.26.tgz", + "integrity": "sha512-46597LNFI+MFdUnzX2QJWwmdTRdq0XVD+vVNJTtGVzIrnCuhG9pFo1OAzbNBqci8UJgk/X5KJZ6LcV+y7PTuDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/@streamparser/json-node": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.26.tgz", + "integrity": "sha512-9OxH3oyILbxiHxNfhvfVpyWgaiLDxreWLk6t6xdSZxJlzKciXReMN6w446+lu+cgdpJxJlwNoyfBLPtTrCUJgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json": "^0.0.26" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/ethereum-cryptography": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-3.2.0.tgz", + "integrity": "sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.0", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0" + }, + "engines": { + "node": "^14.21.3 || >=16", + "npm": ">=9" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/fast-equals": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.2.1.tgz", + "integrity": "sha512-s7KFkLPAAbIDGTh+nVYhjTiwKGvgMXAUG5vwzg8vQKj7NSRZ4eEGExBQ4rq9V90fTYVWd1cb/Wr4ffCNBmLQMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/micro-eth-signer": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.19.0.tgz", + "integrity": "sha512-vgij8q88ZMcTvWDnOy76htaneQqagvU7FYjvtxUCeQJT2iTjYCHMzw46ArybKJNZICQ8W8qUFhI9CXWCePd9uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "2.2.0", + "@noble/curves": "2.2.0", + "@noble/hashes": "2.2.0", + "micro-packed": "0.9.0" + }, + "engines": { + "node": ">= 20.19.0" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/micro-eth-signer/node_modules/@noble/ciphers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", + "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/micro-packed": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.9.0.tgz", + "integrity": "sha512-gFdaWTxEXOwtSOcpxulO4AuXVtp3HWIRmB8eq8+3m1Zku0ubgva0UGpi03YhcvsTJasHngG9gTIUK5kHNKdesg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/micro-packed/node_modules/@scure/base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.2.0.tgz", + "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-errors/node_modules/undici": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", + "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/@nomicfoundation/hardhat-ethers": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-4.0.3.tgz", + "integrity": "sha512-DtYjmHtPM1BenmNm5ZMVn5fTGD4RdDPGE/ElpaLUjDGbkQnn4ytvhqnGsY+osLaWFvDxKfhdI8fyISg53bk8Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.2", + "@nomicfoundation/hardhat-utils": "^3.0.5", + "debug": "^4.3.2", + "ethereum-cryptography": "^2.2.1", + "ethers": "^6.14.0" + }, + "peerDependencies": { + "hardhat": "^3.0.7" + } + }, + "node_modules/@nomicfoundation/hardhat-utils": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-3.0.6.tgz", + "integrity": "sha512-AD/LPNdjXNFRrZcaAAewgJpdnHpPppZxo5p+x6wGMm5Hz4B3+oLf/LUzVn8qb4DDy9RE2c24l2F8vmL/w6ZuXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json-node": "^0.0.22", + "debug": "^4.3.2", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^2.2.1", + "fast-equals": "^5.4.0", + "json-stream-stringify": "^3.1.6", + "rfdc": "^1.3.1", + "undici": "^6.16.1" + } + }, + "node_modules/@nomicfoundation/hardhat-vendored": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-vendored/-/hardhat-vendored-3.0.4.tgz", + "integrity": "sha512-RO8Otj1FvRvxJmXzkxh1vTwK/+cqSVPYLqY6RrWkmzHEEcxnAwAFsBYdW7xyTEyW/pVbSSNd2gs3aoGdGZaoNA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nomicfoundation/hardhat-viem": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-viem/-/hardhat-viem-3.0.9.tgz", + "integrity": "sha512-GtQ7l55C70Jj80yrZGdW7Kah0vPmEje29G/xVfcxchVxRRFdj1XyFZFn+7e53b11qhHMWDB787pVN+I8YZae3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.15", + "@nomicfoundation/hardhat-utils": "^4.1.2" + }, + "peerDependencies": { + "hardhat": "^3.8.0", + "viem": "^2.47.6" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@noble/curves": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz", + "integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@nomicfoundation/hardhat-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-4.4.0.tgz", + "integrity": "sha512-fRaVVbPs+Az7K3B40x8jlPDM4o7jfgoTMpxNXjg2JrpxORKqQtf9YSv9HN9lZKFZecLIYwHT3U9RQEOrZBkAEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json-node": "^0.0.26", + "env-paths": "^4.0.0", + "ethereum-cryptography": "^3.0.0", + "fast-equals": "^6.0.0", + "json-stream-stringify": "^3.1.7", + "micro-eth-signer": "^0.19.0", + "rfdc": "^1.3.1", + "undici": "^7.29.0" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@streamparser/json": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.26.tgz", + "integrity": "sha512-46597LNFI+MFdUnzX2QJWwmdTRdq0XVD+vVNJTtGVzIrnCuhG9pFo1OAzbNBqci8UJgk/X5KJZ6LcV+y7PTuDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/@streamparser/json-node": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.26.tgz", + "integrity": "sha512-9OxH3oyILbxiHxNfhvfVpyWgaiLDxreWLk6t6xdSZxJlzKciXReMN6w446+lu+cgdpJxJlwNoyfBLPtTrCUJgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json": "^0.0.26" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/ethereum-cryptography": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-3.2.0.tgz", + "integrity": "sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.0", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0" + }, + "engines": { + "node": "^14.21.3 || >=16", + "npm": ">=9" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/fast-equals": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.2.1.tgz", + "integrity": "sha512-s7KFkLPAAbIDGTh+nVYhjTiwKGvgMXAUG5vwzg8vQKj7NSRZ4eEGExBQ4rq9V90fTYVWd1cb/Wr4ffCNBmLQMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/micro-eth-signer": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.19.0.tgz", + "integrity": "sha512-vgij8q88ZMcTvWDnOy76htaneQqagvU7FYjvtxUCeQJT2iTjYCHMzw46ArybKJNZICQ8W8qUFhI9CXWCePd9uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "2.2.0", + "@noble/curves": "2.2.0", + "@noble/hashes": "2.2.0", + "micro-packed": "0.9.0" + }, + "engines": { + "node": ">= 20.19.0" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/micro-eth-signer/node_modules/@noble/ciphers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", + "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/micro-packed": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.9.0.tgz", + "integrity": "sha512-gFdaWTxEXOwtSOcpxulO4AuXVtp3HWIRmB8eq8+3m1Zku0ubgva0UGpi03YhcvsTJasHngG9gTIUK5kHNKdesg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/micro-packed/node_modules/@scure/base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.2.0.tgz", + "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-viem/node_modules/undici": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", + "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-zod-utils/-/hardhat-zod-utils-3.0.7.tgz", + "integrity": "sha512-Q7k+cEnLRZGqxbi6iLk40z1LAVmcBoFSHCwOiOy8dbkxPAifrZoBEZPnA0+HD7yMBa+s7GvqZYq74Q3Or/5mpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.13", + "@nomicfoundation/hardhat-utils": "^4.1.2" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@noble/curves": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz", + "integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@nomicfoundation/hardhat-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-4.4.0.tgz", + "integrity": "sha512-fRaVVbPs+Az7K3B40x8jlPDM4o7jfgoTMpxNXjg2JrpxORKqQtf9YSv9HN9lZKFZecLIYwHT3U9RQEOrZBkAEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json-node": "^0.0.26", + "env-paths": "^4.0.0", + "ethereum-cryptography": "^3.0.0", + "fast-equals": "^6.0.0", + "json-stream-stringify": "^3.1.7", + "micro-eth-signer": "^0.19.0", + "rfdc": "^1.3.1", + "undici": "^7.29.0" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@streamparser/json": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.26.tgz", + "integrity": "sha512-46597LNFI+MFdUnzX2QJWwmdTRdq0XVD+vVNJTtGVzIrnCuhG9pFo1OAzbNBqci8UJgk/X5KJZ6LcV+y7PTuDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/@streamparser/json-node": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.26.tgz", + "integrity": "sha512-9OxH3oyILbxiHxNfhvfVpyWgaiLDxreWLk6t6xdSZxJlzKciXReMN6w446+lu+cgdpJxJlwNoyfBLPtTrCUJgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json": "^0.0.26" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/ethereum-cryptography": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-3.2.0.tgz", + "integrity": "sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.0", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0" + }, + "engines": { + "node": "^14.21.3 || >=16", + "npm": ">=9" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/fast-equals": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.2.1.tgz", + "integrity": "sha512-s7KFkLPAAbIDGTh+nVYhjTiwKGvgMXAUG5vwzg8vQKj7NSRZ4eEGExBQ4rq9V90fTYVWd1cb/Wr4ffCNBmLQMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/micro-eth-signer": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.19.0.tgz", + "integrity": "sha512-vgij8q88ZMcTvWDnOy76htaneQqagvU7FYjvtxUCeQJT2iTjYCHMzw46ArybKJNZICQ8W8qUFhI9CXWCePd9uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "2.2.0", + "@noble/curves": "2.2.0", + "@noble/hashes": "2.2.0", + "micro-packed": "0.9.0" + }, + "engines": { + "node": ">= 20.19.0" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/micro-eth-signer/node_modules/@noble/ciphers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", + "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/micro-packed": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.9.0.tgz", + "integrity": "sha512-gFdaWTxEXOwtSOcpxulO4AuXVtp3HWIRmB8eq8+3m1Zku0ubgva0UGpi03YhcvsTJasHngG9gTIUK5kHNKdesg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/micro-packed/node_modules/@scure/base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.2.0.tgz", + "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils/node_modules/undici": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", + "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sentry/core": { + "version": "9.47.2", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.47.2.tgz", + "integrity": "sha512-WYEP2ZHkTQMP7Gg5frzrQy1475TnK5Qv8wgvHiTlNerYaEBCNpAeWjUltTgfCQ8Hbv1iq4inca7Kqmmyv9gLnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@streamparser/json": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.22.tgz", + "integrity": "sha512-b6gTSBjJ8G8SuO3Gbbj+zXbVx8NSs1EbpbMKpzGLWMdkR+98McH9bEjSz3+0mPJf68c5nxa3CrJHp5EQNXM6zQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@streamparser/json-node": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.22.tgz", + "integrity": "sha512-sJT2ptNRwqB1lIsQrQlCoWk5rF4tif9wDh+7yluAGijJamAhrHGYpFB/Zg3hJeceoZypi74ftXk8DHzwYpbZSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json": "^0.0.22" + } + }, + "node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/abitype": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", + "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/ethers": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz", + "integrity": "sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.11.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.21.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-equals": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.5.tgz", + "integrity": "sha512-yKEpcFuRPu/pTQL2VB8YKE2yFldrLlIsoWtJeBnAdqEhvu21OgkFT0C8njf/xYc2LSZGEr3K9JGjthHJxnVLvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/hardhat": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-3.8.0.tgz", + "integrity": "sha512-luWXeLA4dcEoj3QrJhmnf+kRyGn9SrrUN9zf2KlrysXt9U3VIhLYZ8vNIA8HP4fZuvrlKMXHRdLDu0+9Gnmrkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr": "0.12.0", + "@nomicfoundation/hardhat-errors": "^3.0.15", + "@nomicfoundation/hardhat-utils": "^4.1.3", + "@nomicfoundation/hardhat-vendored": "^3.0.4", + "@nomicfoundation/hardhat-zod-utils": "^3.0.5", + "@nomicfoundation/solidity-analyzer": "^0.1.1", + "@sentry/core": "^9.4.0", + "adm-zip": "^0.4.16", + "chokidar": "^4.0.3", + "enquirer": "^2.3.0", + "ethereum-cryptography": "^2.2.1", + "micro-eth-signer": "^0.14.0", + "p-map": "^7.0.2", + "resolve.exports": "^2.0.3", + "semver": "^7.6.3", + "tsx": "^4.19.3", + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "bin": { + "hardhat": "dist/src/cli.js" + } + }, + "node_modules/hardhat/node_modules/@noble/curves": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz", + "integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@nomicfoundation/hardhat-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-4.4.0.tgz", + "integrity": "sha512-fRaVVbPs+Az7K3B40x8jlPDM4o7jfgoTMpxNXjg2JrpxORKqQtf9YSv9HN9lZKFZecLIYwHT3U9RQEOrZBkAEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json-node": "^0.0.26", + "env-paths": "^4.0.0", + "ethereum-cryptography": "^3.0.0", + "fast-equals": "^6.0.0", + "json-stream-stringify": "^3.1.7", + "micro-eth-signer": "^0.19.0", + "rfdc": "^1.3.1", + "undici": "^7.29.0" + } + }, + "node_modules/hardhat/node_modules/@nomicfoundation/hardhat-utils/node_modules/ethereum-cryptography": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-3.2.0.tgz", + "integrity": "sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.0", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0" + }, + "engines": { + "node": "^14.21.3 || >=16", + "npm": ">=9" + } + }, + "node_modules/hardhat/node_modules/@nomicfoundation/hardhat-utils/node_modules/micro-eth-signer": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.19.0.tgz", + "integrity": "sha512-vgij8q88ZMcTvWDnOy76htaneQqagvU7FYjvtxUCeQJT2iTjYCHMzw46ArybKJNZICQ8W8qUFhI9CXWCePd9uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/ciphers": "2.2.0", + "@noble/curves": "2.2.0", + "@noble/hashes": "2.2.0", + "micro-packed": "0.9.0" + }, + "engines": { + "node": ">= 20.19.0" + } + }, + "node_modules/hardhat/node_modules/@nomicfoundation/hardhat-utils/node_modules/micro-eth-signer/node_modules/@noble/ciphers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", + "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@nomicfoundation/hardhat-utils/node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@nomicfoundation/hardhat-utils/node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@streamparser/json": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.26.tgz", + "integrity": "sha512-46597LNFI+MFdUnzX2QJWwmdTRdq0XVD+vVNJTtGVzIrnCuhG9pFo1OAzbNBqci8UJgk/X5KJZ6LcV+y7PTuDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/hardhat/node_modules/@streamparser/json-node": { + "version": "0.0.26", + "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.26.tgz", + "integrity": "sha512-9OxH3oyILbxiHxNfhvfVpyWgaiLDxreWLk6t6xdSZxJlzKciXReMN6w446+lu+cgdpJxJlwNoyfBLPtTrCUJgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json": "^0.0.26" + } + }, + "node_modules/hardhat/node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hardhat/node_modules/fast-equals": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.2.1.tgz", + "integrity": "sha512-s7KFkLPAAbIDGTh+nVYhjTiwKGvgMXAUG5vwzg8vQKj7NSRZ4eEGExBQ4rq9V90fTYVWd1cb/Wr4ffCNBmLQMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/hardhat/node_modules/micro-packed": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.9.0.tgz", + "integrity": "sha512-gFdaWTxEXOwtSOcpxulO4AuXVtp3HWIRmB8eq8+3m1Zku0ubgva0UGpi03YhcvsTJasHngG9gTIUK5kHNKdesg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/micro-packed/node_modules/@scure/base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.2.0.tgz", + "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/undici": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", + "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/is-safe-filename": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", + "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peer": true, + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/json-stream-stringify": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.7.tgz", + "integrity": "sha512-F4MWetLtY42YMaAKw5cV4e47zMD5aOT+tjjQWjX18ACtdkQ5Y/vrcfbcQ107Rh+MXjOCIx4KhW0wPmOvG8iQ5w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=7.10.1" + } + }, + "node_modules/micro-eth-signer": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "micro-packed": "~0.7.2" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ox": { + "version": "0.14.56", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.56.tgz", + "integrity": "sha512-Feinlj+deWEam6RIwurRE+eHZ2N3hoUb3AAjQ10BmxRCYIymfqNkv0eZ+4ln4GkgDmSGLD2rGtTMqsFYSVDC6w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.2.3", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ox/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/p-map": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.1.1.tgz", + "integrity": "sha512-6Lh3jQPLthYujSrlw6ccWXBGZTkoTCz27Hd92g79LH/kjAbgoEu0t442cCCNbegPSJsA0lwDX8z0bcKtkpA32g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.4.tgz", + "integrity": "sha512-zepuGL0ulf+nt+XaFrlKeaiTJeyPFPLLY62+ncq1/VTHBdt3HsfXOH60priZ6tnXQozdGcDeIF5JVTanvIcYWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/undici": { + "version": "6.29.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.1.tgz", + "integrity": "sha512-EvRlUt/QqAEvXdQeRMYUfwOQsfzpDztykrG2owGEE/rBOBoYv9uF39ZzsNDh4lTFHhTr2XOZjKkYgueD12ZmGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/viem": { + "version": "2.57.7", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.57.7.tgz", + "integrity": "sha512-x3UqqrcQuESaRVK6a0BvNmoNP0SVhu913uxEAxYLJx1lNYnj6ylTntfUdakCUKjk1+T+63gkdwFGJQ2O5C/nRw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/curves": "1.9.1", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0", + "abitype": "1.2.3", + "isows": "1.0.7", + "ox": "0.14.56", + "ws": "8.21.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/cli/test/pipelines/deployScriptPipeline/project/package.json b/cli/test/pipelines/deployScriptPipeline/project/package.json new file mode 100644 index 00000000..f7aebe58 --- /dev/null +++ b/cli/test/pipelines/deployScriptPipeline/project/package.json @@ -0,0 +1,10 @@ +{ + "name": "compose-deploy-script-hardhat-fixture", + "private": true, + "type": "module", + "devDependencies": { + "hardhat": "3.8.0", + "@nomicfoundation/hardhat-ethers": "4.0.3", + "@nomicfoundation/hardhat-viem": "3.0.9" + } +} diff --git a/cli/test/pipelines/initPipeline/harness.ts b/cli/test/pipelines/initPipeline/harness.ts index d0076cb2..ad19b50a 100644 --- a/cli/test/pipelines/initPipeline/harness.ts +++ b/cli/test/pipelines/initPipeline/harness.ts @@ -56,6 +56,8 @@ function createFixtureAdapter(framework: InitFramework): IFrameworkAdapter { getScriptRoot: (projectRoot) => path.join(projectRoot, scriptDirectory), getTestRoot: (projectRoot) => path.join(projectRoot, "test"), getArtifactDir: (projectRoot) => path.join(projectRoot, artifactDirectory), + getDeploymentToolbox: async () => framework === "hardhat" ? "ethers" : null, + getDeploymentContractReference: async (_root, sourcePath, contractName) => `${sourcePath}:${contractName}`, compile: vi.fn(async () => undefined), compileAst: vi.fn(async (_ctx, sourcePaths) => sourcePaths.map((sourcePath, index) => contractAst(sourcePath, contractNameFromSourcePath(sourcePath), index * 10 + 1)