From 2102aebf90962c5f6a31a674053ffe31431816e5 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 12:55:30 -0400 Subject: [PATCH 01/18] wip cli --- cli/.gitignore | 8 + cli/.gitmodules | 6 + cli/.npmignore | 7 + cli/CHANGELOG.md | 8 + cli/LICENSE | 21 + cli/README.md | 101 + cli/eslint.config.js | 25 + cli/index.js | 56 + cli/package-lock.json | 5937 +++++++++++++++++ cli/package.json | 70 + cli/scripts/generate-templates-config.js | 143 + cli/src/commands/init.js | 148 + cli/src/commands/listTemplates.js | 23 + cli/src/commands/update.js | 14 + cli/src/commands/version.js | 9 + cli/src/config/constants.js | 26 + cli/src/config/templates.json | 38 + cli/src/config/validateTemplatesConfig.js | 38 + cli/src/prompts/initPrompts.js | 68 + cli/src/scaffold/frameworks/foundry.js | 46 + cli/src/scaffold/frameworks/hardhat.js | 50 + cli/src/scaffold/scaffold.js | 49 + cli/src/scaffold/utils/fileManager.js | 75 + cli/src/scaffold/utils/packageOrderer.js | 32 + cli/src/scaffold/utils/templateLoader.js | 51 + cli/src/scaffold/utils/tokenReplace.js | 40 + cli/src/templates/default/foundry/.gitignore | 5 + cli/src/templates/default/foundry/README.md | 9 + .../templates/default/foundry/foundry.toml | 9 + .../templates/default/foundry/remappings.txt | 1 + .../default/foundry/script/Deploy.s.sol | 27 + .../templates/default/foundry/src/Diamond.sol | 18 + .../foundry/src/facets/CounterFacet.sol | 33 + .../default/foundry/test/CounterFacet.t.sol | 28 + .../default/hardhat/ts/minimal/.gitignore | 20 + .../default/hardhat/ts/minimal/README.md | 20 + .../hardhat/ts/minimal/contracts/Diamond.sol | 18 + .../minimal/contracts/facets/CounterFacet.sol | 33 + .../hardhat/ts/minimal/hardhat.config.ts | 8 + .../default/hardhat/ts/minimal/package.json | 10 + .../default/hardhat/ts/minimal/tsconfig.json | 13 + .../hardhat/ts/mocha-ethers/.gitignore | 20 + .../default/hardhat/ts/mocha-ethers/README.md | 59 + .../ts/mocha-ethers/contracts/Diamond.sol | 18 + .../contracts/facets/CounterFacet.sol | 33 + .../contracts/tests/CounterFacet.t.sol | 28 + .../hardhat/ts/mocha-ethers/hardhat.config.ts | 39 + .../mocha-ethers/ignition/modules/Counter.ts | 15 + .../hardhat/ts/mocha-ethers/package.json | 20 + .../ts/mocha-ethers/scripts/send-op-tx.ts | 23 + .../hardhat/ts/mocha-ethers/test/Counter.ts | 24 + .../hardhat/ts/mocha-ethers/tsconfig.json | 13 + .../hardhat/ts/node-runner-viem/.gitignore | 20 + .../hardhat/ts/node-runner-viem/README.md | 59 + .../ts/node-runner-viem/contracts/Diamond.sol | 18 + .../contracts/facets/CounterFacet.sol | 33 + .../contracts/tests/CounterFacet.t.sol | 36 + .../ts/node-runner-viem/hardhat.config.ts | 39 + .../ignition/modules/Counter.ts | 15 + .../hardhat/ts/node-runner-viem/package.json | 14 + .../ts/node-runner-viem/scripts/send-op-tx.ts | 32 + .../ts/node-runner-viem/test/Counter.ts | 25 + .../hardhat/ts/node-runner-viem/tsconfig.json | 13 + cli/src/templates/default/template.json | 14 + cli/src/utils/composeAsciiHeader.js | 13 + cli/src/utils/errors.js | 25 + cli/src/utils/exec.js | 24 + cli/src/utils/helpText.js | 29 + cli/src/utils/logger.js | 23 + cli/src/utils/prompts/initUtils.js | 29 + .../fixtures/template-variants.snapshot.json | 8 + cli/test/integration/cliEntry.test.js | 35 + cli/test/integration/scaffoldVariants.test.js | 147 + cli/test/unit/errors.test.js | 71 + cli/test/unit/fileManager.test.js | 71 + cli/test/unit/initOptions.test.js | 34 + cli/test/unit/initPrompts.test.js | 49 + cli/test/unit/packageOrderer.test.js | 30 + cli/test/unit/templateLoader.test.js | 59 + cli/test/unit/templateSnapshot.test.js | 18 + cli/test/unit/tokenReplace.test.js | 26 + cli/test/unit/validateTemplatesConfig.test.js | 19 + cli/test/unit/versionCommand.test.js | 18 + 83 files changed, 8679 insertions(+) create mode 100644 cli/.gitignore create mode 100644 cli/.gitmodules create mode 100644 cli/.npmignore create mode 100644 cli/CHANGELOG.md create mode 100644 cli/LICENSE create mode 100644 cli/README.md create mode 100644 cli/eslint.config.js create mode 100755 cli/index.js create mode 100644 cli/package-lock.json create mode 100644 cli/package.json create mode 100644 cli/scripts/generate-templates-config.js create mode 100644 cli/src/commands/init.js create mode 100644 cli/src/commands/listTemplates.js create mode 100644 cli/src/commands/update.js create mode 100644 cli/src/commands/version.js create mode 100644 cli/src/config/constants.js create mode 100644 cli/src/config/templates.json create mode 100644 cli/src/config/validateTemplatesConfig.js create mode 100644 cli/src/prompts/initPrompts.js create mode 100644 cli/src/scaffold/frameworks/foundry.js create mode 100644 cli/src/scaffold/frameworks/hardhat.js create mode 100644 cli/src/scaffold/scaffold.js create mode 100644 cli/src/scaffold/utils/fileManager.js create mode 100644 cli/src/scaffold/utils/packageOrderer.js create mode 100644 cli/src/scaffold/utils/templateLoader.js create mode 100644 cli/src/scaffold/utils/tokenReplace.js create mode 100644 cli/src/templates/default/foundry/.gitignore create mode 100644 cli/src/templates/default/foundry/README.md create mode 100644 cli/src/templates/default/foundry/foundry.toml create mode 100644 cli/src/templates/default/foundry/remappings.txt create mode 100644 cli/src/templates/default/foundry/script/Deploy.s.sol create mode 100644 cli/src/templates/default/foundry/src/Diamond.sol create mode 100644 cli/src/templates/default/foundry/src/facets/CounterFacet.sol create mode 100644 cli/src/templates/default/foundry/test/CounterFacet.t.sol create mode 100644 cli/src/templates/default/hardhat/ts/minimal/.gitignore create mode 100644 cli/src/templates/default/hardhat/ts/minimal/README.md create mode 100644 cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol create mode 100644 cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol create mode 100644 cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts create mode 100644 cli/src/templates/default/hardhat/ts/minimal/package.json create mode 100644 cli/src/templates/default/hardhat/ts/minimal/tsconfig.json create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/README.md create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/package.json create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts create mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/README.md create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/package.json create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts create mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json create mode 100644 cli/src/templates/default/template.json create mode 100644 cli/src/utils/composeAsciiHeader.js create mode 100644 cli/src/utils/errors.js create mode 100644 cli/src/utils/exec.js create mode 100644 cli/src/utils/helpText.js create mode 100644 cli/src/utils/logger.js create mode 100644 cli/src/utils/prompts/initUtils.js create mode 100644 cli/test/fixtures/template-variants.snapshot.json create mode 100644 cli/test/integration/cliEntry.test.js create mode 100644 cli/test/integration/scaffoldVariants.test.js create mode 100644 cli/test/unit/errors.test.js create mode 100644 cli/test/unit/fileManager.test.js create mode 100644 cli/test/unit/initOptions.test.js create mode 100644 cli/test/unit/initPrompts.test.js create mode 100644 cli/test/unit/packageOrderer.test.js create mode 100644 cli/test/unit/templateLoader.test.js create mode 100644 cli/test/unit/templateSnapshot.test.js create mode 100644 cli/test/unit/tokenReplace.test.js create mode 100644 cli/test/unit/validateTemplatesConfig.test.js create mode 100644 cli/test/unit/versionCommand.test.js diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 00000000..3a2c4c75 --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +coverage/ +dist/ +tmp/ +.env +.env.local + +docs/ \ No newline at end of file diff --git a/cli/.gitmodules b/cli/.gitmodules new file mode 100644 index 00000000..e5545047 --- /dev/null +++ b/cli/.gitmodules @@ -0,0 +1,6 @@ +[submodule "src/templates/default/foundry/lib/forge-std"] + path = src/templates/default/foundry/lib/forge-std + url = https://github.com/foundry-rs/forge-std.git +[submodule "src/templates/default/foundry/lib/Compose"] + path = src/templates/default/foundry/lib/Compose + url = https://github.com/Perfect-Abstractions/Compose.git diff --git a/cli/.npmignore b/cli/.npmignore new file mode 100644 index 00000000..8267d94b --- /dev/null +++ b/cli/.npmignore @@ -0,0 +1,7 @@ +node_modules/ +test/ +.github/ +.cursor/ +.tmp/ +lib/ +src/templates/**/foundry/lib/ diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md new file mode 100644 index 00000000..a67c6f5d --- /dev/null +++ b/cli/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## 0.1.0 + +- Initial Compose CLI foundation. +- Added config-driven template registry with Foundry/Hardhat variants. +- Added scaffold engine, local facet source, and registry-mode stub. +- Added unit/integration tests, lint config, CI workflow, and release documentation. diff --git a/cli/LICENSE b/cli/LICENSE new file mode 100644 index 00000000..f50fe699 --- /dev/null +++ b/cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 M.N + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 00000000..3f5c0dc9 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,101 @@ +# Compose CLI + +`@perfect-abstractions/compose-cli` scaffolds diamond-based projects using the Compose Library. +Supports both Foundry and Hardhat. + +## Install + +```bash +npm install -g @perfect-abstractions/compose-cli +``` + +Requires Node.js >= 18. + +## Usage + +```bash +compose init [options] +compose templates +compose --version | -v +compose --help | -h +compose update +``` + +### Options + +- `--name `: directory / package name for the new project. +- `--template `: template to use (see Template registry below). +- `--framework `: target framework. +- `--language `: source language (Hardhat only; defaults to `typescript` when omitted). +- `--install-deps` / `--no-install-deps`: whether to install npm dependencies for Hardhat templates (defaults to `true` unless disabled or using `--yes` with an explicit value). +- `--yes`: non-interactive mode. Skips prompts and fills missing values with sensible defaults. +- `--help`: print CLI help text. + +When `--yes` is not provided, `compose init` will prompt for any values you omit. + +### Non-interactive examples + +```bash +# Foundry default template +compose init --name my-foundry-app --template default --framework foundry --yes + +# Hardhat minimal TypeScript template, skip dependency install +compose init --name my-hardhat-minimal \ + --template default \ + --framework hardhat \ + --language typescript \ + --install-deps=false \ + --yes + +# Hardhat mocha-ethers TypeScript template +compose init --name my-hardhat-mocha-ethers \ + --template default \ + --framework hardhat \ + --language typescript \ + --yes +``` + + +`compose templates` prints this information in a CLI-friendly format. + +## Notes on `@perfect-abstractions/compose` + +Hardhat scaffolds inject `@perfect-abstractions/compose` as the dependency name. The current package isn't published yet. + + +## Development + +From the `cli` directory: + +```bash +npm install +npm run build:templates +npm run check +``` + +To build or test the Foundry template (or any template that uses `lib/` submodules), init libs once: + +```bash +npm run prepare:lib +``` + +Then from a template directory, for example `src/templates/default/foundry`: + +```bash +forge build +forge test +``` + +New templates that need `forge-std` or Compose can add the same submodules under their own `lib/`; `prepare:lib` inits all submodules repo-wide. + +### Template registry generation + +The template registry at `src/config/templates.json` is generated from per-template manifests under `src/templates/**/template.json`. + +- To regenerate the registry after changing templates: + +```bash +npm run build:templates +``` + +The CLI loads the generated `templates.json` at runtime; editing `template.json` files alone is not enough unless you rebuild the registry. diff --git a/cli/eslint.config.js b/cli/eslint.config.js new file mode 100644 index 00000000..95840019 --- /dev/null +++ b/cli/eslint.config.js @@ -0,0 +1,25 @@ +const js = require("@eslint/js"); + +module.exports = [ + { + ignores: ["node_modules/**", "src/templates/**"], + }, + js.configs.recommended, + { + files: ["**/*.js"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "script", + globals: { + console: "readonly", + process: "readonly", + __dirname: "readonly", + module: "readonly", + require: "readonly", + }, + }, + rules: { + "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + }, + }, +]; diff --git a/cli/index.js b/cli/index.js new file mode 100755 index 00000000..ca16455d --- /dev/null +++ b/cli/index.js @@ -0,0 +1,56 @@ +#!/usr/bin/env node + +const minimist = require("minimist"); +const pkg = require("./package.json"); +const { logger } = require("./src/utils/logger"); +const { exitWithError } = require("./src/utils/errors"); +const { runInitCommand } = require("./src/commands/init"); +const { runVersionCommand } = require("./src/commands/version"); +const { runUpdateCommand } = require("./src/commands/update"); +const { runListTemplatesCommand } = require("./src/commands/listTemplates"); +const { HELP_TEXT } = require("./src/utils/helpText"); + +async function main() { + const argv = minimist(process.argv.slice(2), { + alias: { + v: "version", + h: "help", + n: "name", + }, + boolean: ["version", "help", "yes"], + string: ["name", "template", "framework", "language"], + }); + + const [command = ""] = argv._; + + if (argv.version) { + runVersionCommand(pkg.version); + return; + } + + if (argv.help || !command) { + logger.plain(HELP_TEXT.trim()); + return; + } + + if (command === "init") { + await runInitCommand(argv); + return; + } + + if (command === "update") { + await runUpdateCommand(pkg.name); + return; + } + + if (command === "templates") { + await runListTemplatesCommand(); + return; + } + + throw new Error(`Unknown command: ${command}. Run 'compose --help' for available commands.`); +} + +main().catch((error) => { + exitWithError(error); +}); diff --git a/cli/package-lock.json b/cli/package-lock.json new file mode 100644 index 00000000..2e53b4e5 --- /dev/null +++ b/cli/package-lock.json @@ -0,0 +1,5937 @@ +{ + "name": "@perfect-abstractions/compose-cli", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@perfect-abstractions/compose-cli", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.3.3", + "inquirer": "^13.3.0", + "minimist": "^1.2.8", + "picocolors": "^1.1.1" + }, + "bin": { + "compose": "index.js" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@nomicfoundation/hardhat-ethers": "^4.0.5", + "@nomicfoundation/hardhat-ignition": "^3.0.8", + "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.3", + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2", + "@types/chai": "^5.2.3", + "@types/chai-as-promised": "^8.0.2", + "@types/mocha": "^10.0.10", + "@types/node": "^22.19.13", + "chai": "^6.2.2", + "eslint": "^10.0.2", + "ethers": "^6.16.0", + "forge-std": "github:foundry-rs/forge-std#v1.9.4", + "hardhat": "^3.1.10", + "mocha": "^11.7.5", + "typescript": "~5.8.0", + "viem": "^2.47.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@actions/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", + "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/exec": "^1.1.1", + "@actions/http-client": "^2.0.1" + } + }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.2.tgz", + "integrity": "sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.2", + "debug": "^4.3.1", + "minimatch": "^10.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz", + "integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", + "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.2.tgz", + "integrity": "sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz", + "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", + "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", + "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", + "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", + "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/rlp": "^5.8.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", + "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", + "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", + "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", + "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", + "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@inquirer/ansi": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.3.tgz", + "integrity": "sha512-g44zhR3NIKVs0zUesa4iMzExmZpLUdTLRMCStqX3GE5NT6VkPcxQGJ+uC8tDgBUC/vB1rUhUd55cOf++4NZcmw==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.1.0.tgz", + "integrity": "sha512-/HjF1LN0a1h4/OFsbGKHNDtWICFU/dqXCdym719HFTyJo9IG7Otr+ziGWc9S0iQuohRZllh+WprSgd5UW5Fw0g==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.5", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.8.tgz", + "integrity": "sha512-Di6dgmiZ9xCSUxWUReWTqDtbhXCuG2MQm2xmgSAIruzQzBqNf49b8E07/vbCYY506kDe8BiwJbegXweG8M1klw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.5", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.1.5.tgz", + "integrity": "sha512-QQPAX+lka8GyLcZ7u7Nb1h6q72iZ/oy0blilC3IB2nSt1Qqxp7akt94Jqhi/DzARuN3Eo9QwJRvtl4tmVe4T5A==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.0.8.tgz", + "integrity": "sha512-sLcpbb9B3XqUEGrj1N66KwhDhEckzZ4nI/W6SvLXyBX8Wic3LDLENlWRvkOGpCPoserabe+MxQkpiMoI8irvyA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.5", + "@inquirer/external-editor": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.8.tgz", + "integrity": "sha512-QieW3F1prNw3j+hxO7/NKkG1pk3oz7pOB6+5Upwu3OIwADfPX0oZVppsqlL+Vl/uBHHDSOBY0BirLctLnXwGGg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.5", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-2.0.3.tgz", + "integrity": "sha512-LgyI7Agbda74/cL5MvA88iDpvdXI2KuMBCGRkbCl2Dg1vzHeOgs+s0SDcXV7b+WZJrv2+ERpWSM65Fpi9VfY3w==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.3.tgz", + "integrity": "sha512-y09iGt3JKoOCBQ3w4YrSJdokcD8ciSlMIWsD+auPu+OZpfxLuyz+gICAQ6GCBOmJJt4KEQGHuZSVff2jiNOy7g==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + } + }, + "node_modules/@inquirer/input": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.8.tgz", + "integrity": "sha512-p0IJslw0AmedLEkOU+yrEX3Aj2RTpQq7ZOf8nc1DIhjzaxRWrrgeuE5Kyh39fVRgtcACaMXx/9WNo8+GjgBOfw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.5", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.8.tgz", + "integrity": "sha512-uGLiQah9A0F9UIvJBX52m0CnqtLaym0WpT9V4YZrjZ+YRDKZdwwoEPz06N6w8ChE2lrnsdyhY9sL+Y690Kh9gQ==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.5", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.8.tgz", + "integrity": "sha512-zt1sF4lYLdvPqvmvHdmjOzuUUjuCQ897pdUCO8RbXMUDKXJTTyOQgtn23le+jwcb+MpHl3VAFvzIdxRAf6aPlA==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.5", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.3.0.tgz", + "integrity": "sha512-JAj66kjdH/F1+B7LCigjARbwstt3SNUOSzMdjpsvwJmzunK88gJeXmcm95L9nw1KynvFVuY4SzXh/3Y0lvtgSg==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^5.1.0", + "@inquirer/confirm": "^6.0.8", + "@inquirer/editor": "^5.0.8", + "@inquirer/expand": "^5.0.8", + "@inquirer/input": "^5.0.8", + "@inquirer/number": "^4.0.8", + "@inquirer/password": "^5.0.8", + "@inquirer/rawlist": "^5.2.4", + "@inquirer/search": "^4.1.4", + "@inquirer/select": "^5.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.2.4.tgz", + "integrity": "sha512-fTuJ5Cq9W286isLxwj6GGyfTjx1Zdk4qppVEPexFuA6yioCCXS4V1zfKroQqw7QdbDPN73xs2DiIAlo55+kBqg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.5", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.1.4.tgz", + "integrity": "sha512-9yPTxq7LPmYjrGn3DRuaPuPbmC6u3fiWcsE9ggfLcdgO/ICHYgxq7mEy1yJ39brVvgXhtOtvDVjDh9slJxE4LQ==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.5", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.1.0.tgz", + "integrity": "sha512-OyYbKnchS1u+zRe14LpYrN8S0wH1vD0p2yKISvSsJdH2TpI87fh4eZdWnpdbrGauCRWDph3NwxRmM4Pcm/hx1Q==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.5", + "@inquirer/figures": "^2.0.3", + "@inquirer/type": "^4.0.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.3.tgz", + "integrity": "sha512-cKZN7qcXOpj1h+1eTTcGDVLaBIHNMT1Rz9JqJP5MnEJ0JhgVWllx7H/tahUp5YEK1qaByH2Itb8wLG/iScD5kw==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", + "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", + "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/curves/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/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0-next.24.tgz", + "integrity": "sha512-/NwB9yX7uBs/FIJKHBZo2hVhP7g3v6LbE21JvTLvshgb+XscyaRRUmzB//ankxLGJ1TehtXAf/Qh/a19vgpiig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.24", + "@nomicfoundation/edr-darwin-x64": "0.12.0-next.24", + "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.24", + "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.24", + "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.24", + "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.24", + "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.24" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0-next.24.tgz", + "integrity": "sha512-lYcD9IM52G0hk/3Sso2Rpdpyfafy3aHH0GsSy/FVog9UrEkmmU14AmccE18/zTL+UyV0yzYMDOmh6y83SD/lbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0-next.24.tgz", + "integrity": "sha512-cHDJZlPDpDXJXxQDVM0TGzEuNvV3wW94gipEdjNxZHeC9T2/NU/5GUoQajMJgvCZ6PWDlRMwIBRtM1jC/ny5DA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0-next.24.tgz", + "integrity": "sha512-G/iln4W79CR9f68+crBZM1kBdmmK3IbQCD4b5u+iqby+H5BOLSPQmjeW9UREK5WSecnv7Oxr/ZTHHRq/w9pUPA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0-next.24.tgz", + "integrity": "sha512-wt6UuOutufL3UTSyMiwPOyfRly3uQEFHASXqLsNjgp4qBrm0s+kkyaYpAe8h53lGzZmXIDOAbO0P/fwxnLCnWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0-next.24.tgz", + "integrity": "sha512-mHgkUSynINTnnIvZuZymJ4dMqjemGjdrzQ87rP5/SQQGRQVV82uDomSEglp9btSmbBWfPj4r4tWsV+a3844W0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0-next.24.tgz", + "integrity": "sha512-E0XNSlPc8Hx5Nhowe5VIvAqVeT+1VUWSRqG0cZtYcpUgJZxTp8p03ojPtbyfjL4T+78GfnpmzkkLhB6S2jZ1FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.12.0-next.24", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0-next.24.tgz", + "integrity": "sha512-PbtY2zWc4k8HK4gVnVbPohJnfrICboo6J91vxTlhnPKCWGvfGbsqLfDUAp91ExHHY+80qRfQnwaLbhJiIqLFGw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/hardhat-errors": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-errors/-/hardhat-errors-3.0.7.tgz", + "integrity": "sha512-l4RrzTfJ/WO0B9Te6i9161+pRbCSFXILanmHmgRfS4Bb4pDOjs+0eQf2I2cQrnqcJ6O/bxLvChPTQuad97dmQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-utils": "^4.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-ethers": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-4.0.5.tgz", + "integrity": "sha512-DFTpsg6MBV/JNv8Rd0M/C70Wqk3giYSAYCrBu3PeerX1eNd4wuz5kUlsX4yVoNOPpM6Lva9z+30JRDEuFEt0bQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "debug": "^4.3.2", + "ethereum-cryptography": "^2.2.1", + "ethers": "^6.14.0" + }, + "peerDependencies": { + "hardhat": "^3.0.7" + } + }, + "node_modules/@nomicfoundation/hardhat-ethers-chai-matchers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers-chai-matchers/-/hardhat-ethers-chai-matchers-3.0.3.tgz", + "integrity": "sha512-X02s5neeaBsHiXYcPsXeqbHJ2bRytsBmQRkh0JyO6AYbkIY4pM9g+M4wnCUMWPnh1wQnLyT3Iqx+g8nJ8Ont6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@types/chai-as-promised": "^8.0.1", + "chai-as-promised": "^8.0.0", + "deep-eql": "^5.0.1" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^4.0.0", + "chai": ">=5.1.2 <7", + "ethers": "^6.14.0", + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-ignition": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-3.0.8.tgz", + "integrity": "sha512-hLDQjkUIZ9tHrgXRsqn7ZFofWj6gf7SH6ImjetOZFy25uatKgnz78doCzrGs1gUCBnpKOP9Ck/5a88cK9xBESw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/ignition-core": "^3.0.8", + "@nomicfoundation/ignition-ui": "^3.0.8", + "chalk": "^5.3.0", + "debug": "^4.3.2", + "json5": "^2.2.3", + "prompts": "^2.4.2" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-verify": "^3.0.0", + "hardhat": "^3.1.5" + } + }, + "node_modules/@nomicfoundation/hardhat-ignition-ethers": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-3.0.8.tgz", + "integrity": "sha512-W+FWhKioZA7e4+Yt+jeLcbqnv9Xf/yS8PZPDM9mw+VO+IPs1WWL9tMzhw2G/CaIvdOc8FD6eQ/k+DU3Avc0Zaw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^4.0.0", + "@nomicfoundation/hardhat-ignition": "^3.0.7", + "@nomicfoundation/hardhat-verify": "^3.0.0", + "@nomicfoundation/ignition-core": "^3.0.7", + "ethers": "^6.14.0", + "hardhat": "^3.1.5" + } + }, + "node_modules/@nomicfoundation/hardhat-ignition-viem": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-viem/-/hardhat-ignition-viem-3.0.8.tgz", + "integrity": "sha512-M3RMIwW1htZ/i3P14ZLFgzIg91qlh7OHv3iD7SDZbtjcsdgrGSsf5hpZ7xI8uR8a0/7WVAc7EAQouoW1pBAcvw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ignition": "^3.0.7", + "@nomicfoundation/hardhat-verify": "^3.0.0", + "@nomicfoundation/hardhat-viem": "^3.0.2", + "@nomicfoundation/ignition-core": "^3.0.7", + "hardhat": "^3.1.5", + "viem": "^2.43.0" + } + }, + "node_modules/@nomicfoundation/hardhat-keystore": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-keystore/-/hardhat-keystore-3.0.5.tgz", + "integrity": "sha512-jxihFx7r9ekcGmxRVbeDxFJcE3P9cmOHObKxX4ORyBR4b/AKiaqKiktirvsF5MXKJSuQbbp/+wmaqfQDB3LyeA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/hashes": "1.7.1", + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/hardhat-zod-utils": "^3.0.2", + "chalk": "^5.3.0", + "debug": "^4.3.2", + "zod": "^3.23.8" + }, + "peerDependencies": { + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-mocha": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-mocha/-/hardhat-mocha-3.0.11.tgz", + "integrity": "sha512-02nuOnpsDeBzwgzf89M5uMkC74xUfuENOmZDgxE5LbQ7Ftq9K+mmHP8okCr6+m+i6xUgGLLAY7CZKeaAZKtIoQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/hardhat-zod-utils": "^3.0.2", + "chalk": "^5.3.0", + "debug": "^4.3.2", + "tsx": "^4.19.3", + "zod": "^3.23.8" + }, + "peerDependencies": { + "hardhat": "^3.0.12", + "mocha": "^11.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-3.0.4.tgz", + "integrity": "sha512-WTNISH3/ZkcSDNp//dML18zgV4z3ooeibNcxvv4soCh0AmI8I+2kKaTlKN/Ou1mhKOdiLUbCZCbKNz9LGK3uQw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0" + }, + "peerDependencies": { + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-node-test-reporter": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-node-test-reporter/-/hardhat-node-test-reporter-3.0.2.tgz", + "integrity": "sha512-lbbOVOVxHY+x3olztf8m19nuxpkx/6zN8dmGlbb1CA0V3QvN8EyQWl8O6xtxmTQhLTPKUGwA2r02ikE5Qa02dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/core": "^1.10.1", + "chalk": "^5.3.0", + "jest-diff": "^29.7.0" + } + }, + "node_modules/@nomicfoundation/hardhat-node-test-runner": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-node-test-runner/-/hardhat-node-test-runner-3.0.9.tgz", + "integrity": "sha512-5XzmVIfBhwTZG1IR0Trq/ReJn8n4x6W8SJElpFryklK3OaRpeHMu8TQ8JaiMcrtfNXlg7Byk5NfB486593Ue3g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-node-test-reporter": "^3.0.2", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/hardhat-zod-utils": "^3.0.2", + "tsx": "^4.19.3", + "zod": "^3.23.8" + }, + "peerDependencies": { + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-toolbox-mocha-ethers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox-mocha-ethers/-/hardhat-toolbox-mocha-ethers-3.0.3.tgz", + "integrity": "sha512-74iTn+D5Mwm8czVbVLG/RB5Ec/hSoxsmt4Wvn4O6mtRIL5jRlLoeG8vc6TKDXEpk1MWL2r5TqCrh7F5N/fk01w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^4.0.0", + "@nomicfoundation/hardhat-ethers-chai-matchers": "^3.0.0", + "@nomicfoundation/hardhat-ignition": "^3.0.0", + "@nomicfoundation/hardhat-ignition-ethers": "^3.0.0", + "@nomicfoundation/hardhat-keystore": "^3.0.0", + "@nomicfoundation/hardhat-mocha": "^3.0.0", + "@nomicfoundation/hardhat-network-helpers": "^3.0.0", + "@nomicfoundation/hardhat-typechain": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^3.0.0", + "@nomicfoundation/ignition-core": "^3.0.0", + "chai": ">=5.1.2 <7", + "ethers": "^6.14.0", + "hardhat": "^3.0.0", + "mocha": "^11.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-toolbox-viem": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox-viem/-/hardhat-toolbox-viem-5.0.2.tgz", + "integrity": "sha512-b0hMvronSuryRiQrmB6DxFbpUFB3dMpIVpqCE/zYxG31IakEiuBG1Z/ky5BERVJJSD0nkCAH4wF33GS4PS6UZw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@nomicfoundation/hardhat-ignition": "^3.0.7", + "@nomicfoundation/hardhat-ignition-viem": "^3.0.7", + "@nomicfoundation/hardhat-keystore": "^3.0.0", + "@nomicfoundation/hardhat-network-helpers": "^3.0.0", + "@nomicfoundation/hardhat-node-test-runner": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^3.0.0", + "@nomicfoundation/hardhat-viem": "^3.0.2", + "@nomicfoundation/hardhat-viem-assertions": "^3.0.5", + "@nomicfoundation/ignition-core": "^3.0.7", + "hardhat": "^3.0.0", + "viem": "^2.43.0" + } + }, + "node_modules/@nomicfoundation/hardhat-typechain": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-typechain/-/hardhat-typechain-3.0.3.tgz", + "integrity": "sha512-RjaL94yMpGpKgQDIjD+B1druNboFWWlq609b7bmKOexsCIrxpMQ0+zY7VNvgjv3g9L0a+dIOxalm37/m60rsng==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/hardhat-zod-utils": "^3.0.2", + "@typechain/ethers-v6": "^0.5.0", + "debug": "^4.3.2", + "typechain": "^8.3.1", + "zod": "^3.23.8" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^4.0.0", + "ethers": "^6.14.0", + "hardhat": "^3.1.6" + } + }, + "node_modules/@nomicfoundation/hardhat-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-4.0.0.tgz", + "integrity": "sha512-Deu4od7flcM89K+SEAxmOyn7FFWGiEILrGjoxYl/Gus0tctgpLNaK3M4LIjrJ25ci8LBjGVe3i28XZA4+QGQHQ==", + "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-utils/node_modules/undici": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", + "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/@nomicfoundation/hardhat-vendored": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-vendored/-/hardhat-vendored-3.0.1.tgz", + "integrity": "sha512-jBOAqmEAMJ8zdfiQmTLV+c0IaSyySqkDSJ9spTy8Ts/m/mO8w364TClyfn+p4ZpxBjyX4LMa3NfC402hoDtwCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nomicfoundation/hardhat-verify": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-3.0.11.tgz", + "integrity": "sha512-AcEK5azLRnTyzjvkPKMN4RSCwXHtBRipIdJmN7/GTBfducik/3plG7m8TxNumWcERfCkh9+viLWXddpReocxZw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.8.0", + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/hardhat-zod-utils": "^3.0.2", + "cbor2": "^1.9.0", + "chalk": "^5.3.0", + "debug": "^4.3.2", + "semver": "^7.6.3", + "zod": "^3.23.8" + }, + "peerDependencies": { + "hardhat": "^3.1.6" + } + }, + "node_modules/@nomicfoundation/hardhat-viem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-viem/-/hardhat-viem-3.0.3.tgz", + "integrity": "sha512-UgI4QcEGP0Vy/NT3BzycSX3+rut1Avzym4k7fogki+pUz8jAxyoW0s2SsPY5tY/Cq6bTZXjlDQTt+mY5E52vgg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0" + }, + "peerDependencies": { + "hardhat": "^3.0.0", + "viem": "^2.43.0" + } + }, + "node_modules/@nomicfoundation/hardhat-viem-assertions": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-viem-assertions/-/hardhat-viem-assertions-3.0.6.tgz", + "integrity": "sha512-9lu/MeC0j/tEXE3cXbqo4a5mHxhgTlCxttg9Iw29xCxYV3C2Bp5bs774zNVRONE5MfnkvLFylWcH4FWvruQGAw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-viem": "^3.0.2", + "hardhat": "^3.0.0", + "viem": "^2.43.0" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-zod-utils/-/hardhat-zod-utils-3.0.2.tgz", + "integrity": "sha512-EtMIhi7jtpeQYd+pRQBNlxthi8OPVr/t32yn+VHHp6nwS5wgXLh6/KpvFZfJj5mBAUbOtogB7YQ4n5fpOeuggA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@nomicfoundation/ignition-core": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-3.0.8.tgz", + "integrity": "sha512-IURCj/GJS7e8FgBeWe/pdpI3yQKccttUGkUZJLkgXaEdeENnXjnG8kUXIIgURGqB6NQuk9TXdI5DwAtrzkenCg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/address": "5.6.1", + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/solidity-analyzer": "^0.1.1", + "cbor2": "^1.9.0", + "debug": "^4.3.2", + "ethers": "^6.14.0", + "immer": "10.0.2", + "lodash-es": "4.17.21", + "ndjson": "2.0.0" + } + }, + "node_modules/@nomicfoundation/ignition-core/node_modules/@ethersproject/address": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.1.tgz", + "integrity": "sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/rlp": "^5.6.1" + } + }, + "node_modules/@nomicfoundation/ignition-ui": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-3.0.8.tgz", + "integrity": "sha512-tJlMcKhOi6hlbw/fn8sif+7HLR9gtrwZWSW8muVF2Gy92v8xda09mxwoVkB8ACEL6mA5PQTaruvNIq4XCJALtQ==", + "dev": true + }, + "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/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "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/bip32/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/@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/@scure/bip39/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/@sentry/core": { + "version": "9.47.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.47.1.tgz", + "integrity": "sha512-KX62+qIt4xgy8eHKHiikfhz2p5fOciXd0Cl+dNzhgPFq8klq4MGMNaf148GB3M/vBqP4nw/eFvRMAayFCgdRQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true, + "license": "MIT" + }, + "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/@typechain/ethers-v6": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz", + "integrity": "sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "ethers": "6.x", + "typechain": "^8.3.2", + "typescript": ">=4.7.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/chai-as-promised": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-meQ1wDr1K5KRCSvG2lX7n7/5wf70BeptTKst0axGvnN6zqaVpRqegoIbugiAPSqOW9K9aL8gDVrm7a2LXOtn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz", + "integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "license": "MIT" + }, + "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", + "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/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "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/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cbor2": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/cbor2/-/cbor2-1.12.0.tgz", + "integrity": "sha512-3Cco8XQhi27DogSp9Ri6LYNZLi/TBY/JVnDe+mj06NkBjW/ZYOtekaEU4wZ4xcRMNrFkDv8KNtOAqHyDfz3lYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.7" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/chai-as-promised": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-1GadL+sEJVLzDjcawPM4kjfnL+p/9vrxiEUonowKOAzvVg0PixJUdtuDzdkDeQhK3zfOE76GqGkZIQ7/Adcrqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "check-error": "^2.1.1" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 7" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "license": "MIT" + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "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/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/command-line-usage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/command-line-usage/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/command-line-usage/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "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.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.2.tgz", + "integrity": "sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.2", + "@eslint/config-helpers": "^0.5.2", + "@eslint/core": "^1.1.0", + "@eslint/plugin-kit": "^0.6.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.1", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.1.1", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.1", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.1.tgz", + "integrity": "sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.1.tgz", + "integrity": "sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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/ethereum-cryptography/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/ethers": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", + "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@adraffy/ens-normalize": "1.10.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.17.1" + }, + "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/ethers/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/ethers/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/ethers/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/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz", + "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==", + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", + "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forge-std": { + "version": "1.9.4", + "resolved": "git+ssh://git@github.com/foundry-rs/forge-std.git#1eea5bae12ae557d589f9f0f0edae2faa47cb262", + "dev": true, + "license": "(Apache-2.0 OR MIT)" + }, + "node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "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/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/hardhat": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-3.1.10.tgz", + "integrity": "sha512-+J3LmO5j3r8bYRIiImaTT6WtT0EKcR0nfFxWq/bokAKZq7GKYf6ErKSrOuH+gFIqo+CfnrkxcgbPY20P5vuuSQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/edr": "0.12.0-next.24", + "@nomicfoundation/hardhat-errors": "^3.0.7", + "@nomicfoundation/hardhat-utils": "^4.0.0", + "@nomicfoundation/hardhat-vendored": "^3.0.1", + "@nomicfoundation/hardhat-zod-utils": "^3.0.2", + "@nomicfoundation/solidity-analyzer": "^0.1.1", + "@sentry/core": "^9.4.0", + "adm-zip": "^0.4.16", + "chalk": "^5.3.0", + "chokidar": "^4.0.3", + "debug": "^4.3.2", + "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/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "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/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.2.tgz", + "integrity": "sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/inquirer": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-13.3.0.tgz", + "integrity": "sha512-APTrZe9IhrsshL0u2PgmEMLP3CXDBjZ99xh5dR2+sryOt5R+JGL0KNuaTTT2lW54B9eNQDMutPR05UYTL7Xb1Q==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.5", + "@inquirer/prompts": "^8.3.0", + "@inquirer/type": "^4.0.3", + "mute-stream": "^3.0.0", + "run-async": "^4.0.6", + "rxjs": "^7.8.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "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", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stream-stringify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", + "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=7.10.1" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "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/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ndjson": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", + "integrity": "sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "json-stringify-safe": "^5.0.1", + "minimist": "^1.2.5", + "readable-stream": "^3.6.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "ndjson": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ox": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.0.tgz", + "integrity": "sha512-WLOB7IKnmI3Ol6RAqY7CJdZKl8QaI44LN91OGF1061YIeN6bL5IsFcdp7+oQShRyamE/8fW/CBRWhJAOzI35Dw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "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/@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/ox/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/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", + "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", + "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", + "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", + "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", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "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/run-async": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true, + "license": "WTFPL OR MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "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/strip-ansi-cjs": { + "name": "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/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/ts-command-line-args": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", + "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "dev": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-command-line-args/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typechain": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", + "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/typechain/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/typechain/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/typechain/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/typechain/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/viem": { + "version": "2.47.0", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.47.0.tgz", + "integrity": "sha512-jU5e1E1s5E5M1y+YrELDnNar/34U8NXfVcRfxtVETigs2gS1vvW2ngnBoQUGBwLnNr0kNv+NUu4m10OqHByoFw==", + "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.0", + "ws": "8.18.3" + }, + "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", + "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", + "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", + "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", + "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", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "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/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "license": "MIT", + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "license": "MIT", + "peer": true, + "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/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/cli/package.json b/cli/package.json new file mode 100644 index 00000000..5487388a --- /dev/null +++ b/cli/package.json @@ -0,0 +1,70 @@ +{ + "name": "@perfect-abstractions/compose-cli", + "version": "0.1.0", + "description": "CLI to scaffold Compose facet-based diamond projects", + "main": "index.js", + "bin": { + "compose": "./index.js" + }, + "type": "commonjs", + "scripts": { + "lint": "eslint .", + "test": "node --test test/**/*.test.js", + "test:unit": "node --test test/unit", + "test:integration": "node --test test/integration", + "check": "npm run lint && npm run test", + "build:templates": "node scripts/generate-templates-config.js", + "pack:check": "npm pack --dry-run", + "prepublishOnly": "npm run check && npm run pack:check", + "prepare:lib": "git submodule update --init --recursive" + }, + "keywords": [ + "solidity", + "ethereum", + "smart-contracts", + "diamonds", + "ERC-2535", + "ERC-8153", + "facets", + "compose", + "cli" + ], + "author": "Perfect-Abstractions/Compose", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "files": [ + "index.js", + "src/", + "!src/templates/**/lib/", + "docs/", + "README.md", + "LICENSE" + ], + "dependencies": { + "fs-extra": "^11.3.3", + "inquirer": "^13.3.0", + "minimist": "^1.2.8", + "picocolors": "^1.1.1" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@nomicfoundation/hardhat-ethers": "^4.0.5", + "@nomicfoundation/hardhat-ignition": "^3.0.8", + "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.3", + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2", + "@types/chai": "^5.2.3", + "@types/chai-as-promised": "^8.0.2", + "@types/mocha": "^10.0.10", + "@types/node": "^22.19.13", + "chai": "^6.2.2", + "eslint": "^10.0.2", + "ethers": "^6.16.0", + "forge-std": "github:foundry-rs/forge-std#v1.9.4", + "hardhat": "^3.1.10", + "mocha": "^11.7.5", + "typescript": "~5.8.0", + "viem": "^2.47.0" + } +} diff --git a/cli/scripts/generate-templates-config.js b/cli/scripts/generate-templates-config.js new file mode 100644 index 00000000..9f33b8cc --- /dev/null +++ b/cli/scripts/generate-templates-config.js @@ -0,0 +1,143 @@ +/* eslint-disable no-console */ +const fs = require("fs"); +const path = require("path"); +const { validateTemplatesConfig } = require("../src/config/validateTemplatesConfig"); + +const ROOT_DIR = path.resolve(__dirname, ".."); +const TEMPLATES_ROOT = path.join(ROOT_DIR, "src", "templates"); +const OUTPUT_CONFIG_PATH = path.join(ROOT_DIR, "src", "config", "templates.json"); + +function readJsonFile(filePath) { + const content = fs.readFileSync(filePath, "utf8"); + return JSON.parse(content); +} + +function parseVariantId(templateId, variantId) { + const suffix = variantId.startsWith(`${templateId}-`) + ? variantId.slice(templateId.length + 1) + : variantId; + + const [framework, ...rest] = suffix.split("-"); + + return { + framework, + projectType: rest.length > 0 ? rest.join("-") : undefined, + }; +} + +function inferLanguageFromPath(relativePath) { + if (relativePath.includes("/ts/")) { + return "typescript"; + } + + if (relativePath.includes("/js/")) { + return "javascript"; + } + + return undefined; +} + +function buildVariantPath(templateId, framework, projectType, overridePath) { + if (overridePath) { + return overridePath; + } + + if (framework === "foundry") { + return `templates/${templateId}/${framework}`; + } + + if (!projectType) { + return `templates/${templateId}/${framework}`; + } + + return `templates/${templateId}/${framework}/ts/${projectType}`; +} + +function loadTemplateManifests() { + const entries = fs.readdirSync(TEMPLATES_ROOT, { withFileTypes: true }); + const templates = []; + + entries.forEach((entry) => { + if (!entry.isDirectory()) { + return; + } + + const templateDir = path.join(TEMPLATES_ROOT, entry.name); + const manifestPath = path.join(templateDir, "template.json"); + + if (!fs.existsSync(manifestPath)) { + return; + } + + const manifest = readJsonFile(manifestPath); + templates.push(manifest); + }); + + return templates; +} + +function buildTemplatesConfig() { + const templateManifests = loadTemplateManifests(); + + const templates = templateManifests.map((manifest) => { + const templateId = manifest.id; + + const variants = (manifest.variants || []).map((variantId) => { + const { framework, projectType } = parseVariantId(templateId, variantId); + + const pathValue = buildVariantPath( + templateId, + framework, + projectType, + ); + + const language = inferLanguageFromPath(pathValue); + + return { + id: variantId, + framework, + path: pathValue, + ...(language ? { language } : {}), + ...(projectType ? { projectType } : {}), + }; + }); + + return { + id: templateId, + name: manifest.name, + description: manifest.description, + variants, + }; + }); + + const config = { + templates, + defaultTemplateId: templateManifests[0] ? templateManifests[0].id : "default", + }; + + validateTemplatesConfig(config); + + return config; +} + +function writeTemplatesConfig(config) { + const json = `${JSON.stringify(config, null, 2)}\n`; + fs.writeFileSync(OUTPUT_CONFIG_PATH, json, "utf8"); +} + +function main() { + try { + const config = buildTemplatesConfig(); + writeTemplatesConfig(config); + console.log(`Generated templates config at ${path.relative(ROOT_DIR, OUTPUT_CONFIG_PATH)}`); + } catch (error) { + console.error("Failed to generate templates config:"); + console.error(error.message || error); + process.exitCode = 1; + } +} + +if (require.main === module) { + main(); +} + diff --git a/cli/src/commands/init.js b/cli/src/commands/init.js new file mode 100644 index 00000000..2bd22662 --- /dev/null +++ b/cli/src/commands/init.js @@ -0,0 +1,148 @@ +const fs = require("fs-extra"); +const path = require("node:path"); +const { askInitPrompts } = require("../prompts/initPrompts"); +const { logger } = require("../utils/logger"); +const { COMPOSE_DOCS_URL, COMPOSE_REPO_URL } = require("../config/constants"); +const { loadTemplateConfig, pickVariant, resolveTemplatePath } = require("../scaffold/utils/templateLoader"); +const { scaffold } = require("../scaffold/scaffold"); +const { COMPOSE_HEADER } = require("../utils/composeAsciiHeader"); + +function normalizeInitOptions(argv) { + const options = { + projectName: argv.name || "", + template: argv.template || "", + framework: argv.framework || "", + language: argv.language, + hardhatProjectType: argv.hardhatProjectType, + installDeps: argv["install-deps"], + yes: Boolean(argv.yes), + }; + + return options; +} + +async function ensureBinaryExists(binaryName) { + const hasPath = process.env.PATH || ""; + const separator = process.platform === "win32" ? ";" : ":"; + const paths = hasPath.split(separator); + const extensions = process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""]; + + for (const currentPath of paths) { + for (const extension of extensions) { + const candidate = path.join(currentPath, `${binaryName}${extension}`); + if (await fs.pathExists(candidate)) { + return true; + } + } + } + + return false; +} + +async function preflightChecks(options) { + if (options.framework === "foundry") { + const forgeExists = await ensureBinaryExists("forge"); + if (!forgeExists) { + throw new Error( + "forge not found in PATH. Please install Foundry and try again.", + ); + } + } + + if (options.framework === "hardhat" && options.installDeps !== false) { + const npmExists = await ensureBinaryExists("npm"); + if (!npmExists) { + throw new Error("npm not found in PATH. Please install Node.js (with npm) and try again."); + } + } +} + +async function collectInitOptions(argv) { + const normalized = normalizeInitOptions(argv); + + if (normalized.yes) { + if (!normalized.projectName) { + normalized.projectName = "my-diamond"; + } + if (typeof normalized.installDeps !== "boolean") { + normalized.installDeps = true; + } + return normalized; + } + + const answers = await askInitPrompts({ + name: normalized.projectName || undefined, + template: normalized.template || undefined, + framework: normalized.framework || undefined, + hardhatProjectType: normalized.hardhatProjectType, + installDeps: normalized.installDeps, + }); + + const framework = answers.framework || normalized.framework; + const language = + normalized.language || (framework === "hardhat" ? "typescript" : normalized.language); + + return { + ...normalized, + projectName: answers.name || normalized.projectName || "my-diamond", + template: answers.template || normalized.template, + framework, + language, + hardhatProjectType: answers.hardhatProjectType || normalized.hardhatProjectType, + installDeps: typeof answers.installDeps === "boolean" ? answers.installDeps : true, + }; +} + +function printInitHeader() { + logger.info(COMPOSE_HEADER); + logger.info("Scaffold your diamond smart contracts project with Compose"); + logger.info(`Explore our library: ${COMPOSE_DOCS_URL}\n`); +} + +async function runInitCommand(argv) { + printInitHeader(); + const initOptions = await collectInitOptions(argv); + await preflightChecks(initOptions); + + const templateConfig = await loadTemplateConfig(); + const selectedVariant = pickVariant(templateConfig, { + template: initOptions.template, + framework: initOptions.framework, + language: initOptions.language, + projectType: initOptions.hardhatProjectType, + }); + + const templatePath = resolveTemplatePath(selectedVariant); + + + const { projectDir, displayName, nextSteps } = await scaffold({ + projectName: initOptions.projectName, + templatePath, + options: { + framework: selectedVariant.framework, + language: selectedVariant.language, + hardhatProjectType: initOptions.hardhatProjectType || selectedVariant.projectType, + installDeps: initOptions.installDeps, + }, + }); + + logger.success(`\nProject "${displayName}" scaffolded in "${projectDir}"`); + logger.plain("Next steps:"); + let stepCount = 1; + if (path.resolve(projectDir) !== process.cwd()) { + logger.plain(`${stepCount}. cd ${displayName}`); + } + for (const step of nextSteps) { + logger.plain(`${stepCount}. ${step}`); + stepCount++; + } + + logger.plain(""); + logger.info("You're all set. We hope you'll Compose something great!\n"); + logger.warn(`If this helped you, please give us a star on GitHub:\n${COMPOSE_REPO_URL}\n`); +} + +module.exports = { + runInitCommand, + normalizeInitOptions, +}; diff --git a/cli/src/commands/listTemplates.js b/cli/src/commands/listTemplates.js new file mode 100644 index 00000000..3a3c175c --- /dev/null +++ b/cli/src/commands/listTemplates.js @@ -0,0 +1,23 @@ +const { loadTemplateConfig } = require("../scaffold/utils/templateLoader"); +const { logger } = require("../utils/logger"); + +async function runListTemplatesCommand() { + const config = await loadTemplateConfig(); + + config.templates.forEach((template) => { + logger.plain(`${template.id} - ${template.name}`); + template.variants.forEach((variant) => { + const meta = [ + variant.framework, + variant.language, + variant.projectType, + ].filter(Boolean).join(", "); + + logger.plain(` - ${variant.id}${meta ? ` (${meta})` : ""}`); + }); + }); +} + +module.exports = { + runListTemplatesCommand, +}; diff --git a/cli/src/commands/update.js b/cli/src/commands/update.js new file mode 100644 index 00000000..623d0ea4 --- /dev/null +++ b/cli/src/commands/update.js @@ -0,0 +1,14 @@ +const { runCommand } = require("../utils/exec"); +const { logger } = require("../utils/logger"); + +async function runUpdateCommand(packageName) { + logger.info("Updating CLI to latest..."); + await runCommand("npm", ["install", "-g", `${packageName}@latest`], { + cwd: process.cwd(), + }); + logger.success("Update complete."); +} + +module.exports = { + runUpdateCommand, +}; diff --git a/cli/src/commands/version.js b/cli/src/commands/version.js new file mode 100644 index 00000000..0e4cd959 --- /dev/null +++ b/cli/src/commands/version.js @@ -0,0 +1,9 @@ +const { logger } = require("../utils/logger"); + +function runVersionCommand(version) { + logger.plain(version); +} + +module.exports = { + runVersionCommand, +}; diff --git a/cli/src/config/constants.js b/cli/src/config/constants.js new file mode 100644 index 00000000..26010f50 --- /dev/null +++ b/cli/src/config/constants.js @@ -0,0 +1,26 @@ +const path = require("node:path"); + +const COMPOSE_REPO_URL = "https://github.com/Perfect-Abstractions/Compose"; +const COMPOSE_DOCS_URL = "https://compose.diamonds/"; + +const COMPOSE_NPM_PACKAGE = "@perfect-abstractions/compose"; +const COMPOSE_NPM_VERSION = "latest"; + +const COMPOSE_FOUNDRY_DEP = "Perfect-Abstractions/Compose"; + +const DEFAULT_TEMPLATE_ID = "default"; +const DEFAULT_FRAMEWORK = "foundry"; + +const TEMPLATE_REGISTRY_PATH = path.join(__dirname, "templates.json"); + +module.exports = { + COMPOSE_REPO_URL, + COMPOSE_DOCS_URL, + COMPOSE_NPM_PACKAGE, + COMPOSE_NPM_VERSION, + COMPOSE_FOUNDRY_DEP, + DEFAULT_TEMPLATE_ID, + DEFAULT_FRAMEWORK, + TEMPLATE_REGISTRY_PATH, +}; + diff --git a/cli/src/config/templates.json b/cli/src/config/templates.json new file mode 100644 index 00000000..05f277f5 --- /dev/null +++ b/cli/src/config/templates.json @@ -0,0 +1,38 @@ +{ + "templates": [ + { + "id": "default", + "name": "Counter", + "description": "Simple diamond with a counter facet", + "variants": [ + { + "id": "default-foundry", + "framework": "foundry", + "path": "templates/default/foundry" + }, + { + "id": "default-hardhat-minimal", + "framework": "hardhat", + "path": "templates/default/hardhat/ts/minimal", + "language": "typescript", + "projectType": "minimal" + }, + { + "id": "default-hardhat-mocha-ethers", + "framework": "hardhat", + "path": "templates/default/hardhat/ts/mocha-ethers", + "language": "typescript", + "projectType": "mocha-ethers" + }, + { + "id": "default-hardhat-node-runner-viem", + "framework": "hardhat", + "path": "templates/default/hardhat/ts/node-runner-viem", + "language": "typescript", + "projectType": "node-runner-viem" + } + ] + } + ], + "defaultTemplateId": "default" +} diff --git a/cli/src/config/validateTemplatesConfig.js b/cli/src/config/validateTemplatesConfig.js new file mode 100644 index 00000000..f155e929 --- /dev/null +++ b/cli/src/config/validateTemplatesConfig.js @@ -0,0 +1,38 @@ +function ensureString(value, keyPath) { + if (typeof value !== "string" || value.trim() === "") { + throw new Error(`Invalid templates config: ${keyPath} must be a non-empty string`); + } +} + +function validateTemplatesConfig(config) { + if (!config || typeof config !== "object") { + throw new Error("Invalid templates config: config root must be an object"); + } + + if (!Array.isArray(config.templates) || config.templates.length === 0) { + throw new Error("Invalid templates config: templates must be a non-empty array"); + } + + config.templates.forEach((template, index) => { + ensureString(template.id, `templates[${index}].id`); + ensureString(template.name, `templates[${index}].name`); + + if (!Array.isArray(template.variants) || template.variants.length === 0) { + throw new Error(`Invalid templates config: templates[${index}].variants must be a non-empty array`); + } + + template.variants.forEach((variant, variantIndex) => { + ensureString(variant.id, `templates[${index}].variants[${variantIndex}].id`); + ensureString(variant.framework, `templates[${index}].variants[${variantIndex}].framework`); + ensureString(variant.path, `templates[${index}].variants[${variantIndex}].path`); + }); + }); + + ensureString(config.defaultTemplateId, "defaultTemplateId"); + + return true; +} + +module.exports = { + validateTemplatesConfig, +}; diff --git a/cli/src/prompts/initPrompts.js b/cli/src/prompts/initPrompts.js new file mode 100644 index 00000000..9f1661a7 --- /dev/null +++ b/cli/src/prompts/initPrompts.js @@ -0,0 +1,68 @@ +const inquirer = require("inquirer").default; +const { getTemplateChoices, validateProjectLocation } = require("../utils/prompts/initUtils"); + +async function askInitPrompts(seed = {}) { + const answers = await inquirer.prompt([ + { + type: "input", + name: "name", + message: 'Where would you like to initialize the project? ("." for current directory) ', + default: seed.name || "my-first-diamond", + when: () => !seed.name, + validate: validateProjectLocation, + }, + { + type: "select", + name: "template", + message: "Choose your diamond template? ", + choices: () => getTemplateChoices(), + when: () => !seed.template, + }, + { + type: "select", + name: "framework", + message: "Choose your framework?", + choices: ["foundry", "hardhat"], + when: () => !seed.framework, + }, + { + type: "select", + name: "hardhatProjectType", + message: "What Hardhat 3 project do you want to create? ", + choices: [ + { + name: "Minimal Hardhat Project", + value: "minimal", + }, + { + name: "TypeScript Hardhat project using Mocha and Ethers.js", + value: "mocha-ethers", + }, + { + name: "TypeScript Hardhat project using Node Test Runner and Viem", + value: "node-runner-viem", + }, + ], + when: (answers) => { + const framework = seed.framework || answers.framework; + return framework === "hardhat" && !seed.hardhatProjectType; + }, + }, + { + type: "confirm", + name: "installDeps", + message: "Install dependencies now? ", + default: true, + when: () => typeof seed.installDeps !== "boolean", + }, + ]); + + return { + ...seed, + ...answers, + }; +} + +module.exports = { + askInitPrompts +}; diff --git a/cli/src/scaffold/frameworks/foundry.js b/cli/src/scaffold/frameworks/foundry.js new file mode 100644 index 00000000..db4c778b --- /dev/null +++ b/cli/src/scaffold/frameworks/foundry.js @@ -0,0 +1,46 @@ +const fs = require("fs-extra"); +const path = require("path"); +const { copyTemplate, getTemplateDisplayName } = require("../utils/fileManager"); +const { runCommand } = require("../../utils/exec"); +const { logger } = require("../../utils/logger"); +const { COMPOSE_FOUNDRY_DEP } = require("../../config/constants"); + +async function scaffoldFoundry(projectName, templatePath, projectDir, options) { + const shouldInstallDeps = Boolean(options.installDeps); + + logger.info(`Scaffolding Foundry project in "${projectDir}"…`); + + await fs.ensureDir(projectDir); + + await runCommand("forge", ["init", "."], { cwd: projectDir }); + + if (shouldInstallDeps) { + logger.info("Installing Compose dependencies with forge…"); + await runCommand("forge", ["install", COMPOSE_FOUNDRY_DEP], { cwd: projectDir }); + } else { + logger.info("Skipping dependency installation... "); + } + + // Remove default Forge starter contracts/scripts/tests for replacement with our template. + await Promise.all([ + fs.remove(path.join(projectDir, "src")), + fs.remove(path.join(projectDir, "test")), + fs.remove(path.join(projectDir, "script")), + ]); + + const templateName = getTemplateDisplayName(templatePath); + logger.info(`Applying template "${templateName}"`); + + await copyTemplate(templatePath, projectDir); + + const nextSteps = shouldInstallDeps + ? ["forge build && forge test"] + : [`forge install ${COMPOSE_FOUNDRY_DEP}`, "forge build && forge test"]; + + return { nextSteps }; +} + +module.exports = { + scaffoldFoundry, +}; + diff --git a/cli/src/scaffold/frameworks/hardhat.js b/cli/src/scaffold/frameworks/hardhat.js new file mode 100644 index 00000000..348387f2 --- /dev/null +++ b/cli/src/scaffold/frameworks/hardhat.js @@ -0,0 +1,50 @@ +const fs = require("fs-extra"); +const path = require("node:path"); +const { copyTemplate, readJson, writeJson } = require("../utils/fileManager"); +const { orderPackageJsonWithDepsBeforeDevDeps } = require("../utils/packageOrderer"); +const { runCommand } = require("../../utils/exec"); +const { logger } = require("../../utils/logger"); +const { COMPOSE_NPM_PACKAGE, COMPOSE_NPM_VERSION } = require("../../config/constants"); + +async function scaffoldHardhat(projectName, templatePath, projectDir, options) { + await fs.ensureDir(projectDir); + await copyTemplate(templatePath, projectDir); + + const shouldInstallDeps = Boolean(options.installDeps); + + const packageJsonPath = path.join(projectDir, "package.json"); + const packageJson = await readJson(packageJsonPath); + + packageJson.name = projectName; + packageJson.type = "module"; + + packageJson.scripts = packageJson.scripts || {}; + packageJson.scripts.build = "npx hardhat compile"; + packageJson.scripts.test = "npx hardhat test"; + + packageJson.devDependencies = packageJson.devDependencies || {}; + + packageJson.dependencies = packageJson.dependencies || {}; + packageJson.dependencies[COMPOSE_NPM_PACKAGE] = COMPOSE_NPM_VERSION; + + const orderedPackageJson = orderPackageJsonWithDepsBeforeDevDeps(packageJson); + await writeJson(packageJsonPath, orderedPackageJson); + + if (shouldInstallDeps) { + logger.info("Installing project dependencies…"); + await runCommand("npm", ["install"], { cwd: projectDir }); + } else { + logger.info("Skipping dependency installation (installDeps=false)."); + } + + const nextSteps = shouldInstallDeps + ? ["npx hardhat compile && npx hardhat test"] + : ["npm install", "npx hardhat compile && npx hardhat test"]; + + return { nextSteps }; +} + +module.exports = { + scaffoldHardhat, +}; + diff --git a/cli/src/scaffold/scaffold.js b/cli/src/scaffold/scaffold.js new file mode 100644 index 00000000..2e75e0f5 --- /dev/null +++ b/cli/src/scaffold/scaffold.js @@ -0,0 +1,49 @@ +const fs = require("fs-extra"); +const { + assertTargetDoesNotExist, + assertDirectoryEmpty, + resolveProjectDir, + getProjectDisplayName, +} = require("./utils/fileManager"); +const { replaceTokensRecursively } = require("./utils/tokenReplace"); +const { scaffoldFoundry } = require("./frameworks/foundry"); +const { scaffoldHardhat } = require("./frameworks/hardhat"); + +async function scaffold({ projectName, templatePath, options }) { + const projectDir = resolveProjectDir(projectName); + if (projectName === ".") { + await assertDirectoryEmpty(projectDir); + } else { + await assertTargetDoesNotExist(projectDir); + } + + const displayName = getProjectDisplayName(projectName, projectDir); + + const templateExists = await fs.pathExists(templatePath); + if (!templateExists) { + throw new Error(`Template path does not exist: ${templatePath}`); + } + + let frameworkResult; + if (options.framework === "foundry") { + frameworkResult = await scaffoldFoundry(displayName, templatePath, projectDir, options); + } else if (options.framework === "hardhat") { + frameworkResult = await scaffoldHardhat(displayName, templatePath, projectDir, options); + } else { + throw new Error(`Unknown framework: ${options.framework}`); + } + + await replaceTokensRecursively(projectDir, { + "{{projectName}}": displayName, + }); + + return { + projectDir, + displayName, + nextSteps: frameworkResult?.nextSteps || [], + }; +} + +module.exports = { + scaffold, +}; diff --git a/cli/src/scaffold/utils/fileManager.js b/cli/src/scaffold/utils/fileManager.js new file mode 100644 index 00000000..cb90bced --- /dev/null +++ b/cli/src/scaffold/utils/fileManager.js @@ -0,0 +1,75 @@ +const fs = require("fs-extra"); +const path = require("node:path"); + +async function assertTargetDoesNotExist(projectDir) { + const exists = await fs.pathExists(projectDir); + if (exists) { + throw new Error(`Target directory already exists: ${projectDir}`); + } +} + +async function copyTemplate(templateDir, projectDir) { + await fs.copy(templateDir, projectDir); +} + +async function readJson(filePath) { + return fs.readJson(filePath); +} + +async function writeJson(filePath, data) { + await fs.writeJson(filePath, data, { spaces: 2 }); +} + +async function appendLineIfMissing(filePath, line) { + const exists = await fs.pathExists(filePath); + if (!exists) { + await fs.outputFile(filePath, `${line}\n`); + return; + } + + const content = await fs.readFile(filePath, "utf8"); + if (!content.includes(line)) { + await fs.writeFile(filePath, `${content.trimEnd()}\n${line}\n`); + } +} + +async function assertDirectoryEmpty(projectDir) { + const entries = await fs.readdir(projectDir); + const ignoredEntries = [".git"]; + const nonIgnored = entries.filter((entry) => !ignoredEntries.includes(entry)); + if (nonIgnored.length > 0) { + throw new Error(`Target directory is not empty: ${projectDir}`); + } +} + +function resolveProjectDir(projectName) { + return path.join(process.cwd(), projectName); +} + +function getProjectDisplayName(projectName, projectDir) { + if (projectName === ".") { + return path.basename(projectDir); + } + return projectName; +} + +function getTemplateDisplayName(templatePath) { + const templatesRoot = path.join(__dirname, "..", "..", "templates"); + let templateName = path.relative(templatesRoot, templatePath).replace(/\\/g, "/"); + if (templateName.startsWith("..")) { + templateName = path.basename(templatePath); + } + return templateName; +} + +module.exports = { + assertTargetDoesNotExist, + assertDirectoryEmpty, + copyTemplate, + readJson, + writeJson, + appendLineIfMissing, + resolveProjectDir, + getProjectDisplayName, + getTemplateDisplayName, +}; diff --git a/cli/src/scaffold/utils/packageOrderer.js b/cli/src/scaffold/utils/packageOrderer.js new file mode 100644 index 00000000..26711440 --- /dev/null +++ b/cli/src/scaffold/utils/packageOrderer.js @@ -0,0 +1,32 @@ +function orderPackageJsonWithDepsBeforeDevDeps(packageJson) { + const orderedPackageJson = {}; + const dependencies = packageJson.dependencies || {}; + const devDependencies = packageJson.devDependencies || {}; + let insertedDependencyBlocks = false; + + for (const [key, value] of Object.entries(packageJson)) { + if (key === "dependencies") { + continue; + } + + if (key === "devDependencies") { + orderedPackageJson.dependencies = dependencies; + orderedPackageJson.devDependencies = devDependencies; + insertedDependencyBlocks = true; + continue; + } + + orderedPackageJson[key] = value; + } + + if (!insertedDependencyBlocks) { + orderedPackageJson.dependencies = dependencies; + orderedPackageJson.devDependencies = devDependencies; + } + + return orderedPackageJson; +} + +module.exports = { + orderPackageJsonWithDepsBeforeDevDeps, +}; diff --git a/cli/src/scaffold/utils/templateLoader.js b/cli/src/scaffold/utils/templateLoader.js new file mode 100644 index 00000000..540c3309 --- /dev/null +++ b/cli/src/scaffold/utils/templateLoader.js @@ -0,0 +1,51 @@ +const path = require("node:path"); +const fs = require("fs-extra"); +const { TEMPLATE_REGISTRY_PATH } = require("../../config/constants"); +const { validateTemplatesConfig } = require("../../config/validateTemplatesConfig"); + +async function loadTemplateConfig() { + const config = await fs.readJson(TEMPLATE_REGISTRY_PATH); + validateTemplatesConfig(config); + return config; +} + +function pickVariant(config, options) { + const { template = config.defaultTemplateId, framework, language, projectType } = options; + + const templateEntry = config.templates.find((item) => item.id === template); + if (!templateEntry) { + throw new Error(`Template not found: ${template}`); + } + + const variant = templateEntry.variants.find((item) => { + if (framework && item.framework !== framework) { + return false; + } + if (item.framework === "hardhat" && language && item.language !== language) { + return false; + } + if (projectType && item.projectType && item.projectType !== projectType) { + return false; + } + if (!framework && item.id === config.defaultTemplateId) { + return true; + } + return framework ? true : false; + }); + + if (!variant) { + throw new Error(`No template variant for template=${template}, framework=${framework}, language=${language || "-"}`); + } + + return variant; +} + +function resolveTemplatePath(variant) { + return path.join(__dirname, "..", "..", variant.path); +} + +module.exports = { + loadTemplateConfig, + pickVariant, + resolveTemplatePath, +}; diff --git a/cli/src/scaffold/utils/tokenReplace.js b/cli/src/scaffold/utils/tokenReplace.js new file mode 100644 index 00000000..1b39ad1e --- /dev/null +++ b/cli/src/scaffold/utils/tokenReplace.js @@ -0,0 +1,40 @@ +const fs = require("fs-extra"); +const path = require("node:path"); + +async function replaceTokensInFile(filePath, tokenMap) { + const content = await fs.readFile(filePath, "utf8"); + let updated = content; + + Object.entries(tokenMap).forEach(([token, value]) => { + updated = updated.split(token).join(value); + }); + + if (updated !== content) { + await fs.writeFile(filePath, updated); + } +} + +async function replaceTokensRecursively(rootDir, tokenMap) { + const entries = await fs.readdir(rootDir); + + await Promise.all( + entries.map(async (entry) => { + const fullPath = path.join(rootDir, entry); + const stat = await fs.stat(fullPath); + + if (stat.isDirectory()) { + await replaceTokensRecursively(fullPath, tokenMap); + return; + } + + const textExtensions = [".md", ".txt", ".json", ".toml", ".js", ".ts", ".sol"]; + if (textExtensions.some((ext) => fullPath.endsWith(ext))) { + await replaceTokensInFile(fullPath, tokenMap); + } + }) + ); +} + +module.exports = { + replaceTokensRecursively, +}; diff --git a/cli/src/templates/default/foundry/.gitignore b/cli/src/templates/default/foundry/.gitignore new file mode 100644 index 00000000..c8ba071a --- /dev/null +++ b/cli/src/templates/default/foundry/.gitignore @@ -0,0 +1,5 @@ +out/ +cache/ +broadcast/ +lib/ +.env diff --git a/cli/src/templates/default/foundry/README.md b/cli/src/templates/default/foundry/README.md new file mode 100644 index 00000000..53f92a0f --- /dev/null +++ b/cli/src/templates/default/foundry/README.md @@ -0,0 +1,9 @@ +# {{projectName}} + +Foundry diamond starter scaffolded by Compose CLI. + +## Next steps + +1. `forge build` +2. `forge test` +3. `forge script script/Deploy.s.sol:DeployScript --rpc-url --private-key --broadcast` diff --git a/cli/src/templates/default/foundry/foundry.toml b/cli/src/templates/default/foundry/foundry.toml new file mode 100644 index 00000000..b83fc46b --- /dev/null +++ b/cli/src/templates/default/foundry/foundry.toml @@ -0,0 +1,9 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +optimizer = true +optimizer_runs = 200 + +[fmt] +line_length = 120 diff --git a/cli/src/templates/default/foundry/remappings.txt b/cli/src/templates/default/foundry/remappings.txt new file mode 100644 index 00000000..9352c32e --- /dev/null +++ b/cli/src/templates/default/foundry/remappings.txt @@ -0,0 +1 @@ +@perfect-abstractions/compose/=lib/Compose/src/ diff --git a/cli/src/templates/default/foundry/script/Deploy.s.sol b/cli/src/templates/default/foundry/script/Deploy.s.sol new file mode 100644 index 00000000..ac119f91 --- /dev/null +++ b/cli/src/templates/default/foundry/script/Deploy.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Script} from "forge-std/Script.sol"; +import {CounterFacet} from "../src/facets/CounterFacet.sol"; +import {Diamond} from "../src/Diamond.sol"; +import {DiamondInspectFacet} from "@perfect-abstractions/compose/diamond/DiamondInspectFacet.sol"; +import {DiamondUpgradeFacet} from "@perfect-abstractions/compose/diamond/DiamondUpgradeFacet.sol"; + +contract DeployScript is Script { + function run() external { + vm.startBroadcast(); + + CounterFacet counterFacet = new CounterFacet(); + DiamondInspectFacet inspectFacet = new DiamondInspectFacet(); + DiamondUpgradeFacet upgradeFacet = new DiamondUpgradeFacet(); + + address[] memory facets = new address[](3); + facets[0] = address(counterFacet); + facets[1] = address(inspectFacet); + facets[2] = address(upgradeFacet); + + new Diamond(facets, msg.sender); + + vm.stopBroadcast(); + } +} diff --git a/cli/src/templates/default/foundry/src/Diamond.sol b/cli/src/templates/default/foundry/src/Diamond.sol new file mode 100644 index 00000000..20841d68 --- /dev/null +++ b/cli/src/templates/default/foundry/src/Diamond.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; +import "@perfect-abstractions/compose/access/Owner/OwnerMod.sol" as OwnerMod; + +contract Diamond { + constructor(address[] memory facets, address diamondOwner) { + DiamondMod.addFacets(facets); + OwnerMod.setContractOwner(diamondOwner); + } + + fallback() external payable { + DiamondMod.diamondFallback(); + } + + receive() external payable {} +} diff --git a/cli/src/templates/default/foundry/src/facets/CounterFacet.sol b/cli/src/templates/default/foundry/src/facets/CounterFacet.sol new file mode 100644 index 00000000..d85b39b0 --- /dev/null +++ b/cli/src/templates/default/foundry/src/facets/CounterFacet.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract CounterFacet { + event Increment(uint256 by); + + bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter.storage"); + + struct CounterStorage { + uint256 counter; + } + + function _getStorage() internal pure returns (CounterStorage storage s) { + bytes32 position = COUNTER_STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function increment() external { + CounterStorage storage s = _getStorage(); + s.counter += 1; + emit Increment(1); + } + + function getCounter() external view returns (uint256) { + return _getStorage().counter; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.increment.selector, this.getCounter.selector); + } +} diff --git a/cli/src/templates/default/foundry/test/CounterFacet.t.sol b/cli/src/templates/default/foundry/test/CounterFacet.t.sol new file mode 100644 index 00000000..241d4877 --- /dev/null +++ b/cli/src/templates/default/foundry/test/CounterFacet.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test} from "forge-std/Test.sol"; +import {CounterFacet} from "../src/facets/CounterFacet.sol"; +import {Diamond} from "../src/Diamond.sol"; + +contract CounterFacetTest is Test { + CounterFacet internal counter; + Diamond internal diamond; + + address internal owner = makeAddr("owner"); + + function setUp() public { + CounterFacet counterFacet = new CounterFacet(); + + address[] memory facets = new address[](1); + facets[0] = address(counterFacet); + + diamond = new Diamond(facets, owner); + counter = CounterFacet(address(diamond)); + } + + function test_increment() public { + counter.increment(); + assertEq(counter.getCounter(), 1); + } +} diff --git a/cli/src/templates/default/hardhat/ts/minimal/.gitignore b/cli/src/templates/default/hardhat/ts/minimal/.gitignore new file mode 100644 index 00000000..991a319e --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/minimal/.gitignore @@ -0,0 +1,20 @@ +# Node modules +/node_modules + +# Compilation output +/dist + +# pnpm deploy output +/bundle + +# Hardhat Build Artifacts +/artifacts + +# Hardhat compilation (v2) support directory +/cache + +# Typechain output +/types + +# Hardhat coverage reports +/coverage diff --git a/cli/src/templates/default/hardhat/ts/minimal/README.md b/cli/src/templates/default/hardhat/ts/minimal/README.md new file mode 100644 index 00000000..6bf1b7af --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/minimal/README.md @@ -0,0 +1,20 @@ +# {{projectName}} + +Minimal diamond starter scaffolded by Compose CLI using Hardhat 3. + + +## What's included? + +The project includes native support for TypeScript, Hardhat scripts, tasks, support for Solidity compilation & tests. + +Compose is directly included as a dependency in the project (even before package publication). + +This starter includes: +- `contracts/Diamond.sol` using Compose `DiamondMod` and `OwnerMod` +- `contracts/CounterFacet.sol` with `increment`, `getCounter`, and `exportSelectors` + +To deploy a working diamond, deploy `CounterFacet` first, then pass the facet address and owner into `Diamond` constructor. + +## Next steps +1. `npx hardhat compile` +2. `npx hardhat test` diff --git a/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol new file mode 100644 index 00000000..ef353351 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {DiamondMod} from "@perfect-abstractions/compose/modules/DiamondMod.sol"; +import {OwnerMod} from "@perfect-abstractions/compose/modules/OwnerMod.sol"; + +contract Diamond { + constructor(address[] memory facets, address diamondOwner) { + DiamondMod.addFacets(facets); + OwnerMod.setContractOwner(diamondOwner); + } + + fallback() external payable { + DiamondMod.diamondFallback(); + } + + receive() external payable {} +} diff --git a/cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol b/cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol new file mode 100644 index 00000000..b612d60e --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract CounterFacet { + event Increment(uint256 by); + + bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); + + struct CounterStorage { + uint256 counter; + } + + function _getStorage() private pure returns (CounterStorage storage s) { + bytes32 position = COUNTER_STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function increment() external { + CounterStorage storage s = _getStorage(); + s.counter += 1; + emit Increment(1); + } + + function getCounter() external view returns (uint256) { + return _getStorage().counter; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.increment.selector, this.getCounter.selector); + } +} diff --git a/cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts b/cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts new file mode 100644 index 00000000..82e7c620 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "hardhat/config"; + +export default defineConfig({ + solidity: { + version: "0.8.30", + }, +}); + diff --git a/cli/src/templates/default/hardhat/ts/minimal/package.json b/cli/src/templates/default/hardhat/ts/minimal/package.json new file mode 100644 index 00000000..be8b3d04 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/minimal/package.json @@ -0,0 +1,10 @@ +{ + "name": "{{projectName}}", + "version": "1.0.0", + "type": "module", + "devDependencies": { + "@types/node": "^22.19.13", + "hardhat": "^3.1.10", + "typescript": "~5.8.0" + } +} diff --git a/cli/src/templates/default/hardhat/ts/minimal/tsconfig.json b/cli/src/templates/default/hardhat/ts/minimal/tsconfig.json new file mode 100644 index 00000000..9b1380cc --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/minimal/tsconfig.json @@ -0,0 +1,13 @@ +/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ +{ + "compilerOptions": { + "lib": ["es2023"], + "module": "node16", + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "node16", + "outDir": "dist" + } +} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore b/cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore new file mode 100644 index 00000000..991a319e --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore @@ -0,0 +1,20 @@ +# Node modules +/node_modules + +# Compilation output +/dist + +# pnpm deploy output +/bundle + +# Hardhat Build Artifacts +/artifacts + +# Hardhat compilation (v2) support directory +/cache + +# Typechain output +/types + +# Hardhat coverage reports +/coverage diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/README.md b/cli/src/templates/default/hardhat/ts/mocha-ethers/README.md new file mode 100644 index 00000000..01fe02be --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/README.md @@ -0,0 +1,59 @@ +# {{projectName}} + +This project showcases a Hardhat 3 project using `mocha` for tests and `ethers` for Ethereum interactions, scaffolded as a Compose diamond starter. + +To learn more about the Hardhat 3 Beta, please visit the [Getting Started guide](https://hardhat.org/docs/getting-started#getting-started-with-hardhat-3). To share your feedback, join our [Hardhat 3 Beta](https://hardhat.org/hardhat3-beta-telegram-group) Telegram group or [open an issue](https://github.com/NomicFoundation/hardhat/issues/new) in our GitHub issue tracker. + +## Project Overview + +This example project includes: + +- A simple Hardhat configuration file. +- Foundry-compatible Solidity unit tests. +- TypeScript integration tests using `mocha` and ethers.js +- Examples demonstrating how to connect to different types of networks, including locally simulating OP mainnet. +- A `Diamond` contract using Compose `DiamondMod` and `OwnerMod`. +- Counter facet (`CounterFacet`). + +## Usage + +### Running Tests + +To run all the tests in the project, execute the following command: + +```shell +npx hardhat test +``` + +You can also selectively run the Solidity or `mocha` tests: + +```shell +npx hardhat test solidity +npx hardhat test mocha +``` + +### Make a deployment to Sepolia + +This project includes an example Ignition module to deploy the diamond and facets. You can deploy this module to a locally simulated chain or to Sepolia. + +To run the deployment to a local chain: + +```shell +npx hardhat ignition deploy ignition/modules/Counter.ts +``` + +To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use. + +You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable. + +To set the `SEPOLIA_PRIVATE_KEY` config variable using `hardhat-keystore`: + +```shell +npx hardhat keystore set SEPOLIA_PRIVATE_KEY +``` + +After setting the variable, you can run the deployment with the Sepolia network: + +```shell +npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts +``` diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol new file mode 100644 index 00000000..20841d68 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; +import "@perfect-abstractions/compose/access/Owner/OwnerMod.sol" as OwnerMod; + +contract Diamond { + constructor(address[] memory facets, address diamondOwner) { + DiamondMod.addFacets(facets); + OwnerMod.setContractOwner(diamondOwner); + } + + fallback() external payable { + DiamondMod.diamondFallback(); + } + + receive() external payable {} +} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol new file mode 100644 index 00000000..b612d60e --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract CounterFacet { + event Increment(uint256 by); + + bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); + + struct CounterStorage { + uint256 counter; + } + + function _getStorage() private pure returns (CounterStorage storage s) { + bytes32 position = COUNTER_STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function increment() external { + CounterStorage storage s = _getStorage(); + s.counter += 1; + emit Increment(1); + } + + function getCounter() external view returns (uint256) { + return _getStorage().counter; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.increment.selector, this.getCounter.selector); + } +} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol new file mode 100644 index 00000000..bcd8e675 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {Test} from "forge-std/Test.sol"; +import {CounterFacet} from "../facets/CounterFacet.sol"; +import {Diamond} from "../Diamond.sol"; + +contract CounterFacetTest is Test { + CounterFacet internal counter; + Diamond internal diamond; + + address internal owner = makeAddr("owner"); + + function setUp() public { + CounterFacet counterFacet = new CounterFacet(); + + address[] memory facets = new address[](1); + facets[0] = address(counterFacet); + + diamond = new Diamond(facets, owner); + counter = CounterFacet(address(diamond)); + } + + function test_increment() public { + counter.increment(); + assertEq(counter.getCounter(), 1); + } +} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts new file mode 100644 index 00000000..57c4dd2a --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts @@ -0,0 +1,39 @@ +import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers"; +import { configVariable, defineConfig } from "hardhat/config"; + +export default defineConfig({ + plugins: [hardhatToolboxMochaEthersPlugin], + solidity: { + profiles: { + default: { + version: "0.8.28", + }, + production: { + version: "0.8.28", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + }, + }, + networks: { + hardhatMainnet: { + type: "edr-simulated", + chainType: "l1", + }, + hardhatOp: { + type: "edr-simulated", + chainType: "op", + }, + sepolia: { + type: "http", + chainType: "l1", + url: configVariable("SEPOLIA_RPC_URL"), + accounts: [configVariable("SEPOLIA_PRIVATE_KEY")], + }, + }, +}); + diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts new file mode 100644 index 00000000..0f6234f4 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts @@ -0,0 +1,15 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +import { DiamondInspectFacet } from "@perfect-abstractions/compose/diamond/DiamondInspectFacet.sol"; +import { DiamondUpgradeFacet } from "@perfect-abstractions/compose/diamond/DiamondUpgradeFacet.sol"; + +export default buildModule("CounterDiamondModule", (m) => { + const counterFacet = m.contract("CounterFacet"); + const inspectFacet = m.contract(DiamondInspectFacet); + const upgradeFacet = m.contract(DiamondUpgradeFacet); + + const owner = m.getAccount(0); + const diamond = m.contract("Diamond", [[counterFacet, inspectFacet, upgradeFacet], owner]); + + return { diamond, counterFacet, inspectFacet, upgradeFacet }; +}); diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/package.json b/cli/src/templates/default/hardhat/ts/mocha-ethers/package.json new file mode 100644 index 00000000..5f504c82 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/package.json @@ -0,0 +1,20 @@ +{ + "name": "{{projectName}}", + "version": "1.0.0", + "type": "module", + "devDependencies": { + "@nomicfoundation/hardhat-ethers": "^4.0.5", + "@nomicfoundation/hardhat-ignition": "^3.0.8", + "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.3", + "@types/chai": "^5.2.3", + "@types/chai-as-promised": "^8.0.2", + "@types/mocha": "^10.0.10", + "@types/node": "^22.19.13", + "chai": "^6.2.2", + "ethers": "^6.16.0", + "forge-std": "github:foundry-rs/forge-std#v1.9.4", + "hardhat": "^3.1.10", + "mocha": "^11.7.5", + "typescript": "~5.8.0" + } +} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts new file mode 100644 index 00000000..c3a4f7b2 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts @@ -0,0 +1,23 @@ +import { network } from "hardhat"; + +const { ethers } = await network.connect({ + network: "hardhatOp", + chainType: "op", +}); + +console.log("Sending transaction using the OP chain type"); + +const [sender] = await ethers.getSigners(); + +console.log("Sending 1 wei from", sender.address, "to itself"); + +console.log("Sending L2 transaction"); +const tx = await sender.sendTransaction({ + to: sender.address, + value: 1n, +}); + +await tx.wait(); + +console.log("Transaction sent successfully"); + diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts new file mode 100644 index 00000000..a5dbd535 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts @@ -0,0 +1,24 @@ +import { expect } from "chai"; +import { network } from "hardhat"; + +const { ethers } = await network.connect(); + +describe("Counter", function () { + it("Increment the counter", async function () { + const counterFacet = await ethers.deployContract("CounterFacet"); + const [owner] = await ethers.getSigners(); + + const diamond = await ethers.deployContract("Diamond", [ + [ + await counterFacet.getAddress() + ], + owner.address, + ]); + + const counter = await ethers.getContractAt("CounterFacet", await diamond.getAddress()); + + await counter.increment(); + expect(await counter.getCounter()).to.equal(1n); + }); +}); + diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json b/cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json new file mode 100644 index 00000000..9b1380cc --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json @@ -0,0 +1,13 @@ +/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ +{ + "compilerOptions": { + "lib": ["es2023"], + "module": "node16", + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "node16", + "outDir": "dist" + } +} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore b/cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore new file mode 100644 index 00000000..991a319e --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore @@ -0,0 +1,20 @@ +# Node modules +/node_modules + +# Compilation output +/dist + +# pnpm deploy output +/bundle + +# Hardhat Build Artifacts +/artifacts + +# Hardhat compilation (v2) support directory +/cache + +# Typechain output +/types + +# Hardhat coverage reports +/coverage diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/README.md b/cli/src/templates/default/hardhat/ts/node-runner-viem/README.md new file mode 100644 index 00000000..4677de91 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/README.md @@ -0,0 +1,59 @@ +# {{projectName}} + +This project showcases a Hardhat 3 project using the native Node.js test runner (`node:test`) and the `viem` library for Ethereum interactions, scaffolded as a Compose diamond starter. + +To learn more about the Hardhat 3 Beta, please visit the [Getting Started guide](https://hardhat.org/docs/getting-started#getting-started-with-hardhat-3). To share your feedback, join our [Hardhat 3 Beta](https://hardhat.org/hardhat3-beta-telegram-group) Telegram group or [open an issue](https://github.com/NomicFoundation/hardhat/issues/new) in our GitHub issue tracker. + +## Project Overview + +This example project includes: + +- A simple Hardhat configuration file. +- Foundry-compatible Solidity unit tests. +- TypeScript integration tests using [`node:test`](nodejs.org/api/test.html), the new Node.js native test runner, and [`viem`](https://viem.sh/). +- Examples demonstrating how to connect to different types of networks, including locally simulating OP mainnet. +- A local `Diamond` contract using Compose `DiamondMod` and `OwnerMod`. +- Counter and diamond management facets (`CounterFacet`, `DiamondInspectFacet`, `DiamondUpgradeFacet`). + +## Usage + +### Running Tests + +To run all the tests in the project, execute the following command: + +```shell +npx hardhat test +``` + +You can also selectively run the Solidity or `node:test` tests: + +```shell +npx hardhat test solidity +npx hardhat test nodejs +``` + +### Make a deployment to Sepolia + +This project includes an example Ignition module to deploy the diamond and facets. You can deploy this module to a locally simulated chain or to Sepolia. + +To run the deployment to a local chain: + +```shell +npx hardhat ignition deploy ignition/modules/Counter.ts +``` + +To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use. + +You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable. + +To set the `SEPOLIA_PRIVATE_KEY` config variable using `hardhat-keystore`: + +```shell +npx hardhat keystore set SEPOLIA_PRIVATE_KEY +``` + +After setting the variable, you can run the deployment with the Sepolia network: + +```shell +npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts +``` diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol new file mode 100644 index 00000000..ef353351 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {DiamondMod} from "@perfect-abstractions/compose/modules/DiamondMod.sol"; +import {OwnerMod} from "@perfect-abstractions/compose/modules/OwnerMod.sol"; + +contract Diamond { + constructor(address[] memory facets, address diamondOwner) { + DiamondMod.addFacets(facets); + OwnerMod.setContractOwner(diamondOwner); + } + + fallback() external payable { + DiamondMod.diamondFallback(); + } + + receive() external payable {} +} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol new file mode 100644 index 00000000..894477c9 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +contract CounterFacet { + event Increment(uint256 by); + + bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter.storage"); + + struct CounterStorage { + uint256 counter; + } + + function _getStorage() private pure returns (CounterStorage storage s) { + bytes32 position = COUNTER_STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function increment() external { + CounterStorage storage s = _getStorage(); + s.counter += 1; + emit Increment(1); + } + + function getCounter() external view returns (uint256) { + return _getStorage().counter; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.increment.selector, this.getCounter.selector); + } +} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol new file mode 100644 index 00000000..a6f3b5e8 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.30; + +import {CounterFacet} from "../facets/CounterFacet.sol"; +import {Diamond} from "../Diamond.sol"; +import {DiamondInspectFacet} from "@perfect-abstractions/compose/facets/diamond/DiamondInspectFacet.sol"; +import {DiamondUpgradeFacet} from "@perfect-abstractions/compose/facets/diamond/DiamondUpgradeFacet.sol"; +import {Test} from "forge-std/Test.sol"; + +contract CounterTest is Test { + CounterFacet counter; + + address internal owner = makeAddr("owner"); + + function setUp() public { + CounterFacet counterFacet = new CounterFacet(); + + address[] memory facets = new address[](1); + facets[0] = address(counterFacet); + + Diamond diamond = new Diamond(facets, owner); + counter = CounterFacet(address(diamond)); + } + + function test_InitialValue() public view { + require(counter.getCounter() == 0, "Initial value should be 0"); + } + + function testFuzz_Inc(uint8 x) public { + for (uint8 i = 0; i < x; i++) { + counter.increment(); + } + require(counter.getCounter() == x, "Value after increment x times should be x"); + } +} + diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts new file mode 100644 index 00000000..4874fc3e --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts @@ -0,0 +1,39 @@ +import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem"; +import { configVariable, defineConfig } from "hardhat/config"; + +export default defineConfig({ + plugins: [hardhatToolboxViemPlugin], + solidity: { + profiles: { + default: { + version: "0.8.30", + }, + production: { + version: "0.8.30", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + }, + }, + networks: { + hardhatMainnet: { + type: "edr-simulated", + chainType: "l1", + }, + hardhatOp: { + type: "edr-simulated", + chainType: "op", + }, + sepolia: { + type: "http", + chainType: "l1", + url: configVariable("SEPOLIA_RPC_URL"), + accounts: [configVariable("SEPOLIA_PRIVATE_KEY")], + }, + }, +}); + diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts new file mode 100644 index 00000000..3a4678e8 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts @@ -0,0 +1,15 @@ +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +import { DiamondInspectFacet } from "@perfect-abstractions/compose/facets/diamond/DiamondInspectFacet.sol"; +import { DiamondUpgradeFacet } from "@perfect-abstractions/compose/facets/diamond/DiamondUpgradeFacet.sol"; + +export default buildModule("CounterDiamondModule", (m) => { + const counterFacet = m.contract("CounterFacet"); + const inspectFacet = m.contract(DiamondInspectFacet); + const upgradeFacet = m.contract(DiamondUpgradeFacet); + + const owner = m.getAccount(0); + const diamond = m.contract("Diamond", [[counterFacet, inspectFacet, upgradeFacet], owner]); + + return { diamond, counterFacet, inspectFacet, upgradeFacet }; +}); diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/package.json b/cli/src/templates/default/hardhat/ts/node-runner-viem/package.json new file mode 100644 index 00000000..a4c9106c --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/package.json @@ -0,0 +1,14 @@ +{ + "name": "{{projectName}}", + "version": "1.0.0", + "type": "module", + "devDependencies": { + "@nomicfoundation/hardhat-ignition": "^3.0.8", + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2", + "@types/node": "^22.19.13", + "forge-std": "github:foundry-rs/forge-std#v1.9.4", + "hardhat": "^3.1.10", + "typescript": "~5.8.0", + "viem": "^2.47.0" + } +} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts new file mode 100644 index 00000000..5945f966 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts @@ -0,0 +1,32 @@ +import { network } from "hardhat"; + +const { viem } = await network.connect({ + network: "hardhatOp", + chainType: "op", +}); + +console.log("Sending transaction using the OP chain type"); + +const publicClient = await viem.getPublicClient(); +const [senderClient] = await viem.getWalletClients(); + +console.log("Sending 1 wei from", senderClient.account.address, "to itself"); + +const l1Gas = await publicClient.estimateL1Gas({ + account: senderClient.account.address, + to: senderClient.account.address, + value: 1n, +}); + +console.log("Estimated L1 gas:", l1Gas); + +console.log("Sending L2 transaction"); +const tx = await senderClient.sendTransaction({ + to: senderClient.account.address, + value: 1n, +}); + +await publicClient.waitForTransactionReceipt({ hash: tx }); + +console.log("Transaction sent successfully"); + diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts new file mode 100644 index 00000000..bc107d87 --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts @@ -0,0 +1,25 @@ +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +import { network } from "hardhat"; + +describe("Counter", async function () { + const { viem } = await network.connect(); + const walletClients = await viem.getWalletClients(); + const owner = walletClients[0]; + + it("Increment the counter", async function () { + const counterFacet = await viem.deployContract("CounterFacet"); + + const diamond = await viem.deployContract("Diamond", [ + [counterFacet.address], + owner.account.address, + ]); + + const counter = await viem.getContractAt("CounterFacet", diamond.address); + + await counter.write.increment(); + assert.equal(await counter.read.getCounter(), 1n); + }); +}); + diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json b/cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json new file mode 100644 index 00000000..9b1380cc --- /dev/null +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json @@ -0,0 +1,13 @@ +/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ +{ + "compilerOptions": { + "lib": ["es2023"], + "module": "node16", + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "node16", + "outDir": "dist" + } +} diff --git a/cli/src/templates/default/template.json b/cli/src/templates/default/template.json new file mode 100644 index 00000000..5e1848b1 --- /dev/null +++ b/cli/src/templates/default/template.json @@ -0,0 +1,14 @@ +{ + "id": "default", + "name": "Counter", + "description": "Simple diamond with a counter facet", + "variants": [ + "default-foundry", + "default-hardhat-minimal", + "default-hardhat-mocha-ethers", + "default-hardhat-node-runner-viem" + ], + "compatibility": { + "frameworks": ["foundry", "hardhat"] + } +} diff --git a/cli/src/utils/composeAsciiHeader.js b/cli/src/utils/composeAsciiHeader.js new file mode 100644 index 00000000..de788527 --- /dev/null +++ b/cli/src/utils/composeAsciiHeader.js @@ -0,0 +1,13 @@ +const COMPOSE_HEADER = ` + _____ ____ __ __ _____ ____ _____ ______ _____ _ _____ + / ____/ __ \\| \\/ | __ \\ / __ \\ / ____| ____| / ____| | |_ _| + | | | | | | \\ / | |__) | | | | (___ | |__ | | | | | | + | | | | | | |\\/| | ___/| | | |\\___ \\| __| | | | | | | + | |___| |__| | | | | | | |__| |____) | |____ | |____| |____ _| |_ + \\_____\\____/|_| |_|_| \\____/|_____/|______| \\_____|______|_____| + + ` + +module.exports = { + COMPOSE_HEADER, +}; \ No newline at end of file diff --git a/cli/src/utils/errors.js b/cli/src/utils/errors.js new file mode 100644 index 00000000..d6cdbf7e --- /dev/null +++ b/cli/src/utils/errors.js @@ -0,0 +1,25 @@ +const { logger } = require("./logger"); + +function normalizeError(error) { + if (error instanceof Error) { + return error; + } + + return new Error(String(error)); +} + +function exitWithError(error) { + const normalized = normalizeError(error); + logger.error(normalized.message); + + if (process.env.DEBUG === "1" && normalized.stack) { + logger.plain(normalized.stack); + } + + process.exitCode = 1; +} + +module.exports = { + normalizeError, + exitWithError, +}; diff --git a/cli/src/utils/exec.js b/cli/src/utils/exec.js new file mode 100644 index 00000000..9019a1ff --- /dev/null +++ b/cli/src/utils/exec.js @@ -0,0 +1,24 @@ +const { spawn } = require("node:child_process"); + +function runCommand(command, args, options = {}) { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { + stdio: "inherit", + ...options, + }); + + child.on("error", reject); + child.on("exit", (code) => { + if (code === 0) { + resolve(); + return; + } + + reject(new Error(`Command failed: ${command} ${args.join(" ")} (exit ${code})`)); + }); + }); +} + +module.exports = { + runCommand, +}; diff --git a/cli/src/utils/helpText.js b/cli/src/utils/helpText.js new file mode 100644 index 00000000..9ce1b23b --- /dev/null +++ b/cli/src/utils/helpText.js @@ -0,0 +1,29 @@ +const pkg = require("../../package.json"); +const { COMPOSE_DOCS_URL } = require("../config/constants"); + +const HELP_TEXT = ` +Compose CLI v${pkg.version} + +Scaffolds Diamond-based projects using the Compose Library + +Usage: + compose init [options] + compose list-templates + compose --version | -v + compose update + +Options: + --name + --template + --framework + --language + --install-deps | --no-install-deps + --yes + --help + +For more information about the Compose, see: ${COMPOSE_DOCS_URL} +`; + +module.exports = { + HELP_TEXT, +}; \ No newline at end of file diff --git a/cli/src/utils/logger.js b/cli/src/utils/logger.js new file mode 100644 index 00000000..830be744 --- /dev/null +++ b/cli/src/utils/logger.js @@ -0,0 +1,23 @@ +const pc = require("picocolors"); + +const logger = { + info(message) { + console.log(pc.cyan(message)); + }, + success(message) { + console.log(pc.green(message)); + }, + warn(message) { + console.warn(pc.yellow(message)); + }, + error(message) { + console.error(pc.red(message)); + }, + plain(message) { + console.log(message); + }, +}; + +module.exports = { + logger, +}; diff --git a/cli/src/utils/prompts/initUtils.js b/cli/src/utils/prompts/initUtils.js new file mode 100644 index 00000000..85ac0987 --- /dev/null +++ b/cli/src/utils/prompts/initUtils.js @@ -0,0 +1,29 @@ +const templateConfig = require("../../config/templates.json"); +const { assertDirectoryEmpty } = require("../../scaffold/utils/fileManager"); + +function getTemplateChoices() { + const list = templateConfig.templates || []; + if (list.length === 0) { + return [{ name: "Default", value: "default" }]; + } + return list.map((t) => ({ name: t.name, value: t.id })); +} + +async function validateProjectLocation(input) { + if (input !== ".") { + return true; + } + + try { + await assertDirectoryEmpty(process.cwd()); + return true; + } catch { + return 'Current directory must be empty (or only .git) when using ".".'; + } +} + +module.exports = { + getTemplateChoices, + validateProjectLocation, +}; + diff --git a/cli/test/fixtures/template-variants.snapshot.json b/cli/test/fixtures/template-variants.snapshot.json new file mode 100644 index 00000000..1ab0d33a --- /dev/null +++ b/cli/test/fixtures/template-variants.snapshot.json @@ -0,0 +1,8 @@ +{ + "default": [ + "default-foundry", + "default-hardhat-minimal", + "default-hardhat-mocha-ethers", + "default-hardhat-node-runner-viem" + ] +} diff --git a/cli/test/integration/cliEntry.test.js b/cli/test/integration/cliEntry.test.js new file mode 100644 index 00000000..6d2116ee --- /dev/null +++ b/cli/test/integration/cliEntry.test.js @@ -0,0 +1,35 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const path = require("node:path"); +const { spawnSync } = require("node:child_process"); + +const cliPath = path.join(__dirname, "..", "..", "index.js"); + +function runCli(args) { + return spawnSync(process.execPath, [cliPath, ...args], { + encoding: "utf8", + }); +} + +test("compose --version prints version and exits cleanly", () => { + const result = runCli(["--version"]); + const packageJson = require("../../package.json"); + + assert.equal(result.status, 0); + assert.equal(result.stdout.trim(), packageJson.version); +}); + +test("compose --help prints usage text", () => { + const result = runCli(["--help"]); + + assert.equal(result.status, 0); + assert.equal(result.stdout.includes("Usage:"), true); + assert.equal(result.stdout.includes("compose init [options]"), true); +}); + +test("compose unknown command exits with error", () => { + const result = runCli(["does-not-exist"]); + + assert.equal(result.status, 1); + assert.equal(result.stderr.includes("Unknown command"), true); +}); diff --git a/cli/test/integration/scaffoldVariants.test.js b/cli/test/integration/scaffoldVariants.test.js new file mode 100644 index 00000000..eaf1ac53 --- /dev/null +++ b/cli/test/integration/scaffoldVariants.test.js @@ -0,0 +1,147 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const path = require("node:path"); +const os = require("node:os"); +const fs = require("fs-extra"); +const { + loadTemplateConfig, + pickVariant, + resolveTemplatePath, +} = require("../../src/scaffold/utils/templateLoader"); +const { scaffold } = require("../../src/scaffold/scaffold"); + +async function scaffoldWithVariant(variant, options = {}) { + const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-it-")); + const originalCwd = process.cwd(); + process.chdir(tempRoot); + try { + const projectName = options.projectName || "demo-project"; + const result = await scaffold({ + projectName, + templatePath: resolveTemplatePath(variant), + options: { + framework: variant.framework, + language: variant.language, + hardhatProjectType: variant.projectType, + installDeps: false, + }, + }); + return { tempRoot, projectDir: result.projectDir, nextSteps: result.nextSteps }; + } finally { + process.chdir(originalCwd); + } +} + +test("scaffolds hardhat minimal variant", async () => { + const config = await loadTemplateConfig(); + const variant = pickVariant(config, { + template: "default", + framework: "hardhat", + language: "typescript", + projectType: "minimal", + }); + + const { projectDir, nextSteps } = await scaffoldWithVariant(variant, { + projectName: "hardhat-minimal-app", + }); + const packageJson = await fs.readJson(path.join(projectDir, "package.json")); + + assert.equal(await fs.pathExists(path.join(projectDir, "hardhat.config.ts")), true); + assert.equal(packageJson.name, "hardhat-minimal-app"); + assert.equal(nextSteps.includes("npm install"), true); +}); + +test("scaffolds hardhat mocha-ethers variant", async () => { + const config = await loadTemplateConfig(); + const variant = pickVariant(config, { + template: "default", + framework: "hardhat", + language: "typescript", + projectType: "mocha-ethers", + }); + + const { projectDir } = await scaffoldWithVariant(variant, { projectName: "hardhat-mocha-app" }); + const readme = await fs.readFile(path.join(projectDir, "README.md"), "utf8"); + + assert.equal(await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), true); + assert.equal(readme.includes("{{projectName}}"), false); + assert.equal(readme.includes("hardhat-mocha-app"), true); +}); + +test("scaffolds hardhat node-runner-viem variant", async () => { + const config = await loadTemplateConfig(); + const variant = pickVariant(config, { + template: "default", + framework: "hardhat", + language: "typescript", + projectType: "node-runner-viem", + }); + + const { projectDir } = await scaffoldWithVariant(variant, { + projectName: "hardhat-viem-app", + }); + const packageJson = await fs.readJson(path.join(projectDir, "package.json")); + + assert.equal(await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), true); + assert.equal( + packageJson.dependencies["@perfect-abstractions/compose"], + "latest" + ); +}); + +test("scaffolds into current directory when projectName is dot and directory is logically empty", async () => { + const config = await loadTemplateConfig(); + const variant = pickVariant(config, { + template: "default", + framework: "hardhat", + language: "typescript", + projectType: "minimal", + }); + + const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-it-dot-")); + const originalCwd = process.cwd(); + process.chdir(tempRoot); + + try { + const result = await scaffold({ + projectName: ".", + templatePath: resolveTemplatePath(variant), + options: { + framework: variant.framework, + language: variant.language, + hardhatProjectType: variant.projectType, + installDeps: false, + }, + }); + + const packageJson = await fs.readJson(path.join(result.projectDir, "package.json")); + assert.equal(result.projectDir, tempRoot); + assert.equal(packageJson.name, path.basename(tempRoot)); + } finally { + process.chdir(originalCwd); + } +}); + +test("scaffold throws for unknown framework", async () => { + await assert.rejects( + () => + scaffold({ + projectName: "demo", + templatePath: resolveTemplatePath({ path: "templates/default/foundry" }), + options: { framework: "unknown", installDeps: false }, + }), + /Unknown framework/ + ); +}); + +test("scaffold throws when template path is missing", async () => { + await assert.rejects( + () => + scaffold({ + projectName: "demo", + templatePath: path.join(process.cwd(), "this-template-does-not-exist"), + options: { framework: "hardhat", language: "typescript", installDeps: false }, + }), + /Template path does not exist/ + ); +}); diff --git a/cli/test/unit/errors.test.js b/cli/test/unit/errors.test.js new file mode 100644 index 00000000..c3d4250a --- /dev/null +++ b/cli/test/unit/errors.test.js @@ -0,0 +1,71 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const { normalizeError, exitWithError } = require("../../src/utils/errors"); +const { logger } = require("../../src/utils/logger"); + +test("normalizeError returns original Error instance", () => { + const error = new Error("boom"); + assert.equal(normalizeError(error), error); +}); + +test("normalizeError wraps non-error values", () => { + const normalized = normalizeError("boom"); + assert.equal(normalized instanceof Error, true); + assert.equal(normalized.message, "boom"); +}); + +test("exitWithError logs error and sets process.exitCode", () => { + const calls = []; + const originalError = logger.error; + const originalPlain = logger.plain; + const originalExitCode = process.exitCode; + let exitCodeAfterCall; + + logger.error = (message) => calls.push(["error", message]); + logger.plain = (message) => calls.push(["plain", message]); + delete process.env.DEBUG; + process.exitCode = 0; + + try { + exitWithError("failure"); + exitCodeAfterCall = process.exitCode; + } finally { + logger.error = originalError; + logger.plain = originalPlain; + process.exitCode = originalExitCode; + } + + assert.deepEqual(calls, [["error", "failure"]]); + assert.equal(exitCodeAfterCall, 1); +}); + +test("exitWithError logs stack trace when DEBUG=1", () => { + const calls = []; + const originalError = logger.error; + const originalPlain = logger.plain; + const originalDebug = process.env.DEBUG; + const originalExitCode = process.exitCode; + let exitCodeAfterCall; + + logger.error = (message) => calls.push(["error", message]); + logger.plain = (message) => calls.push(["plain", message]); + process.env.DEBUG = "1"; + process.exitCode = 0; + + try { + exitWithError(new Error("debug-failure")); + exitCodeAfterCall = process.exitCode; + } finally { + logger.error = originalError; + logger.plain = originalPlain; + process.env.DEBUG = originalDebug; + process.exitCode = originalExitCode; + } + + assert.equal(calls[0][0], "error"); + assert.equal(calls[0][1], "debug-failure"); + assert.equal(calls[1][0], "plain"); + assert.equal(typeof calls[1][1], "string"); + assert.equal(calls[1][1].includes("debug-failure"), true); + assert.equal(exitCodeAfterCall, 1); +}); diff --git a/cli/test/unit/fileManager.test.js b/cli/test/unit/fileManager.test.js new file mode 100644 index 00000000..37f29fcd --- /dev/null +++ b/cli/test/unit/fileManager.test.js @@ -0,0 +1,71 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const path = require("node:path"); +const os = require("node:os"); +const fs = require("fs-extra"); +const { + assertTargetDoesNotExist, + appendLineIfMissing, + assertDirectoryEmpty, + getProjectDisplayName, + getTemplateDisplayName, +} = require("../../src/scaffold/utils/fileManager"); + +test("assertTargetDoesNotExist throws when path already exists", async () => { + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-")); + await assert.rejects(() => assertTargetDoesNotExist(tempDir), /Target directory already exists/); +}); + +test("appendLineIfMissing creates file and avoids duplicate lines", async () => { + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-")); + const filePath = path.join(tempDir, ".gitignore"); + + await appendLineIfMissing(filePath, "node_modules"); + await appendLineIfMissing(filePath, "node_modules"); + await appendLineIfMissing(filePath, "dist"); + + const content = await fs.readFile(filePath, "utf8"); + assert.equal(content, "node_modules\ndist\n"); +}); + +test("getTemplateDisplayName returns relative template path when inside templates root", () => { + const templatePath = path.join(process.cwd(), "src", "templates", "default", "foundry"); + assert.equal(getTemplateDisplayName(templatePath), "default/foundry"); +}); + +test("getTemplateDisplayName falls back to basename for external paths", () => { + const templatePath = path.join(os.tmpdir(), "custom-template"); + assert.equal(getTemplateDisplayName(templatePath), "custom-template"); +}); + +test("assertDirectoryEmpty allows only .git in directory", async () => { + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-empty-")); + + // Empty directory is allowed + await assert.doesNotReject(() => assertDirectoryEmpty(tempDir)); + + // Directory with only .git is allowed + const gitDir = path.join(tempDir, ".git"); + await fs.mkdir(gitDir); + await assert.doesNotReject(() => assertDirectoryEmpty(tempDir)); + + // Any additional entry should cause a failure + const readmePath = path.join(tempDir, "README.md"); + await fs.writeFile(readmePath, "# demo\n"); + await assert.rejects( + () => assertDirectoryEmpty(tempDir), + /Target directory is not empty/ + ); +}); + +test("getProjectDisplayName uses folder name for dot project", () => { + const projectDir = path.join(os.tmpdir(), "compose-cli-project-dir"); + const name = getProjectDisplayName(".", projectDir); + assert.equal(name, path.basename(projectDir)); +}); + +test("getProjectDisplayName returns projectName for non-dot project", () => { + const projectDir = path.join(os.tmpdir(), "compose-cli-project-dir"); + const name = getProjectDisplayName("my-app", projectDir); + assert.equal(name, "my-app"); +}); diff --git a/cli/test/unit/initOptions.test.js b/cli/test/unit/initOptions.test.js new file mode 100644 index 00000000..ae338ee4 --- /dev/null +++ b/cli/test/unit/initOptions.test.js @@ -0,0 +1,34 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const { normalizeInitOptions } = require("../../src/commands/init"); + +test("normalizeInitOptions sets defaults", () => { + const options = normalizeInitOptions({}); + + assert.equal(options.template, ""); + assert.equal(options.framework, ""); + assert.equal(options.installDeps, undefined); +}); + +test("normalizeInitOptions prioritizes explicit flags", () => { + const options = normalizeInitOptions({ + name: "demo", + template: "default", + framework: "hardhat", + language: "javascript", + "install-deps": true, + }); + + assert.equal(options.projectName, "demo"); + assert.equal(options.framework, "hardhat"); + assert.equal(options.language, "javascript"); + assert.equal(options.installDeps, true); +}); + +test("normalizeInitOptions preserves no-install flag", () => { + const options = normalizeInitOptions({ + "install-deps": false, + }); + + assert.equal(options.installDeps, false); +}); diff --git a/cli/test/unit/initPrompts.test.js b/cli/test/unit/initPrompts.test.js new file mode 100644 index 00000000..f9a8486e --- /dev/null +++ b/cli/test/unit/initPrompts.test.js @@ -0,0 +1,49 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const path = require("node:path"); +const os = require("node:os"); +const fs = require("fs-extra"); + +const { assertDirectoryEmpty } = require("../../src/scaffold/utils/fileManager"); +const { validateProjectLocation } = require("../../src/utils/prompts/initUtils"); + +test("validateProjectLocation returns true for non-dot names", async () => { + const result = await validateProjectLocation("my-app"); + assert.equal(result, true); +}); + +test("validateProjectLocation accepts dot in logically empty directory", async () => { + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-init-")); + const originalCwd = process.cwd(); + process.chdir(tempDir); + + try { + // Ensure our invariant helper agrees this directory is acceptable + await assertDirectoryEmpty(process.cwd()); + + const result = await validateProjectLocation("."); + assert.equal(result, true); + } finally { + process.chdir(originalCwd); + } +}); + +test("validateProjectLocation rejects dot in non-empty directory", async () => { + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-init-")); + const originalCwd = process.cwd(); + process.chdir(tempDir); + + try { + const readmePath = path.join(tempDir, "README.md"); + await fs.writeFile(readmePath, "# demo\n"); + + const result = await validateProjectLocation("."); + assert.equal( + result, + 'Current directory must be empty (or only .git) when using ".".' + ); + } finally { + process.chdir(originalCwd); + } +}); + diff --git a/cli/test/unit/packageOrderer.test.js b/cli/test/unit/packageOrderer.test.js new file mode 100644 index 00000000..90d996f7 --- /dev/null +++ b/cli/test/unit/packageOrderer.test.js @@ -0,0 +1,30 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const { orderPackageJsonWithDepsBeforeDevDeps } = require("../../src/scaffold/utils/packageOrderer"); + +test("places dependencies before devDependencies", () => { + const input = { + name: "demo", + version: "1.0.0", + devDependencies: { b: "1.0.0" }, + dependencies: { a: "1.0.0" }, + scripts: { test: "node --test" }, + }; + + const ordered = orderPackageJsonWithDepsBeforeDevDeps(input); + assert.deepEqual(Object.keys(ordered), [ + "name", + "version", + "dependencies", + "devDependencies", + "scripts", + ]); +}); + +test("adds missing dependency blocks when absent", () => { + const ordered = orderPackageJsonWithDepsBeforeDevDeps({ name: "demo" }); + + assert.deepEqual(Object.keys(ordered), ["name", "dependencies", "devDependencies"]); + assert.deepEqual(ordered.dependencies, {}); + assert.deepEqual(ordered.devDependencies, {}); +}); diff --git a/cli/test/unit/templateLoader.test.js b/cli/test/unit/templateLoader.test.js new file mode 100644 index 00000000..4ac52aab --- /dev/null +++ b/cli/test/unit/templateLoader.test.js @@ -0,0 +1,59 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const { + loadTemplateConfig, + pickVariant, + resolveTemplatePath, +} = require("../../src/scaffold/utils/templateLoader"); + +test("pickVariant returns foundry variant", async () => { + const config = await loadTemplateConfig(); + const variant = pickVariant(config, { + template: "default", + framework: "foundry", + }); + + assert.equal(variant.id, "default-foundry"); +}); + +test("pickVariant returns hardhat minimal variant", async () => { + const config = await loadTemplateConfig(); + const variant = pickVariant(config, { + template: "default", + framework: "hardhat", + language: "typescript", + projectType: "minimal", + }); + + assert.equal(variant.id, "default-hardhat-minimal"); +}); + +test("pickVariant throws for unknown template", async () => { + const config = await loadTemplateConfig(); + assert.throws( + () => + pickVariant(config, { + template: "does-not-exist", + framework: "foundry", + }), + /Template not found/ + ); +}); + +test("pickVariant throws when no variant matches", async () => { + const config = await loadTemplateConfig(); + assert.throws( + () => + pickVariant(config, { + template: "default", + framework: "hardhat", + language: "javascript", + }), + /No template variant/ + ); +}); + +test("resolveTemplatePath returns an absolute path in src", () => { + const resolved = resolveTemplatePath({ path: "templates/default/foundry" }); + assert.equal(resolved.includes("/src/templates/default/foundry"), true); +}); diff --git a/cli/test/unit/templateSnapshot.test.js b/cli/test/unit/templateSnapshot.test.js new file mode 100644 index 00000000..483d3193 --- /dev/null +++ b/cli/test/unit/templateSnapshot.test.js @@ -0,0 +1,18 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const fs = require("fs-extra"); +const path = require("node:path"); +const { loadTemplateConfig } = require("../../src/scaffold/utils/templateLoader"); + +test("template variants match snapshot", async () => { + const snapshotPath = path.join(__dirname, "..", "fixtures", "template-variants.snapshot.json"); + const snapshot = await fs.readJson(snapshotPath); + const config = await loadTemplateConfig(); + + const actual = {}; + config.templates.forEach((template) => { + actual[template.id] = template.variants.map((variant) => variant.id); + }); + + assert.deepEqual(actual, snapshot); +}); diff --git a/cli/test/unit/tokenReplace.test.js b/cli/test/unit/tokenReplace.test.js new file mode 100644 index 00000000..1645af96 --- /dev/null +++ b/cli/test/unit/tokenReplace.test.js @@ -0,0 +1,26 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const path = require("node:path"); +const os = require("node:os"); +const fs = require("fs-extra"); +const { replaceTokensRecursively } = require("../../src/scaffold/utils/tokenReplace"); + +test("replaceTokensRecursively updates supported text files recursively", async () => { + const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-tr-")); + const nestedDir = path.join(rootDir, "nested"); + await fs.ensureDir(nestedDir); + + const readmePath = path.join(rootDir, "README.md"); + const jsonPath = path.join(nestedDir, "package.json"); + const pngPath = path.join(rootDir, "image.png"); + + await fs.writeFile(readmePath, "Project {{projectName}}"); + await fs.writeFile(jsonPath, '{"name":"{{projectName}}"}'); + await fs.writeFile(pngPath, "binary-{{projectName}}"); + + await replaceTokensRecursively(rootDir, { "{{projectName}}": "demo-app" }); + + assert.equal(await fs.readFile(readmePath, "utf8"), "Project demo-app"); + assert.equal(await fs.readFile(jsonPath, "utf8"), '{"name":"demo-app"}'); + assert.equal(await fs.readFile(pngPath, "utf8"), "binary-{{projectName}}"); +}); diff --git a/cli/test/unit/validateTemplatesConfig.test.js b/cli/test/unit/validateTemplatesConfig.test.js new file mode 100644 index 00000000..9808ad2a --- /dev/null +++ b/cli/test/unit/validateTemplatesConfig.test.js @@ -0,0 +1,19 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const templatesConfig = require("../../src/config/templates.json"); +const { validateTemplatesConfig } = require("../../src/config/validateTemplatesConfig"); + +test("validateTemplatesConfig accepts current registry", () => { + assert.equal(validateTemplatesConfig(templatesConfig), true); +}); + +test("validateTemplatesConfig rejects missing variants", () => { + assert.throws( + () => + validateTemplatesConfig({ + templates: [{ id: "default", name: "Default", variants: [] }], + defaultTemplateId: "default", + }), + /variants must be a non-empty array/ + ); +}); diff --git a/cli/test/unit/versionCommand.test.js b/cli/test/unit/versionCommand.test.js new file mode 100644 index 00000000..629545e6 --- /dev/null +++ b/cli/test/unit/versionCommand.test.js @@ -0,0 +1,18 @@ +const test = require("node:test"); +const assert = require("node:assert/strict"); +const { runVersionCommand } = require("../../src/commands/version"); +const { logger } = require("../../src/utils/logger"); + +test("runVersionCommand prints version string", () => { + const calls = []; + const originalPlain = logger.plain; + logger.plain = (message) => calls.push(message); + + try { + runVersionCommand("1.2.3"); + } finally { + logger.plain = originalPlain; + } + + assert.deepEqual(calls, ["1.2.3"]); +}); From 2c6e0111ddeb0caa048bc6a692e28794dab58fb1 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 13:08:09 -0400 Subject: [PATCH 02/18] add cli action --- .github/workflows/cli.yml | 167 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 .github/workflows/cli.yml diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml new file mode 100644 index 00000000..8a565664 --- /dev/null +++ b/.github/workflows/cli.yml @@ -0,0 +1,167 @@ +name: CLI + +on: + push: + branches: [main] + paths: + - 'cli/**' + - '.github/workflows/cli.yml' + tags: + - 'v*' + pull_request: + paths: + - 'cli/**' + - '.github/workflows/cli.yml' + workflow_dispatch: + +jobs: + lint-and-unit: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x, 20.x, 22.x] + name: Lint and unit (Node ${{ matrix.node-version }}) + defaults: + run: + working-directory: cli + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + cache-dependency-path: cli/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Build templates registry + run: npm run build:templates + + - name: Lint + run: npm run lint + + - name: Run unit tests + run: npm run test:unit + + integration: + runs-on: ubuntu-latest + needs: lint-and-unit + defaults: + run: + working-directory: cli + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: npm + cache-dependency-path: cli/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Build templates registry + run: npm run build:templates + + - name: Run integration tests + run: npm run test:integration + + template-smoke-tests: + runs-on: ubuntu-latest + needs: lint-and-unit + env: + FOUNDRY_PROFILE: ci + defaults: + run: + working-directory: cli + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: npm + cache-dependency-path: cli/package-lock.json + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Install dependencies + run: npm ci + + - name: Prepare libraries + run: npm run prepare:lib + + - name: Build templates registry + run: npm run build:templates + + - name: Smoke test Foundry default template + run: | + set -euo pipefail + rm -rf ci-foundry + node index.js init \ + --name ci-foundry \ + --template default \ + --framework foundry \ + --yes + cd ci-foundry + forge build + + - name: Smoke test Hardhat default TypeScript template + run: | + set -euo pipefail + rm -rf ci-hardhat + node index.js init \ + --name ci-hardhat \ + --template default \ + --framework hardhat \ + --language typescript \ + --yes + cd ci-hardhat + npm install + npm test + + pack-verify: + runs-on: ubuntu-latest + needs: + - lint-and-unit + - integration + - template-smoke-tests + defaults: + run: + working-directory: cli + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: npm + cache-dependency-path: cli/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Build templates registry + run: npm run build:templates + + - name: Verify npm pack output + run: npm run pack:check + From 6a816bf6d88bfe5e33fd13da1924b239c98318d0 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 13:16:27 -0400 Subject: [PATCH 03/18] remove cli license to global license --- cli/LICENSE | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 cli/LICENSE diff --git a/cli/LICENSE b/cli/LICENSE deleted file mode 100644 index f50fe699..00000000 --- a/cli/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 M.N - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. From a3047ba5be5382310f4841753269a857a0e878e4 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 13:24:46 -0400 Subject: [PATCH 04/18] update test path, ignore action on cli --- .github/workflows/coverage.yml | 1 + .github/workflows/gas-report.yml | 1 + .github/workflows/slither.yml | 2 ++ .github/workflows/test.yml | 2 ++ cli/package.json | 4 ++-- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7616b465..30fab45c 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -5,6 +5,7 @@ on: paths-ignore: - '**.md' - 'website/**' + - 'cli/**' workflow_dispatch: env: diff --git a/.github/workflows/gas-report.yml b/.github/workflows/gas-report.yml index 734ee915..7c88b20b 100644 --- a/.github/workflows/gas-report.yml +++ b/.github/workflows/gas-report.yml @@ -5,6 +5,7 @@ on: paths-ignore: - '**.md' - 'website/**' + - 'cli/**' workflow_dispatch: env: diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml index e36567d7..d35e7680 100644 --- a/.github/workflows/slither.yml +++ b/.github/workflows/slither.yml @@ -7,10 +7,12 @@ on: paths-ignore: - '**.md' - 'website/**' + - 'cli/**' pull_request: paths-ignore: - '**.md' - 'website/**' + - 'cli/**' workflow_dispatch: env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4deacf4a..33b9e29c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,10 +6,12 @@ on: paths-ignore: - '**.md' - 'website/**' + - 'cli/**' pull_request: paths-ignore: - '**.md' - 'website/**' + - 'cli/**' workflow_dispatch: env: diff --git a/cli/package.json b/cli/package.json index 5487388a..b0424e5b 100644 --- a/cli/package.json +++ b/cli/package.json @@ -10,8 +10,8 @@ "scripts": { "lint": "eslint .", "test": "node --test test/**/*.test.js", - "test:unit": "node --test test/unit", - "test:integration": "node --test test/integration", + "test:unit": "node --test test/unit/**/*.test.js", + "test:integration": "node --test test/integration/**/*.test.js", "check": "npm run lint && npm run test", "build:templates": "node scripts/generate-templates-config.js", "pack:check": "npm pack --dry-run", From a1438f7f24b1fa383be2d7f7af039bba46de6cb5 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 13:29:20 -0400 Subject: [PATCH 05/18] adjust test path --- cli/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/package.json b/cli/package.json index b0424e5b..5864e669 100644 --- a/cli/package.json +++ b/cli/package.json @@ -10,8 +10,8 @@ "scripts": { "lint": "eslint .", "test": "node --test test/**/*.test.js", - "test:unit": "node --test test/unit/**/*.test.js", - "test:integration": "node --test test/integration/**/*.test.js", + "test:unit": "node --test \"test/unit/**/*.test.js\"", + "test:integration": "node --test \"test/integration/**/*.test.js\"", "check": "npm run lint && npm run test", "build:templates": "node scripts/generate-templates-config.js", "pack:check": "npm pack --dry-run", From 934e990c63a28004f753986ea3d1d774a3d925c4 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 13:35:52 -0400 Subject: [PATCH 06/18] remove support for node18 to >=20 --- .github/workflows/cli.yml | 2 +- cli/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 8a565664..ebfcbb03 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18.x, 20.x, 22.x] + node-version: [20.x, 22.x, 24.x] name: Lint and unit (Node ${{ matrix.node-version }}) defaults: run: diff --git a/cli/package.json b/cli/package.json index 5864e669..785ce9b2 100644 --- a/cli/package.json +++ b/cli/package.json @@ -32,7 +32,7 @@ "author": "Perfect-Abstractions/Compose", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" }, "files": [ "index.js", From 5afcd2ccb69e58767a2a4bc343fbeb768d19c723 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 13:42:30 -0400 Subject: [PATCH 07/18] try fix test across node version --- cli/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/package.json b/cli/package.json index 785ce9b2..0587eeb3 100644 --- a/cli/package.json +++ b/cli/package.json @@ -9,9 +9,9 @@ "type": "commonjs", "scripts": { "lint": "eslint .", - "test": "node --test test/**/*.test.js", - "test:unit": "node --test \"test/unit/**/*.test.js\"", - "test:integration": "node --test \"test/integration/**/*.test.js\"", + "test": "node --test test", + "test:unit": "node --test test/unit", + "test:integration": "node --test test/integration", "check": "npm run lint && npm run test", "build:templates": "node scripts/generate-templates-config.js", "pack:check": "npm pack --dry-run", From 2b7ae4fd94edc8e8bbf6f1f9cbb493fff36daacd Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 13:51:30 -0400 Subject: [PATCH 08/18] update CI to run tests on 24.x and smoke test across node version --- .github/workflows/cli.yml | 17 +++++++++-------- cli/README.md | 2 +- cli/package.json | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index ebfcbb03..f2dd5898 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -17,10 +17,7 @@ on: jobs: lint-and-unit: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x, 22.x, 24.x] - name: Lint and unit (Node ${{ matrix.node-version }}) + name: Lint and Test defaults: run: working-directory: cli @@ -32,7 +29,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 24.x cache: npm cache-dependency-path: cli/package-lock.json @@ -62,7 +59,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x cache: npm cache-dependency-path: cli/package-lock.json @@ -77,6 +74,10 @@ jobs: template-smoke-tests: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [20.x, 22.x, 24.x] needs: lint-and-unit env: FOUNDRY_PROFILE: ci @@ -93,7 +94,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: ${{ matrix.node-version }} cache: npm cache-dependency-path: cli/package-lock.json @@ -152,7 +153,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x cache: npm cache-dependency-path: cli/package-lock.json diff --git a/cli/README.md b/cli/README.md index 3f5c0dc9..c437cf80 100644 --- a/cli/README.md +++ b/cli/README.md @@ -9,7 +9,7 @@ Supports both Foundry and Hardhat. npm install -g @perfect-abstractions/compose-cli ``` -Requires Node.js >= 18. +Requires Node.js >= 20. ## Usage diff --git a/cli/package.json b/cli/package.json index 0587eeb3..4c37e3db 100644 --- a/cli/package.json +++ b/cli/package.json @@ -9,9 +9,9 @@ "type": "commonjs", "scripts": { "lint": "eslint .", - "test": "node --test test", - "test:unit": "node --test test/unit", - "test:integration": "node --test test/integration", + "test": "node --test \"test/**/*.test.js\"", + "test:unit": "node --test \"test/unit/**/*.test.js\"", + "test:integration": "node --test \"test/integration/**/*.test.js\"", "check": "npm run lint && npm run test", "build:templates": "node scripts/generate-templates-config.js", "pack:check": "npm pack --dry-run", From 2cd20e724c2a19500d730772287c9123f7f078d3 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 14:20:25 -0400 Subject: [PATCH 09/18] adjust path, adjust counter storage location --- .github/workflows/cli.yml | 1 - cli/src/templates/default/foundry/src/Diamond.sol | 4 ++-- .../templates/default/foundry/src/facets/CounterFacet.sol | 2 +- .../default/hardhat/ts/minimal/contracts/Diamond.sol | 6 +++--- .../default/hardhat/ts/mocha-ethers/contracts/Diamond.sol | 4 ++-- .../hardhat/ts/node-runner-viem/contracts/Diamond.sol | 6 +++--- .../ts/node-runner-viem/contracts/facets/CounterFacet.sol | 2 +- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index f2dd5898..822a7598 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -17,7 +17,6 @@ on: jobs: lint-and-unit: runs-on: ubuntu-latest - name: Lint and Test defaults: run: working-directory: cli diff --git a/cli/src/templates/default/foundry/src/Diamond.sol b/cli/src/templates/default/foundry/src/Diamond.sol index 20841d68..2f927076 100644 --- a/cli/src/templates/default/foundry/src/Diamond.sol +++ b/cli/src/templates/default/foundry/src/Diamond.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.30; import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; -import "@perfect-abstractions/compose/access/Owner/OwnerMod.sol" as OwnerMod; +import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; contract Diamond { constructor(address[] memory facets, address diamondOwner) { DiamondMod.addFacets(facets); - OwnerMod.setContractOwner(diamondOwner); + OwnerDataMod.setContractOwner(diamondOwner); } fallback() external payable { diff --git a/cli/src/templates/default/foundry/src/facets/CounterFacet.sol b/cli/src/templates/default/foundry/src/facets/CounterFacet.sol index d85b39b0..6b5d03ec 100644 --- a/cli/src/templates/default/foundry/src/facets/CounterFacet.sol +++ b/cli/src/templates/default/foundry/src/facets/CounterFacet.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.30; contract CounterFacet { event Increment(uint256 by); - bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter.storage"); + bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); struct CounterStorage { uint256 counter; diff --git a/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol index ef353351..2f927076 100644 --- a/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol +++ b/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; -import {DiamondMod} from "@perfect-abstractions/compose/modules/DiamondMod.sol"; -import {OwnerMod} from "@perfect-abstractions/compose/modules/OwnerMod.sol"; +import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; +import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; contract Diamond { constructor(address[] memory facets, address diamondOwner) { DiamondMod.addFacets(facets); - OwnerMod.setContractOwner(diamondOwner); + OwnerDataMod.setContractOwner(diamondOwner); } fallback() external payable { diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol index 20841d68..2f927076 100644 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol +++ b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.30; import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; -import "@perfect-abstractions/compose/access/Owner/OwnerMod.sol" as OwnerMod; +import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; contract Diamond { constructor(address[] memory facets, address diamondOwner) { DiamondMod.addFacets(facets); - OwnerMod.setContractOwner(diamondOwner); + OwnerDataMod.setContractOwner(diamondOwner); } fallback() external payable { diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol index ef353351..2f927076 100644 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; -import {DiamondMod} from "@perfect-abstractions/compose/modules/DiamondMod.sol"; -import {OwnerMod} from "@perfect-abstractions/compose/modules/OwnerMod.sol"; +import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; +import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; contract Diamond { constructor(address[] memory facets, address diamondOwner) { DiamondMod.addFacets(facets); - OwnerMod.setContractOwner(diamondOwner); + OwnerDataMod.setContractOwner(diamondOwner); } fallback() external payable { diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol index 894477c9..b612d60e 100644 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol +++ b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.30; contract CounterFacet { event Increment(uint256 by); - bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter.storage"); + bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); struct CounterStorage { uint256 counter; From 618726dd9ad742dbe2311b2ef240173bab24a446 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 14:33:43 -0400 Subject: [PATCH 10/18] avoid install deps for now in hardhat test --- .github/workflows/cli.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 822a7598..0b7ff783 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -130,6 +130,7 @@ jobs: --template default \ --framework hardhat \ --language typescript \ + --install-deps=false \ --yes cd ci-hardhat npm install From 93e210b1bd6506091ec0c208bc3e7f25747c00ae Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 14:42:54 -0400 Subject: [PATCH 11/18] remove compose package for now (remove when pkg published) --- .github/workflows/cli.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 0b7ff783..cbf6fc78 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -130,9 +130,11 @@ jobs: --template default \ --framework hardhat \ --language typescript \ - --install-deps=false \ + --install-deps false \ --yes cd ci-hardhat + # TODO: Remove once @perfect-abstractions/compose is published to npm + npm pkg delete dependencies.@perfect-abstractions/compose || true npm install npm test From 5e28e17d81d0405cd686a6fa1da6d1dfc7396ce1 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 14:50:02 -0400 Subject: [PATCH 12/18] fix ci installdep flag --- .github/workflows/cli.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index cbf6fc78..b7b70221 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -130,7 +130,7 @@ jobs: --template default \ --framework hardhat \ --language typescript \ - --install-deps false \ + --install-deps=false \ --yes cd ci-hardhat # TODO: Remove once @perfect-abstractions/compose is published to npm From 6f9acb2d99afb72a1c994d8dc867d5a5352cb6be Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 14:59:16 -0400 Subject: [PATCH 13/18] try --no-install-deps --- .github/workflows/cli.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index b7b70221..b06bcd1b 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -130,7 +130,7 @@ jobs: --template default \ --framework hardhat \ --language typescript \ - --install-deps=false \ + --no-install-deps \ --yes cd ci-hardhat # TODO: Remove once @perfect-abstractions/compose is published to npm From 42b360701650cb9a3c241f434c1102f0ddb436fb Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 15:07:41 -0400 Subject: [PATCH 14/18] comment out hardhat smoketest until package published --- .github/workflows/cli.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index b06bcd1b..f1423ba9 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -121,22 +121,22 @@ jobs: cd ci-foundry forge build - - name: Smoke test Hardhat default TypeScript template - run: | - set -euo pipefail - rm -rf ci-hardhat - node index.js init \ - --name ci-hardhat \ - --template default \ - --framework hardhat \ - --language typescript \ - --no-install-deps \ - --yes - cd ci-hardhat - # TODO: Remove once @perfect-abstractions/compose is published to npm - npm pkg delete dependencies.@perfect-abstractions/compose || true - npm install - npm test + # TODO: Remove once @perfect-abstractions/compose is published to npm + # Currently, this make the Ci fail when trying to install the dependency. + # - name: Smoke test Hardhat default TypeScript template + # run: | + # set -euo pipefail + # rm -rf ci-hardhat + # node index.js init \ + # --name ci-hardhat \ + # --template default \ + # --framework hardhat \ + # --language typescript \ + # --no-install-deps \ + # --yes + # cd ci-hardhat + # npm install + # npm test pack-verify: runs-on: ubuntu-latest From df5fc9cd21d25bb7a40c1d7ad0b9fb6062f92ddc Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 17:57:40 -0400 Subject: [PATCH 15/18] remove lib script, add doc for new templates --- cli/README.md | 96 +++++++++++++++++++++++++++++++++++++++++------- cli/package.json | 3 +- 2 files changed, 83 insertions(+), 16 deletions(-) diff --git a/cli/README.md b/cli/README.md index c437cf80..d264e8c9 100644 --- a/cli/README.md +++ b/cli/README.md @@ -73,29 +73,97 @@ npm run build:templates npm run check ``` -To build or test the Foundry template (or any template that uses `lib/` submodules), init libs once: +### Template registry generation -```bash -npm run prepare:lib -``` +The template registry at `src/config/templates.json` is generated from per-template manifests under `src/templates/**/template.json`. -Then from a template directory, for example `src/templates/default/foundry`: +- To regenerate the registry after changing templates: ```bash -forge build -forge test +npm run build:templates ``` -New templates that need `forge-std` or Compose can add the same submodules under their own `lib/`; `prepare:lib` inits all submodules repo-wide. +## Add a new template + +To make a new template: + +1. **Create the template folder** + - Add a new directory under `src/templates/`. + - Example: `src/templates/erc721`. + +2. **Add a `template.json` manifest** + - Place it at `src/templates//template.json`. + - Required fields: + - `id`: the template id (must match ``). + - `name`: human‑readable name shown in `compose templates`. + - `description`: short description. + - `variants`: list of variant ids (see below). + - `compatibility.frameworks`: array of supported frameworks, e.g. `["foundry"]` or `["foundry","hardhat"]`. + - Example: + ```json + { + "id": "erc721", + "name": "ERC‑721 Diamond", + "description": "Diamond project with an ERC‑721 facet", + "variants": [ + "erc721-foundry", + "erc721-hardhat-minimal" + ], + "compatibility": { + "frameworks": ["foundry", "hardhat"] + } + } + ``` + +3. **Add variant directories** + - Variant ids follow the pattern: `-[-]`. + - The generator maps variants to paths as follows: + - **Foundry**: `templates//foundry` + - Example variant id: `erc721-foundry` → `src/templates/erc721/foundry` + - **Hardhat (no project type)**: `templates//hardhat` + - Example variant id: `erc721-hardhat` → `src/templates/erc721/hardhat` + - **Hardhat with project type (TypeScript/JS layout)**: + - Path pattern: `templates//hardhat/ts/` + - Example variant id: `erc721-hardhat-minimal` → `src/templates/erc721/hardhat/ts/minimal` + - Place the scaffolded project files (contracts, configs, tests, etc.) inside each variant directory. + +4. **Language detection** + - The CLI infers the language from the variant path: + - Paths containing `/ts/` → `language: "typescript"`. + - Paths containing `/js/` → `language: "javascript"`. + - For Foundry templates, language is not set on the variant; the framework alone is enough. + +5. **Regenerate the templates registry** + - From the `cli` directory run: + ```bash + npm run build:templates + ``` + - This rebuilds `src/config/templates.json` from all `template.json` manifests and validates the result. + +6. **Verify your template is available** + - Run: + ```bash + node index.js templates + ``` + - Confirm your new template and variants appear in the list. + +7. **Smoke‑test the template** + - Use your new template to scaffold a project: + ```bash + node index.js init --name my-test-project --template --framework --yes + ``` + - Then run the framework’s own test / build commands in the generated project. + +### Test the CLI locally -### Template registry generation +```bash +npm link +``` -The template registry at `src/config/templates.json` is generated from per-template manifests under `src/templates/**/template.json`. +This will create a symlink to the CLI in your global `node_modules` directory. -- To regenerate the registry after changing templates: +You can then test the CLI by running: ```bash -npm run build:templates +compose --help ``` - -The CLI loads the generated `templates.json` at runtime; editing `template.json` files alone is not enough unless you rebuild the registry. diff --git a/cli/package.json b/cli/package.json index 4c37e3db..fd3ffc9e 100644 --- a/cli/package.json +++ b/cli/package.json @@ -15,8 +15,7 @@ "check": "npm run lint && npm run test", "build:templates": "node scripts/generate-templates-config.js", "pack:check": "npm pack --dry-run", - "prepublishOnly": "npm run check && npm run pack:check", - "prepare:lib": "git submodule update --init --recursive" + "prepublishOnly": "npm run check && npm run pack:check" }, "keywords": [ "solidity", From 49bfbe13f88dbabb20af3199cc633d7c2145ada8 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 18:03:08 -0400 Subject: [PATCH 16/18] readd prepare:lib --- cli/README.md | 2 +- cli/package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cli/README.md b/cli/README.md index d264e8c9..244d2743 100644 --- a/cli/README.md +++ b/cli/README.md @@ -56,7 +56,7 @@ compose init --name my-hardhat-mocha-ethers \ ``` -`compose templates` prints this information in a CLI-friendly format. +`compose templates` prints this information in a friendly format. ## Notes on `@perfect-abstractions/compose` diff --git a/cli/package.json b/cli/package.json index fd3ffc9e..4c37e3db 100644 --- a/cli/package.json +++ b/cli/package.json @@ -15,7 +15,8 @@ "check": "npm run lint && npm run test", "build:templates": "node scripts/generate-templates-config.js", "pack:check": "npm pack --dry-run", - "prepublishOnly": "npm run check && npm run pack:check" + "prepublishOnly": "npm run check && npm run pack:check", + "prepare:lib": "git submodule update --init --recursive" }, "keywords": [ "solidity", From 9782814f7ddf0040d1c9431d5feadd8f35536945 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 18:43:36 -0400 Subject: [PATCH 17/18] add contributor doc for new template --- website/docs/contribution/cli/_category_.json | 6 + .../docs/contribution/cli/cli-templates.mdx | 250 ++++++++++++++++++ .../documentation/_category_.json | 2 +- 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 website/docs/contribution/cli/_category_.json create mode 100644 website/docs/contribution/cli/cli-templates.mdx diff --git a/website/docs/contribution/cli/_category_.json b/website/docs/contribution/cli/_category_.json new file mode 100644 index 00000000..f0d07382 --- /dev/null +++ b/website/docs/contribution/cli/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Compose CLI", + "position": 6, + "collapsible": true, + "collapsed": true +} \ No newline at end of file diff --git a/website/docs/contribution/cli/cli-templates.mdx b/website/docs/contribution/cli/cli-templates.mdx new file mode 100644 index 00000000..fa4fda53 --- /dev/null +++ b/website/docs/contribution/cli/cli-templates.mdx @@ -0,0 +1,250 @@ +--- +sidebar_position: 3 +title: New Project Templates +description: How to add new project templates to the Compose CLI and keep the template registry in sync. +--- + +import Badge from '@site/src/components/ui/Badge'; +import GradientText from '@site/src/components/ui/GradientText'; +import Callout from '@site/src/components/ui/Callout'; +import StepIndicator from '@site/src/components/docs/StepIndicator'; +import TerminalCommand from '@site/src/components/code/TerminalCommand'; +import DocSubtitle from '@site/src/components/docs/DocSubtitle'; +import RelatedDocs from '@site/src/components/docs/RelatedDocs'; + +# New Template Guide + + + Learn how to add new project templates to the Compose CLI so contributors can scaffold diamonds and example projects consistently. + + +## When to Add a New Template + +Add a new CLI template when you want to: + +- **Showcase a new pattern** (e.g. a new facet layout or diamond configuration). +- **Support a new framework variant** (e.g. a different Hardhat layout). +- **Provide an opinionated starter** (e.g. ERC‑721, ERC‑20, or example applications). + + +Templates should demonstrate **one clear pattern**. Avoid shipping large demo apps or unnecessary dependencies. + + +--- + +## Overview of the Template System + +Templates live in the CLI package under `cli/src/templates`. Each template has: + +- **A template id** – top‑level folder and manifest. +- **One or more variants** – concrete projects for a framework / language combo. +- **A generated registry** – `src/config/templates.json`, built from all manifests. + +' }, + { title: 'Add template.json', description: 'Describe template & variants' }, + { title: 'Create variant directories', description: 'Add Foundry / Hardhat scaffolds' }, + { title: 'Regenerate registry', description: 'Run npm run build:templates' }, + ]} +/> + +--- + +## Prerequisites + +From the `cli` directory: + +```bash +npm install +``` + +
+ +```bash +npm run build:templates +``` + +
+ +You also need: + +- Node.js **20 or higher**. +- A basic understanding of **Foundry** and/or **Hardhat** layouts. (You can always refer to the default template) + +### Test the CLI locally + +```bash +npm link +``` +
+ +This will create a symlink to the CLI in your global `node_modules` directory. + +You can then test the CLI by running: + +```bash +compose --help +``` + + +## 1. Create the Template Folder + +Templates are grouped by **template id**: + +- Root folder: `cli/src/templates/<template-id>` +- Example: `cli/src/templates/erc721` + +Choose an id that is: + +- **Short and descriptive**, e.g. `erc721`, `erc20`, `example-counter`. +- **Stable**, because users reference it via `--template `. + +--- + +## 2. Add `template.json` + +Create a manifest at: + +- `cli/src/templates//template.json` + +This file declares: + +- **id** – must match the folder name and CLI `--template` value. +- **name** – human‑readable label shown in `compose templates`. +- **description** – short explanation of what the template includes. +- **variants** – list of variant ids (see next section). +- **compatibility.frameworks** – supported frameworks (`foundry`, `hardhat`). + +Example: + +```json +{ + "id": "erc721", + "name": "ERC-721 Diamond", + "description": "Diamond project with an ERC-721 facet", + "variants": [ + "erc721-foundry", + "erc721-hardhat-minimal" + ], + "compatibility": { + "frameworks": ["foundry", "hardhat"] + } +} +``` + + +The `npm run build:templates` script validates all `template.json` files and regenerates the registry. If something is wrong, the build will fail. + + + +## 3. Create Variant Directories + +Each **variant id** maps to a concrete folder on disk: + +- **Foundry** + - Variant id: `-foundry` + - Path: `cli/src/templates//foundry` +- **Hardhat (framework‑only)** + - Variant id: `-hardhat` + - Path: `cli/src/templates//hardhat` +- **Hardhat with project type (language/layout)** + - Variant id: `-hardhat-` + - Path: `cli/src/templates//hardhat/ts/` for TypeScript + - Path: `cli/src/templates//hardhat/js/` for JavaScript + +Inside each variant directory, add the full scaffolded project: + +- Contracts, config files, scripts, tests, etc. +- Any `README` or notes specific to that template. + + +The CLI knows the language from the variant path. For Foundry templates, only the **framework** is set. + + +## 4. Regenerate the Template Registry + +Whenever you add or modify templates, rebuild the registry from the `cli` directory by running: + +```bash +npm run build:templates +``` +
+ +- Scans all `src/templates/**/template.json` manifests. +- Validates ids, variants, and compatibility fields. +- Regenerates `src/config/templates.json` used by the CLI. + +If the command fails, fix the manifest or folder layout until the build succeeds. + +--- + +## 5. Verify Your Template + +First, list templates via the local CLI: + +```bash +node index.js templates +``` +
+ + +Check that: + +- Your **template id** appears in the list. +- All **variants** are listed with the expected framework and language. + +Then scaffold a project using your new template: + +```bash +compose init \ + --name my-test-project \ + --template \ + --framework \ + --yes +``` +
+ +From inside the generated project, run the usual framework commands: + +- For **Foundry**: `forge build`, `forge test` +- For **Hardhat**: `npm test`, `npx hardhat test`, etc. + +--- + +## Review Checklist + +Before opening a pull request: + +- **Template structure** + - `cli/src/templates/` exists. + - `template.json` is valid and matches the folder name. + - All variant ids map to real directories. +- **Registry & CLI** + - `npm run build:templates` passes. + - `node index.js templates` shows the new template and variants. + - `node index.js init ...` successfully scaffolds a project. +- **Quality** + - Template files follow existing **code style** and **project layout**. + - Dependencies are minimal and justified. + - Any README or comments clearly explain what the template demonstrates. + +--- + + + diff --git a/website/docs/contribution/documentation/_category_.json b/website/docs/contribution/documentation/_category_.json index a3d2b0bc..8ae1d77c 100644 --- a/website/docs/contribution/documentation/_category_.json +++ b/website/docs/contribution/documentation/_category_.json @@ -1,6 +1,6 @@ { "label": "Documentation", - "position": 5, + "position": 7, "collapsible": true, "collapsed": true } \ No newline at end of file From b5b003ee83ca316196b4adba6f014998326ca81e Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 17 Mar 2026 18:48:48 -0400 Subject: [PATCH 18/18] update page url --- .../docs/contribution/cli/{cli-templates.mdx => templates.mdx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename website/docs/contribution/cli/{cli-templates.mdx => templates.mdx} (100%) diff --git a/website/docs/contribution/cli/cli-templates.mdx b/website/docs/contribution/cli/templates.mdx similarity index 100% rename from website/docs/contribution/cli/cli-templates.mdx rename to website/docs/contribution/cli/templates.mdx