From f4132fc868b9f3c5bb8ee589e1027c76f428d6a8 Mon Sep 17 00:00:00 2001 From: dbeal Date: Tue, 10 Feb 2026 23:01:29 +0900 Subject: [PATCH 01/13] fix(ci): remove claude (#1849) --- .github/workflows/claude-code-review.yml | 54 ------------------------ .github/workflows/claude.yml | 50 ---------------------- 2 files changed, 104 deletions(-) delete mode 100644 .github/workflows/claude-code-review.yml delete mode 100644 .github/workflows/claude.yml diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml deleted file mode 100644 index 2d85029ef..000000000 --- a/.github/workflows/claude-code-review.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Claude Code Review - -on: - pull_request: - types: [opened, synchronize] - # Optional: Only run on specific file changes - # paths: - # - "src/**/*.ts" - # - "src/**/*.tsx" - # - "src/**/*.js" - # - "src/**/*.jsx" - -jobs: - claude-review: - # Optional: Filter by PR author - # if: | - # github.event.pull_request.user.login == 'external-contributor' || - # github.event.pull_request.user.login == 'new-developer' || - # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' - - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - issues: read - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Run Claude Code Review - id: claude-review - uses: anthropics/claude-code-action@v1 - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - prompt: | - Please review this pull request and provide feedback on: - - Code quality and best practices - - Potential bugs or issues - - Performance considerations - - Security concerns - - Test coverage - - Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback. - - Use `gh pr comment --edit-last` with your Bash tool to leave your review as a comment on the PR. - - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options - claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"' - diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml deleted file mode 100644 index ae36c007f..000000000 --- a/.github/workflows/claude.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Claude Code - -on: - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] - issues: - types: [opened, assigned] - pull_request_review: - types: [submitted] - -jobs: - claude: - if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - issues: read - id-token: write - actions: read # Required for Claude to read CI results on PRs - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Run Claude Code - id: claude - uses: anthropics/claude-code-action@v1 - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - - # This is an optional setting that allows Claude to read CI results on PRs - additional_permissions: | - actions: read - - # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. - # prompt: 'Update the pull request description to include a summary of changes.' - - # Optional: Add claude_args to customize behavior and configuration - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options - # claude_args: '--model claude-opus-4-1-20250805 --allowed-tools Bash(gh pr:*)' - From 329c15e875fc94ec7274534ca984e6027fc7fb50 Mon Sep 17 00:00:00 2001 From: dbeal Date: Sun, 15 Feb 2026 12:40:08 +0900 Subject: [PATCH 02/13] feat(cli): sourcify verification (#1850) --- .eslintignore | 1 + packages/cli/src/commands/config/index.ts | 5 + packages/cli/src/commands/verify.ts | 258 +++++++++++++++------- packages/cli/src/index.ts | 5 +- packages/cli/src/settings.ts | 12 + packages/cli/src/util/verify.ts | 98 +++++++- 6 files changed, 291 insertions(+), 88 deletions(-) diff --git a/.eslintignore b/.eslintignore index 20ff18014..18d22a3aa 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,5 @@ .next +artifacts coverage dist next.lock diff --git a/packages/cli/src/commands/config/index.ts b/packages/cli/src/commands/config/index.ts index 680c90aef..e51426177 100644 --- a/packages/cli/src/commands/config/index.ts +++ b/packages/cli/src/commands/config/index.ts @@ -193,6 +193,11 @@ export const commandsConfig: CommandsConfig = { }, ], options: [ + { + flags: '-s --service ', + description: 'Which service to verify on? Either etherscan or sourcify is supported. Specify `all` to verify both.', + defaultValue: 'etherscan', + }, { flags: '-a --api-key ', description: 'Etherscan API key', diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index f646d87c6..ab1df42d4 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -1,3 +1,4 @@ +import _ from 'lodash'; import axios from 'axios'; import Debug from 'debug'; import * as viem from 'viem'; @@ -10,12 +11,26 @@ import { createDefaultReadRegistry } from '../registry'; import { getMainLoader } from '../loader'; -import { logSpinner } from '../util/console'; -import { isVerified } from '../util/verify'; +import { log, logSpinner, spinner } from '../util/console'; +import { + ETHERSCAN_DEFAULT_SERVER_URL, + getSourcifyVerificationEndpoint, + getSourcifyVerificationStatusEndpoint, + isEtherscanVerified, + isSourcifyVerified, + SourcifyVerifyRequest, + SourcifyVerifyResponse, + SourcifyVerifyStatusResponse, +} from '../util/verify'; const debug = Debug('cannon:cli:verify'); -export async function verify(packageRef: string, cliSettings: CliSettings, chainId: number) { +export async function verify( + packageRef: string, + cliSettings: CliSettings, + chainId: number, + service: 'etherscan' | 'sourcify' | 'all' +) { const { fullPackageRef } = new PackageReference(packageRef); // create temporary provider @@ -43,21 +58,13 @@ export async function verify(packageRef: string, cliSettings: CliSettings, chain getMainLoader(cliSettings) ); - const etherscanApi = cliSettings.etherscanApiUrl || 'https://api.etherscan.io/v2/api'; + const etherscanApi = cliSettings.etherscanApiUrl || ETHERSCAN_DEFAULT_SERVER_URL; - if (!etherscanApi) { - throw new Error( - `couldn't find etherscan api url for network with ${chainId}. Please set your etherscan URL with CANNON_ETHERSCAN_API_URL` - ); + if (service === 'etherscan' || (service === 'all' && !cliSettings.etherscanApiKey)) { + log('Using generic API key for Etherscan. If this is incorrect, specify CANNON_ETHERSCAN_API_KEY'); } - if (!cliSettings.etherscanApiKey) { - throw new Error( - 'Etherscan Api Key not supplied. Please set it with --api-key or CANNON_ETHERSCAN_API_KEY environment variable' - ); - } - - const guids: { [c: string]: string } = {}; + const guids: { [c: string]: { [v: string]: string } } = {}; const verifiedAddresses = new Set(); @@ -91,65 +98,109 @@ export async function verify(packageRef: string, cliSettings: CliSettings, chain miscData.artifacts[`${contractInfo.sourceName}:${contractInfo.contractName}`]; if (!contractArtifact) { - logSpinner(`${c}: cannot verify: no contract artifact found`); + logSpinner(`${c} (${contractInfo.address}): cannot verify: no contract artifact found`); continue; } if (!contractArtifact.source) { - logSpinner(`${c}: cannot verify: no source code recorded in deploy data`); + logSpinner(`${c} (${contractInfo.address}): cannot verify: no source code recorded in deploy data`); continue; } - if (await isVerified(contractInfo.address, chainId, etherscanApi, cliSettings.etherscanApiKey)) { - logSpinner(`✅ ${c}: Contract source code already verified`); - await sleep(500); - continue; - } + // supply any linked libraries within the inputs since those are calculated at runtime + const inputData = JSON.parse(contractArtifact.source.input); + _.set(inputData, 'settings.libraries', contractInfo.linkedLibraries); - try { - // supply any linked libraries within the inputs since those are calculated at runtime - const inputData = JSON.parse(contractArtifact.source.input); - inputData.settings.libraries = contractInfo.linkedLibraries; - - const reqData: { [k: string]: string } = { - apikey: cliSettings.etherscanApiKey, - chainid: chainId.toString(), - module: 'contract', - action: 'verifysourcecode', - contractaddress: contractInfo.address, - // need to parse to get the inner structure, then stringify again - sourceCode: JSON.stringify(inputData), - codeformat: 'solidity-standard-json-input', - contractname: `${contractArtifact.sourceName}:${contractArtifact.contractName}`, - compilerversion: 'v' + contractArtifact.source.solcVersion, - - // NOTE: below: yes, the etherscan api is misspelling - constructorArguements: viem - .encodeAbiParameters( - contractArtifact.abi.find((i: viem.AbiItem) => i.type === 'constructor')?.inputs ?? [], - contractInfo.constructorArgs || [] - ) - .slice(2), - }; - - debug('verification request', reqData); - - const res = await axios.post(etherscanApi, reqData, { - headers: { 'content-type': 'application/x-www-form-urlencoded' }, - }); - - if (res.data.status === '0') { - debug('etherscan failed', res.data); - logSpinner(`${c}:\tcannot verify:`, res.data.result); + if (service === 'etherscan' || service === 'all') { + if (await isEtherscanVerified(contractInfo.address, chainId, etherscanApi, cliSettings.etherscanApiKey)) { + logSpinner(`Etherscan: ✅ ${c} (${contractInfo.address}): Contract source code already verified`); } else { - logSpinner(`${c}:\tsubmitted verification (${contractInfo.address})`); - guids[c] = res.data.result; + try { + const reqData: { [k: string]: string } = { + apikey: cliSettings.etherscanApiKey, + chainid: chainId.toString(), + module: 'contract', + action: 'verifysourcecode', + contractaddress: contractInfo.address, + // need to parse to get the inner structure, then stringify again + sourceCode: JSON.stringify(inputData), + codeformat: 'solidity-standard-json-input', + contractname: `${contractArtifact.sourceName}:${contractArtifact.contractName}`, + compilerversion: 'v' + contractArtifact.source.solcVersion, + + // NOTE: below: yes, the etherscan api is misspelling + constructorArguements: viem + .encodeAbiParameters( + contractArtifact.abi.find((i: viem.AbiItem) => i.type === 'constructor')?.inputs ?? [], + contractInfo.constructorArgs || [] + ) + .slice(2), + }; + + debug('verification request', reqData); + + const res = await axios.post(etherscanApi, reqData, { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'User-Agent': 'Cannon CLI', + }, + }); + + if (res.data.status === '0') { + debug('etherscan failed', res.data); + logSpinner(`Etherscan: ${c} (${contractInfo.address}):\tCannot verify:`, res.data.result); + } else { + logSpinner(`Etherscan: ${c} (${contractInfo.address}):\tSubmitted verification (${res.data.result})`); + guids[c]['etherscan'] = res.data.result; + } + } catch (err) { + logSpinner(`Etherscan: ${c} (${contractInfo.address}): Verification request failed:`, err); + } } - } catch (err) { - logSpinner(`verification for ${c} (${contractInfo.address}) failed:`, err); } - await sleep(500); + if (service === 'sourcify' || service === 'all') { + if (await isSourcifyVerified(contractInfo.address, chainId, cliSettings.sourcifyApiUrl || null)) { + logSpinner(`Sourcify: ✅ ${c} (${contractInfo.address}): Contract source code already verified`); + await sleep(500); + continue; + } + + try { + const reqData: SourcifyVerifyRequest = { + stdJsonInput: inputData, + compilerVersion: 'v' + contractArtifact.source.solcVersion, + contractIdentifier: `${contractArtifact.sourceName}:${contractArtifact.contractName}`, + }; + + if (contractInfo.deployTxnHash) { + reqData.creationTransactionHash = contractInfo.deployTxnHash; + } + + debug('sourcify verification request', reqData); + + const res = await axios.post( + getSourcifyVerificationEndpoint(chainId, contractInfo.address, cliSettings.sourcifyApiUrl || null), + reqData, + { + headers: { + 'content-type': 'application/json', + 'User-Agent': 'Cannon CLI', + }, + } + ); + + if (res.status >= 300) { + debug('sourcify failed', res.data); + logSpinner(`Sourcify: ${c} (${contractInfo.address}):\tCannot verify:`, res.data); + } else { + logSpinner(`Sourcify: ${c} (${contractInfo.address}):\tSubmitted verification (${res.data.verificationId})`); + _.set(guids, [c, 'sourcify'], res.data.verificationId); + } + } catch (err) { + logSpinner(`Sourcify: ${c} (${contractInfo.address}): Verification request failed:`, err); + } + } } return {}; @@ -167,31 +218,68 @@ export async function verify(packageRef: string, cliSettings: CliSettings, chain await forPackageTree(runtime, deployData, verifyPackage); // at this point, all contracts should have been submitted for verification. so we are just printing status. + spinner?.update({ text: 'Checking verification status...' }); for (const c in guids) { - for (;;) { - const res = await axios.post( - etherscanApi, - { - apiKey: cliSettings.etherscanApiKey, - module: 'contract', - action: 'checkverifystatus', - guid: guids[c], - }, - { headers: { 'content-type': 'application/x-www-form-urlencoded' } } - ); - - if (res.data.status === '0') { - if (res.data.result === 'Pending in queue') { - await sleep(1000); - } else { - logSpinner(`❌ ${c}`, res.data.result); - logSpinner(res.data); - break; + for (const v in guids[c]) { + for (;;) { + if (v === 'etherscan') { + const res = await axios.post( + etherscanApi, + { + apiKey: cliSettings.etherscanApiKey, + module: 'contract', + action: 'checkverifystatus', + guid: guids[c], + }, + { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'User-Agent': 'Cannon CLI', + }, + } + ); + + if (res.data.status === '0') { + if (res.data.result === 'Pending in queue') { + await sleep(1000); + } else { + logSpinner(`Etherscan: ❌ ${c}`, res.data.result); + logSpinner(res.data); + break; + } + } else { + logSpinner(`Etherscan: ✅ ${c}`); + await sleep(500); + break; + } + } else if (v === 'sourcify') { + const res = await axios.get( + getSourcifyVerificationStatusEndpoint(guids[c][v], cliSettings.sourcifyApiUrl || null), + { + headers: { + 'User-Agent': 'Cannon CLI', + }, + } + ); + + if (res.status === 200) { + if (!res.data.isJobCompleted) { + await sleep(1000); + } else { + if (res.data.error) { + logSpinner(`Sourcify: ❌ ${c}`, res.data.error.message); + logSpinner(res.data.error); + } else { + logSpinner(`Sourcify: ✅ ${c} ${res.data.contract.match}`); + } + break; + } + } else { + logSpinner(`Sourcify: ❌ ${c}: unknown error (${res.status}): ${res.data}`); + await sleep(500); + break; + } } - } else { - logSpinner(`✅ ${c}`); - await sleep(500); - break; } } } diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index ad095f59f..e29ac93e2 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -286,6 +286,9 @@ applyCommandsConfig(program.command('build'), commandsConfig.build) }); applyCommandsConfig(program.command('verify'), commandsConfig.verify).action(async function (packageRef, options) { + if (options.service !== 'etherscan' && options.service !== 'sourcify' && options.service !== 'all') { + throw new Error('--service must be one of "etherscan", "sourcify", or "all"'); + } try { spinner?.update({ text: 'Verifying...' }); const { verify } = await import('./commands/verify'); @@ -296,7 +299,7 @@ applyCommandsConfig(program.command('verify'), commandsConfig.verify).action(asy const cliSettings = resolveCliSettings(options); const { fullPackageRef, chainId } = await getPackageInfo(packageRef, options.chainId, cliSettings.rpcUrl); - await verify(fullPackageRef, cliSettings, chainId); + await verify(fullPackageRef, cliSettings, chainId, options.service); logSpinnerEnd(); } catch (err) { logSpinnerEnd(); diff --git a/packages/cli/src/settings.ts b/packages/cli/src/settings.ts index ad9ffa3a5..a0d344ce0 100644 --- a/packages/cli/src/settings.ts +++ b/packages/cli/src/settings.ts @@ -105,6 +105,11 @@ export type CliSettings = { */ etherscanApiKey: string; + /** + * URL of sourcify API for verification + */ + sourcifyApiUrl?: string; + /** * Whether to run in E2E mode */ @@ -183,6 +188,11 @@ function createCannonSettingsSchema(fileSettings: CliSettings) { .optional() .default(fileSettings.etherscanApiUrl as string), CANNON_ETHERSCAN_API_KEY: z.string().length(34).optional().default(fileSettings.etherscanApiKey), + CANNON_SOURCIFY_API_URL: z + .string() + .url() + .optional() + .default(fileSettings.sourcifyApiUrl as string), CANNON_QUIET: z.boolean().default(fileSettings.quiet || false), CANNON_E2E: z.boolean().default(false), TRACE: z.boolean().default(false), @@ -215,6 +225,7 @@ function computeCliSettings(overrides: Partial = {}): CliSettings { CANNON_REGISTRY_PRIORITY, CANNON_ETHERSCAN_API_URL, CANNON_ETHERSCAN_API_KEY, + CANNON_SOURCIFY_API_URL, CANNON_QUIET, CANNON_E2E, TRACE, @@ -244,6 +255,7 @@ function computeCliSettings(overrides: Partial = {}): CliSettings { registryPriority: CANNON_REGISTRY_PRIORITY, etherscanApiUrl: CANNON_ETHERSCAN_API_URL, etherscanApiKey: CANNON_ETHERSCAN_API_KEY, + sourcifyApiUrl: CANNON_SOURCIFY_API_URL, quiet: CANNON_QUIET, isE2E: CANNON_E2E, trace: TRACE, diff --git a/packages/cli/src/util/verify.ts b/packages/cli/src/util/verify.ts index 2c03587db..47070f6f1 100644 --- a/packages/cli/src/util/verify.ts +++ b/packages/cli/src/util/verify.ts @@ -28,6 +28,48 @@ interface EtherscanGetSourceCodeOkResponse { export type EtherscanGetSourceCodeResponse = EtherscanGetSourceCodeNotOkResponse | EtherscanGetSourceCodeOkResponse; +export type SourcifyVerifyRequest = { + stdJsonInput: object; + compilerVersion: string; + contractIdentifier: string; + creationTransactionHash?: string; +}; + +export type SourcifyVerifyResponse = { + verificationId: string; +}; + +export type SourcifyVerifyStatusResponse = { + isJobCompleted: boolean; + verificationId: string; + error: { + customCode: string; + message: string; + errorId: string; + recompiledCreationCode: string; + recompiledRuntimeCode: string; + onchainCreationCode: string; + onchainRuntimeCode: string; + creationTransactionHash: string; + errorData: object; + }; + jobStartTime: string; + jobFinishTime: string; + compilationTime: string; + contract: { + match: 'exact_match' | 'match' | null; + creationMatch: 'exact_match' | 'match' | null; + runtimeMatch: 'exact_match' | 'match' | null; + chainId: string; + address: string; + verifiedAt: string; + matchId: string; + }; +}; + +export const ETHERSCAN_DEFAULT_SERVER_URL = 'https://api.etherscan.io/v2/api'; +export const SOURCIFY_DEFAULT_SERVER_URL = 'https://sourcify.dev/server'; + /** * Check if a smart contract is verified on Etherscan. * @link https://docs.etherscan.io/api-endpoints/contracts#get-contract-source-code-for-verified-contract-source-codes @@ -36,8 +78,12 @@ export type EtherscanGetSourceCodeResponse = EtherscanGetSourceCodeNotOkResponse * @param apiKey - Etherscan API Key. * @returns True if the contract is verified, false otherwise. */ - -export async function isVerified(address: string, chainId: number, apiUrl: string, apiKey: string): Promise { +export async function isEtherscanVerified( + address: string, + chainId: number, + apiUrl: string, + apiKey: string +): Promise { const parameters = new URLSearchParams({ apikey: apiKey, chainid: chainId.toString(), @@ -69,3 +115,51 @@ export async function isVerified(address: string, chainId: number, apiUrl: strin return false; } } + +/** + * Check if a smart contract is verified on Sourcify. + * @link https://docs.sourcify.dev/docs/api/#/Contract%20Lookup/get-contract + * @param address - The address of the smart contract. + * @param chainId - The chainId of the smart contract. + * @param serverUrl - Sourcify API URL. + * @returns True if the contract is verified, false otherwise. + */ +export async function isSourcifyVerified(address: string, chainId: number, serverUrl: string | null): Promise { + try { + const response = await fetch(`${serverUrl || SOURCIFY_DEFAULT_SERVER_URL}/v2/contract/${chainId}/${address}`); + + // sourcify only returns 200 when the contract is verified, and 404 if its not + if (response.status === 404) { + return false; + } else if (response.status === 200) { + return true; + } else { + throw new Error( + `Sourcify returned error while checking verification status (${response.status}):` + (await response.text()) + ); + } + } catch (e) { + throw new Error('Could not check verification status on Sourcify: ' + e); + } +} + +/** + * Get the endpoint needed to do an actual verification with sourcify + * @param address - The address of the smart contract. + * @param chainId - The chainId of the smart contract. + * @param serverUrl - Sourcify API URL. + * @returns The URL to POST to + */ +export function getSourcifyVerificationEndpoint(chainId: number, address: string, serverOverride: string | null) { + return `${serverOverride || SOURCIFY_DEFAULT_SERVER_URL}/v2/verify/${chainId}/${address}`; +} + +/** + * Get the endpoint needed to do an actual verification with sourcify + * @param verificationId - The ID received from the verification endpoint + * @param serverUrl - Sourcify API URL. + * @returns The URL to GET + */ +export function getSourcifyVerificationStatusEndpoint(verificationId: string, serverOverride: string | null) { + return `${serverOverride || SOURCIFY_DEFAULT_SERVER_URL}/v2/verify/${verificationId}`; +} From 8e2a08f5cfcf2849cb16ebfae046365646110af9 Mon Sep 17 00:00:00 2001 From: dbeal Date: Sun, 15 Feb 2026 12:40:52 +0900 Subject: [PATCH 03/13] fix(cli): viair does not work properly with `cannon verify` (#1847) --- packages/cli/src/foundry.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/foundry.ts b/packages/cli/src/foundry.ts index bbadcdfef..f6548985c 100644 --- a/packages/cli/src/foundry.ts +++ b/packages/cli/src/foundry.ts @@ -1,9 +1,9 @@ -import path from 'path'; +import { ContractArtifact } from '@usecannon/builder'; +import Debug from 'debug'; import fs from 'fs-extra'; import { glob } from 'glob'; -import { ContractArtifact } from '@usecannon/builder'; import _ from 'lodash'; -import Debug from 'debug'; +import path from 'path'; import { execPromise } from './helpers'; import { warn } from './util/console'; @@ -121,6 +121,7 @@ export async function getFoundryArtifact(name: string, baseDir = '', includeSour language: 'Solidity', sources, settings: { + ...artifact.metadata.settings, optimizer: artifact.metadata.settings.optimizer, evmVersion: evmVersionInfo, remappings: artifact.metadata.settings.remappings, From f74cc1a12b634972d40fed3d540cd7479a56f04f Mon Sep 17 00:00:00 2001 From: shubham shinde Date: Sun, 15 Feb 2026 09:18:08 +0530 Subject: [PATCH 04/13] Fix Select Safe dialog overflow (#1852) --- packages/website/src/features/Deploy/SafeAddressInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/website/src/features/Deploy/SafeAddressInput.tsx b/packages/website/src/features/Deploy/SafeAddressInput.tsx index cb755df98..cd91ff528 100644 --- a/packages/website/src/features/Deploy/SafeAddressInput.tsx +++ b/packages/website/src/features/Deploy/SafeAddressInput.tsx @@ -252,7 +252,7 @@ export function SafeAddressInput() { onOpenChange={setIsDialogOpen} modal={false} > - + Select Safe From 5fa7b94211f00170f956cdde5897c8925298137f Mon Sep 17 00:00:00 2001 From: saturn-dbeal Date: Fri, 6 Mar 2026 14:41:38 +0900 Subject: [PATCH 05/13] feat(cli): add --ipfs-superfluous flag to clean command (#1854) --- packages/cli/src/commands/clean.test.ts | 217 +++++++++++++++++++++- packages/cli/src/commands/clean.ts | 202 ++++++++++++++++++++ packages/cli/src/commands/config/index.ts | 4 + packages/cli/src/index.ts | 21 ++- 4 files changed, 439 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/commands/clean.test.ts b/packages/cli/src/commands/clean.test.ts index 67e68a7c5..e9e5e2e54 100644 --- a/packages/cli/src/commands/clean.test.ts +++ b/packages/cli/src/commands/clean.test.ts @@ -1,4 +1,4 @@ -import { clean } from './clean'; +import { clean, cleanOrphanedIpfs } from './clean'; import fs from 'node:fs/promises'; import { existsSync } from 'node:fs'; import prompts from 'prompts'; @@ -61,3 +61,218 @@ describe('clean function', () => { expect(fs.rm).not.toHaveBeenCalled(); }); }); + +describe('cleanOrphanedIpfs function', () => { + let consoleLogSpy: jest.SpyInstance; + + beforeEach(() => { + consoleLogSpy = jest.spyOn(console, 'log'); + }); + + afterEach(() => { + consoleLogSpy.mockRestore(); + jest.resetAllMocks(); + }); + + it('should return success with no deletions when no orphaned files exist', async () => { + // Mock tags directory with one tag + (existsSync as jest.Mock).mockImplementation((path: string) => { + if (path.includes('tags')) return true; + if (path.includes('ipfs_cache')) return true; + return false; + }); + + // @ts-ignore + jest.spyOn(fs, 'readdir').mockImplementation((dir: string) => { + if (dir.includes('tags')) { + return Promise.resolve(['package_1.0.0_1-main.txt', 'package_1.0.0_1-main.txt.meta']); + } + if (dir.includes('ipfs_cache')) { + // Return files that match the tag's IPFS URLs + // ipfs://QmXyz -> 58cd78e4d20301f9456940b3f1a735b5-qmxyz.json + // ipfs://QmMeta -> 1cdfa4521e3d781a0da1a3d3ff4eeece-qmmeta.json + return Promise.resolve([ + '58cd78e4d20301f9456940b3f1a735b5-qmxyz.json', + '1cdfa4521e3d781a0da1a3d3ff4eeece-qmmeta.json', + ]); + } + return Promise.resolve([]); + }); + + // Mock tag file contents and cache file contents + jest.spyOn(fs, 'readFile').mockImplementation((path: any) => { + const pathStr = path.toString(); + if (pathStr.includes('.txt') && !pathStr.includes('.meta')) { + return Promise.resolve('ipfs://QmXyz') as any; + } + if (pathStr.includes('.meta')) { + return Promise.resolve('ipfs://QmMeta') as any; + } + // Cache files - return JSON without nested IPFS URLs + if (pathStr.includes('ipfs_cache')) { + return Promise.resolve('{"state": {}}') as any; + } + return Promise.resolve('') as any; + }); + + const result = await cleanOrphanedIpfs(false); + + expect(result.success).toBe(true); + expect(result.stats.orphanedFiles).toBe(0); + }); + + it('should identify and delete orphaned IPFS files', async () => { + (existsSync as jest.Mock).mockReturnValue(true); + + // @ts-ignore + jest.spyOn(fs, 'readdir').mockImplementation((dir: string) => { + if (dir.includes('tags')) { + return Promise.resolve(['package_1.0.0_1-main.txt']); + } + if (dir.includes('ipfs_cache')) { + // ipfs://QmXyz -> 58cd78e4d20301f9456940b3f1a735b5-qmxyz.json (referenced) + // ipfs://QmAbc -> d7195b608c408f59397fc013eba8fef4-qmabc.json (orphaned) + return Promise.resolve([ + '58cd78e4d20301f9456940b3f1a735b5-qmxyz.json', + 'd7195b608c408f59397fc013eba8fef4-qmabc.json', + ]); + } + return Promise.resolve([]); + }); + + // Mock tag file contents and cache file contents + jest.spyOn(fs, 'readFile').mockImplementation((path: any) => { + const pathStr = path.toString(); + if (pathStr.includes('.txt')) { + return Promise.resolve('ipfs://QmXyz') as any; + } + // Cache files - no nested IPFS URLs + if (pathStr.includes('ipfs_cache')) { + return Promise.resolve('{"state": {}}') as any; + } + return Promise.resolve('') as any; + }); + + // Mock unlink + jest.spyOn(fs, 'unlink').mockImplementation(() => Promise.resolve()); + + const result = await cleanOrphanedIpfs(false); + + expect(result.success).toBe(true); + expect(result.stats.totalFiles).toBe(2); + expect(result.stats.orphanedFiles).toBe(1); + expect(result.stats.deletedFiles).toBe(1); + }); + + it('should not delete files when user cancels confirmation', async () => { + (existsSync as jest.Mock).mockReturnValue(true); + (prompts as unknown as jest.Mock).mockResolvedValue({ value: false }); + + // @ts-ignore + jest.spyOn(fs, 'readdir').mockImplementation((dir: string) => { + if (dir.includes('tags')) { + return Promise.resolve(['package_1.0.0_1-main.txt']); + } + if (dir.includes('ipfs_cache')) { + // Only orphaned file: ipfs://QmAbc + return Promise.resolve(['d7195b608c408f59397fc013eba8fef4-qmabc.json']); + } + return Promise.resolve([]); + }); + + jest.spyOn(fs, 'readFile').mockImplementation((path: any) => { + const pathStr = path.toString(); + if (pathStr.includes('.txt')) { + return Promise.resolve('ipfs://QmXyz') as any; + } + // Cache files - no nested IPFS URLs + if (pathStr.includes('ipfs_cache')) { + return Promise.resolve('{"state": {}}') as any; + } + return Promise.resolve('') as any; + }); + + const unlinkSpy = jest.spyOn(fs, 'unlink').mockImplementation(() => Promise.resolve()); + + const result = await cleanOrphanedIpfs(true); + + expect(result.success).toBe(false); + expect(unlinkSpy).not.toHaveBeenCalled(); + }); + + it('should preserve second-order IPFS dependencies', async () => { + (existsSync as jest.Mock).mockReturnValue(true); + + // We have: + // - Tag references ipfs://QmRoot + // - QmRoot's cache file contains a reference to ipfs://QmNested + // - QmNested's cache file contains a reference to ipfs://QmDeep + // - ipfs://QmOrphan is not referenced by anything + // All of QmRoot, QmNested, QmDeep should be kept; QmOrphan should be deleted + + // eslint-disable-next-line @typescript-eslint/no-var-requires + const crypto = require('crypto'); + const hashOf = (cid: string) => { + const md5 = crypto.createHash('md5').update(cid).digest('hex'); + return `${md5}-${cid.toLowerCase()}`; + }; + + const rootHash = hashOf('QmRoot'); + const nestedHash = hashOf('QmNested'); + const deepHash = hashOf('QmDeep'); + const orphanHash = hashOf('QmOrphan'); + + // @ts-ignore + jest.spyOn(fs, 'readdir').mockImplementation((dir: string) => { + if (dir.includes('tags')) { + return Promise.resolve(['package_1.0.0_1-main.txt']); + } + if (dir.includes('ipfs_cache')) { + return Promise.resolve([`${rootHash}.json`, `${nestedHash}.json`, `${deepHash}.json`, `${orphanHash}.json`]); + } + return Promise.resolve([]); + }); + + jest.spyOn(fs, 'readFile').mockImplementation((filePath: any) => { + const pathStr = filePath.toString(); + // Tag file + if (pathStr.includes('.txt')) { + return Promise.resolve('ipfs://QmRoot') as any; + } + // Cache files with nested IPFS references + if (pathStr.includes(rootHash)) { + return Promise.resolve( + JSON.stringify({ + state: { 'deploy.Contract': { url: 'ipfs://QmNested' } }, + }) + ) as any; + } + if (pathStr.includes(nestedHash)) { + return Promise.resolve( + JSON.stringify({ + state: { 'deploy.Sub': { metaUrl: 'ipfs://QmDeep' } }, + }) + ) as any; + } + if (pathStr.includes(deepHash)) { + return Promise.resolve(JSON.stringify({ state: {} })) as any; + } + if (pathStr.includes(orphanHash)) { + return Promise.resolve(JSON.stringify({ state: {} })) as any; + } + return Promise.resolve('') as any; + }); + + jest.spyOn(fs, 'unlink').mockImplementation(() => Promise.resolve()); + + const result = await cleanOrphanedIpfs(false); + + expect(result.success).toBe(true); + expect(result.stats.totalFiles).toBe(4); + // QmRoot (direct), QmNested (second-order), QmDeep (third-order) = 3 referenced + expect(result.stats.referencedFiles).toBe(3); + // Only QmOrphan should be orphaned + expect(result.stats.orphanedFiles).toBe(1); + expect(result.stats.deletedFiles).toBe(1); + }); +}); diff --git a/packages/cli/src/commands/clean.ts b/packages/cli/src/commands/clean.ts index 6389c030e..0ca463605 100644 --- a/packages/cli/src/commands/clean.ts +++ b/packages/cli/src/commands/clean.ts @@ -7,6 +7,8 @@ import prompts from 'prompts'; import { log } from '../util/console'; import { resolveCliSettings } from '../settings'; +import { CliLoader } from '../loader'; + const debug = Debug('cannon:cli:clean'); export async function clean(confirm = true) { @@ -61,3 +63,203 @@ export async function clean(confirm = true) { return true; } + +/** + * Read all tag files and extract referenced IPFS URLs + */ +async function getReferencedIpfsUrls(tagsDir: string): Promise> { + const referencedUrls = new Set(); + + if (!existsSync(tagsDir)) { + return referencedUrls; + } + + const tagFiles = await fs.readdir(tagsDir); + + for (const file of tagFiles) { + // Process both .txt files (main package URL) and .meta files (metadata URL) + if (!file.endsWith('.txt') && !file.endsWith('.meta')) continue; + + const filePath = path.join(tagsDir, file); + const content = await fs.readFile(filePath, 'utf-8'); + const url = content.trim(); + + if (url.startsWith('ipfs://')) { + referencedUrls.add(url); + debug(`Found referenced URL in ${file}: ${url}`); + } + } + + return referencedUrls; +} + +/** + * Extract all IPFS URLs from a string (e.g., JSON content of a cached IPFS file). + * Looks for ipfs://Qm... and ipfs://bafy... patterns. + */ +function extractIpfsUrls(content: string): Set { + const urls = new Set(); + const regex = /ipfs:\/\/[A-Za-z0-9]+/g; + let match; + while ((match = regex.exec(content)) !== null) { + urls.add(match[0]); + } + return urls; +} + +/** + * Recursively resolve all IPFS dependencies starting from a set of root URLs. + * Reads the content of each referenced IPFS cache file and looks for additional + * IPFS URLs, building a complete dependency graph. + */ +async function resolveIpfsDependencies(rootUrls: Set, ipfsCacheDir: string): Promise> { + const allReferencedUrls = new Set(rootUrls); + const queue = [...rootUrls]; + + while (queue.length > 0) { + const url = queue.pop()!; + const cacheHash = CliLoader.getCacheHash(url); + const cacheFile = path.join(ipfsCacheDir, `${cacheHash}.json`); + + try { + const content = await fs.readFile(cacheFile, 'utf-8'); + const nestedUrls = extractIpfsUrls(content); + + for (const nestedUrl of nestedUrls) { + if (!allReferencedUrls.has(nestedUrl)) { + allReferencedUrls.add(nestedUrl); + queue.push(nestedUrl); + debug(`Found nested IPFS dependency: ${nestedUrl} (from ${url})`); + } + } + } catch { + // Cache file may not exist locally, that's fine + debug(`Could not read cache file for ${url}, skipping dependency scan`); + } + } + + return allReferencedUrls; +} + +/** + * Get all IPFS cache files + */ +async function getIpfsCacheFiles(ipfsCacheDir: string): Promise { + if (!existsSync(ipfsCacheDir)) { + return []; + } + + const files = await fs.readdir(ipfsCacheDir); + return files.filter((f) => f.endsWith('.json')); +} + +export interface CleanIpfsStats { + totalFiles: number; + referencedFiles: number; + orphanedFiles: number; + deletedFiles: number; + failedFiles: number; +} + +/** + * Clean orphaned IPFS packages (packages not referenced by any tag) + */ +export async function cleanOrphanedIpfs(confirm = true): Promise<{ success: boolean; stats: CleanIpfsStats }> { + const settings = resolveCliSettings(); + + const tagsDir = path.join(settings.cannonDirectory, 'tags'); + const ipfsCacheDir = path.join(settings.cannonDirectory, 'ipfs_cache'); + + const stats: CleanIpfsStats = { + totalFiles: 0, + referencedFiles: 0, + orphanedFiles: 0, + deletedFiles: 0, + failedFiles: 0, + }; + + // Get all directly referenced IPFS URLs from tags + const directUrls = await getReferencedIpfsUrls(tagsDir); + debug(`Found ${directUrls.size} directly referenced IPFS URLs in tags`); + + // Recursively resolve all IPFS dependencies (second-order and deeper) + const referencedUrls = await resolveIpfsDependencies(directUrls, ipfsCacheDir); + debug(`Found ${referencedUrls.size} total referenced IPFS URLs (including nested dependencies)`); + + // Get all IPFS cache files + const cacheFiles = await getIpfsCacheFiles(ipfsCacheDir); + stats.totalFiles = cacheFiles.length; + debug(`Found ${cacheFiles.length} IPFS cache files`); + + // Build a set of referenced cache hashes for quick lookup + const referencedHashes = new Set(); + for (const url of referencedUrls) { + referencedHashes.add(CliLoader.getCacheHash(url)); + } + + // Find orphaned files (not referenced by any tag) + const orphanedFiles: string[] = []; + + for (const file of cacheFiles) { + // Extract the hash part from the filename (format: {md5}-{cid}.json) + const hashPart = file.replace('.json', ''); + + if (referencedHashes.has(hashPart)) { + stats.referencedFiles++; + debug(`File ${file} is referenced, keeping`); + } else { + orphanedFiles.push(file); + stats.orphanedFiles++; + debug(`File ${file} is orphaned, marking for deletion`); + } + } + + if (stats.orphanedFiles === 0) { + log('No orphaned IPFS packages found.'); + return { success: true, stats }; + } + + // Show what will be deleted + log(`Found ${stats.orphanedFiles} orphaned IPFS package(s) (out of ${stats.totalFiles} total):`); + for (const file of orphanedFiles) { + log(` - ${file}`); + } + log(); + + if (confirm) { + const confirmation = await prompts({ + type: 'confirm', + name: 'value', + message: 'Delete these orphaned IPFS packages?', + initial: false, + }); + + if (!confirmation.value) { + log('Cancelled.'); + return { success: false, stats }; + } + } + + // Delete orphaned files + for (const file of orphanedFiles) { + const filePath = path.join(ipfsCacheDir, file); + try { + await fs.unlink(filePath); + stats.deletedFiles++; + debug(`Deleted ${file}`); + } catch (error: unknown) { + stats.failedFiles++; + if (error instanceof Error) { + debug(`Failed to delete ${file}: ${error.message}`); + } + } + } + + log(); + log(`Deleted ${stats.deletedFiles} orphaned IPFS package(s).`); + if (stats.failedFiles > 0) { + log(`Failed to delete ${stats.failedFiles} file(s).`); + } + + return { success: true, stats }; +} diff --git a/packages/cli/src/commands/config/index.ts b/packages/cli/src/commands/config/index.ts index e51426177..80525ee47 100644 --- a/packages/cli/src/commands/config/index.ts +++ b/packages/cli/src/commands/config/index.ts @@ -795,6 +795,10 @@ export const commandsConfig: CommandsConfig = { flags: '--no-confirm', description: 'Do not ask for confirmation before deleting', }, + { + flags: '--ipfs', + description: 'Only delete orphaned IPFS packages not referenced by any tag', + }, ], }, plugin: { diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index e29ac93e2..083369831 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -915,12 +915,25 @@ applyCommandsConfig(program.command('setup'), commandsConfig.setup).action(async } }); -applyCommandsConfig(program.command('clean'), commandsConfig.clean).action(async function ({ noConfirm }) { +applyCommandsConfig(program.command('clean'), commandsConfig.clean).action(async function (options: { + confirm?: boolean; + ipfs?: boolean; +}) { try { logSpinnerEnd(); - const { clean } = await import('./commands/clean'); - const executed = await clean(!noConfirm); - if (executed) log('Complete!'); + const { clean, cleanOrphanedIpfs } = await import('./commands/clean'); + + // With --no-confirm flag, Commander sets confirm to false + // Without the flag, confirm is undefined (default to true for confirmation) + const shouldConfirm = options.confirm !== false; + + if (options.ipfs) { + const { success } = await cleanOrphanedIpfs(shouldConfirm); + if (success) log('Complete!'); + } else { + const executed = await clean(shouldConfirm); + if (executed) log('Complete!'); + } logSpinnerEnd(); } catch (err) { From 8595bf3859b0a38ea4a5fac0d948d27ec4153ae4 Mon Sep 17 00:00:00 2001 From: dbeal Date: Sat, 7 Mar 2026 08:45:44 +0900 Subject: [PATCH 06/13] fix(builder): deploy `importExisting` was not properly handling create2 contracts (#1853) --- .eslintignore | 1 + packages/builder/src/steps/deploy.test.ts | 95 +++++++++++++++++++++++ packages/builder/src/steps/deploy.ts | 31 +++++--- 3 files changed, 117 insertions(+), 10 deletions(-) diff --git a/.eslintignore b/.eslintignore index 18d22a3aa..f9e045301 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,3 +10,4 @@ packages/hardhat-cannon/dist packages/website/out typechain-types typechain +artifacts \ No newline at end of file diff --git a/packages/builder/src/steps/deploy.test.ts b/packages/builder/src/steps/deploy.test.ts index 5b30e6fdc..b5def0c24 100644 --- a/packages/builder/src/steps/deploy.test.ts +++ b/packages/builder/src/steps/deploy.test.ts @@ -424,4 +424,99 @@ describe('steps/deploy.ts', () => { }); }); }); + + describe('importExisting', () => { + it('throws if more than one existing key supplied', async () => { + await expect(() => + action.importExisting(fakeRuntime, fakeCtx, {} as any, { currentLabel: 'foo' } as any, ['one', 'two']) + ).rejects.toThrow('can only be deployed on one transaction'); + }); + + it('works for normal contract creation', async () => { + const rx = fixtureTransactionReceipt(); + const tx = { + hash: rx.transactionHash, + blockNumber: 1234, + }; + + jest.mocked(fakeRuntime.provider.getTransaction).mockResolvedValue(tx as any); + jest.mocked(fakeRuntime.provider.getTransactionReceipt).mockResolvedValue(rx); + jest.mocked(fakeRuntime.provider.getBlock).mockResolvedValue({ timestamp: 1234123412 } as any); + + const result = await action.importExisting( + fakeRuntime, + fakeCtx, + { artifact: 'hello' } as any, + { currentLabel: 'contract.Woot' } as any, + [rx.transactionHash] + ); + + expect(result).toMatchObject({ + contracts: { + Woot: { + address: rx.contractAddress, + deployTxnHash: rx.transactionHash, + }, + }, + }); + }); + + it('works for create2 contract creation', async () => { + const rx = fixtureTransactionReceipt({ contractAddress: null }); + const tx = { + hash: rx.transactionHash, + blockNumber: 1234, + to: '0x1234567890123456789012345678901234567890', + input: viem.concat([viem.zeroHash, '0x1234']), + }; + + jest.mocked(fakeRuntime.provider.getTransaction).mockResolvedValue(tx as any); + jest.mocked(fakeRuntime.provider.getTransactionReceipt).mockResolvedValue(rx); + jest.mocked(fakeRuntime.provider.getBlock).mockResolvedValue({ timestamp: 1234123412 } as any); + + // calculate expected address + const expectedAddress = viem.getContractAddress({ + opcode: 'CREATE2', + from: tx.to as any, + salt: viem.zeroHash, + bytecode: '0x1234', + }); + + const result = await action.importExisting( + fakeRuntime, + fakeCtx, + { artifact: 'hello' } as any, + { currentLabel: 'contract.Woot' } as any, + [rx.transactionHash] + ); + + expect(result).toMatchObject({ + contracts: { + Woot: { + address: expectedAddress, + deployTxnHash: rx.transactionHash, + }, + }, + }); + }); + + it('throws if transaction not a contract creation', async () => { + const rx = fixtureTransactionReceipt({ contractAddress: null }); + const tx = { + hash: rx.transactionHash, + blockNumber: 1234, + to: '0x1234567890123456789012345678901234567890', + input: '0x', + }; + + jest.mocked(fakeRuntime.provider.getTransaction).mockResolvedValue(tx as any); + jest.mocked(fakeRuntime.provider.getTransactionReceipt).mockResolvedValue(rx); + + await expect(() => + action.importExisting(fakeRuntime, fakeCtx, { artifact: 'hello' } as any, { currentLabel: 'contract.Woot' } as any, [ + rx.transactionHash, + ]) + ).rejects.toThrow('does not appear to deploy a contract'); + }); + }); }); diff --git a/packages/builder/src/steps/deploy.ts b/packages/builder/src/steps/deploy.ts index 15eeb4c7d..efb77f911 100644 --- a/packages/builder/src/steps/deploy.ts +++ b/packages/builder/src/steps/deploy.ts @@ -121,7 +121,7 @@ function generateOutputs( deployedOn: currentLabel!, highlight: config.highlight, gasUsed: Number(deployTxn?.gasUsed) || 0, - gasCost: deployTxn?.effectiveGasPrice.toString() || '0', + gasCost: deployTxn?.effectiveGasPrice?.toString() || '0', }, }, }; @@ -428,19 +428,30 @@ const deploySpec = { const artifactData = await runtime.getArtifact!(config.artifact); - const txn = await runtime.provider.getTransactionReceipt({ hash: existingKeys[0] as viem.Hash }); - - // When a CREATE2 contract is deployed, it doesnt output the contractAddress property. - // However the txn will emit events from the deployed contract address which can be found in the txn logs - const contractAddress = config.create2 ? txn.logs[0].address : txn.contractAddress; - - if (!viem.isAddress(contractAddress as string)) { - throw new Error('imported txn does not appear to deploy a contract'); + const txn = await runtime.provider.getTransaction({ hash: existingKeys[0] as viem.Hash }); + const receipt = await runtime.provider.getTransactionReceipt({ hash: existingKeys[0] as viem.Hash }); + + // We need to compute from the import data + let contractAddress; + // In the case that the contract address is given in the transaction receipt: It was a create (1) transaction + if (receipt.contractAddress) { + contractAddress = receipt.contractAddress; + // in the case that the contract address is *NOT* given, its CREATE2 through arachnid (or, not a contract creation transaction at all). + } else if (txn.to && txn.input && txn.input.length > 66) { + // Note: the `from` address is actually the `to` address here because this function wants the address of the contract executing the deployment of the contract + contractAddress = viem.getContractAddress({ + opcode: 'CREATE2', + from: txn.to, + salt: viem.sliceHex(txn.input, 0, 32), + bytecode: viem.sliceHex(txn.input, 32), + }); + } else { + throw new Error('The transaction hash you provided does not appear to deploy a contract'); } const block = await runtime.provider.getBlock({ blockNumber: txn?.blockNumber }); - return generateOutputs(config, ctx, artifactData, txn, block, contractAddress!, packageState.currentLabel); + return generateOutputs(config, ctx, artifactData, receipt, block, contractAddress!, packageState.currentLabel); }, } satisfies CannonAction; From 8faef0db550b252442fc8993c0933b1a499f3875 Mon Sep 17 00:00:00 2001 From: dbeal Date: Sat, 7 Mar 2026 12:46:40 +0900 Subject: [PATCH 07/13] fix(builder): early return from `computeTemplateAccesses` (#1846) Co-authored-by: saturn --- packages/builder/src/access-recorder.test.ts | 53 +++++++-------- packages/builder/src/access-recorder.ts | 69 +++++++++++++------- packages/builder/src/actions.ts | 4 +- packages/builder/src/definition.ts | 46 +++++++++---- packages/builder/src/index.ts | 2 +- packages/builder/src/steps/clone.test.ts | 3 +- packages/builder/src/steps/clone.ts | 24 +++---- packages/builder/src/steps/deploy.test.ts | 3 +- packages/builder/src/steps/deploy.ts | 30 ++++----- packages/builder/src/steps/diamond.ts | 14 ++-- packages/builder/src/steps/invoke.test.ts | 3 +- packages/builder/src/steps/invoke.ts | 32 ++++----- packages/builder/src/steps/pull.ts | 8 +-- packages/builder/src/steps/router.ts | 12 ++-- packages/builder/src/steps/var.ts | 8 +-- packages/cli/src/custom-steps/run.ts | 12 ++-- 16 files changed, 176 insertions(+), 147 deletions(-) diff --git a/packages/builder/src/access-recorder.test.ts b/packages/builder/src/access-recorder.test.ts index 3c9372f43..f38652773 100644 --- a/packages/builder/src/access-recorder.test.ts +++ b/packages/builder/src/access-recorder.test.ts @@ -1,51 +1,52 @@ -import { computeTemplateAccesses } from './access-recorder'; +import { AccessRecorderEngine } from './access-recorder'; describe('access-recorder.ts', () => { + const engine = new AccessRecorderEngine([]); describe('computeTemplateAccesses()', () => { it('computes dependency with addition operation', () => { - expect(computeTemplateAccesses('<%= settings.value1 + settings.value2 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.value1 + settings.value2 %>')).toEqual({ accesses: ['settings.value1', 'settings.value2'], unableToCompute: false, }); }); it('computes dependency with addition operation using extras', () => { - expect(computeTemplateAccesses('<%= extras.value1 + extras.value2 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= extras.value1 + extras.value2 %>')).toEqual({ accesses: ['extras.value1', 'extras.value2'], unableToCompute: false, }); }); it('computes dependency with usage of allowed global variables', () => { - expect(computeTemplateAccesses('<%= parseEther(String(0.3)) %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= parseEther(String(0.3)) %>')).toEqual({ accesses: [], unableToCompute: false, }); }); it('computes simple addition', () => { - expect(computeTemplateAccesses('<%= 1 + 1 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= 1 + 1 %>')).toEqual({ accesses: [], unableToCompute: false, }); }); it('computes dependency with subtraction operation', () => { - expect(computeTemplateAccesses('<%= settings.value1 - settings.value2 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.value1 - settings.value2 %>')).toEqual({ accesses: ['settings.value1', 'settings.value2'], unableToCompute: false, }); }); it('computes dependency with multiplication operation', () => { - expect(computeTemplateAccesses('<%= settings.value1 * settings.value2 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.value1 * settings.value2 %>')).toEqual({ accesses: ['settings.value1', 'settings.value2'], unableToCompute: false, }); }); it('computes dependency with division operation', () => { - expect(computeTemplateAccesses('<%= settings.value1 / settings.value2 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.value1 / settings.value2 %>')).toEqual({ accesses: ['settings.value1', 'settings.value2'], unableToCompute: false, }); @@ -53,7 +54,7 @@ describe('access-recorder.ts', () => { it('computes dependency with complex math operation', () => { expect( - computeTemplateAccesses('<%= (settings.value1 + settings.value2) * settings.value3 / settings.value4 %>') + engine.computeTemplateAccesses('<%= (settings.value1 + settings.value2) * settings.value3 / settings.value4 %>') ).toEqual({ accesses: ['settings.value1', 'settings.value2', 'settings.value3', 'settings.value4'], unableToCompute: false, @@ -61,14 +62,14 @@ describe('access-recorder.ts', () => { }); it('computes multiple dependencies on different template tags', () => { - expect(computeTemplateAccesses('<%= settings.woot %>-<%= settings.woot2 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.woot %>-<%= settings.woot2 %>')).toEqual({ accesses: ['settings.woot', 'settings.woot2'], unableToCompute: false, }); }); it('computes simple dependency', () => { - expect(computeTemplateAccesses('<%= settings.woot %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.woot %>')).toEqual({ accesses: ['settings.woot'], unableToCompute: false, }); @@ -76,7 +77,7 @@ describe('access-recorder.ts', () => { it('computes array dependency', () => { expect( - computeTemplateAccesses( + engine.computeTemplateAccesses( '["<%= settings.camelotSwapPublisherAdmin1 %>","<%= settings.camelotSwapPublisherAdmin2 %>"]' ) ).toEqual({ @@ -86,7 +87,7 @@ describe('access-recorder.ts', () => { }); it('computes dependency using simple CannonHelperContext', () => { - expect(computeTemplateAccesses('<%= parseEther(settings.woot) %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= parseEther(settings.woot) %>')).toEqual({ accesses: ['settings.woot'], unableToCompute: false, }); @@ -94,7 +95,7 @@ describe('access-recorder.ts', () => { it('computes dependency using complex CannonHelperContext', () => { expect( - computeTemplateAccesses( + engine.computeTemplateAccesses( '<%= defaultAbiCoder.encode(parseEther(settings.woot)) %> + <%= defaultAbiCoder.decode(contracts.compound) %>' ) ).toEqual({ @@ -106,28 +107,28 @@ describe('access-recorder.ts', () => { describe('computeTemplateAccesses() syntax validation', () => { it('handles invalid template syntax - unmatched brackets', () => { - expect(computeTemplateAccesses('<%= settings.value) %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.value) %>')).toEqual({ accesses: [], unableToCompute: true, }); }); it('handles empty template tags', () => { - expect(computeTemplateAccesses('<%=%>')).toEqual({ + expect(engine.computeTemplateAccesses('<%=%>')).toEqual({ accesses: [], unableToCompute: true, }); }); it('handles multiple template tags with mixed validity', () => { - expect(computeTemplateAccesses('<%= settings.valid %> and <% invalid.syntax')).toEqual({ + expect(engine.computeTemplateAccesses('<%= settings.valid %> and <% invalid.syntax')).toEqual({ accesses: ['settings.valid'], unableToCompute: false, }); }); it('handles template with only whitespace', () => { - expect(computeTemplateAccesses('<%= %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= %>')).toEqual({ accesses: [], unableToCompute: true, }); @@ -136,42 +137,42 @@ describe('access-recorder.ts', () => { describe('computeTemplateAccesses() security', () => { it('prevents direct code execution', () => { - expect(computeTemplateAccesses('<%= process.exit(1) %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= process.exit(1) %>')).toEqual({ accesses: [], unableToCompute: true, }); }); it('prevents access to global objects', () => { - expect(computeTemplateAccesses('<%= global.process %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= global.process %>')).toEqual({ accesses: [], unableToCompute: true, }); }); it('prevents require/import statements', () => { - expect(computeTemplateAccesses('<%= require("fs") %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= require("fs") %>')).toEqual({ accesses: [], unableToCompute: true, }); }); it('prevents eval usage', () => { - expect(computeTemplateAccesses('<%= eval("console.log(\'REKT\')") %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= eval("console.log(\'REKT\')") %>')).toEqual({ accesses: [], unableToCompute: true, }); }); it('prevents Function constructor usage', () => { - expect(computeTemplateAccesses('<%= new Function("return process")() %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= new Function("return process")() %>')).toEqual({ accesses: [], unableToCompute: true, }); }); it('prevents setTimeout/setInterval usage', () => { - expect(computeTemplateAccesses('<%= setTimeout(() => {}, 1000) %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= setTimeout(() => {}, 1000) %>')).toEqual({ accesses: [], unableToCompute: true, }); @@ -179,7 +180,7 @@ describe('access-recorder.ts', () => { it('prevents overriding console.log', () => { expect( - computeTemplateAccesses('<%= console.log=function(n){require("fs").writeFileSync("./exploit.log",n)} %>') + engine.computeTemplateAccesses('<%= console.log=function(n){require("fs").writeFileSync("./exploit.log",n)} %>') ).toEqual({ accesses: [], unableToCompute: true, @@ -187,7 +188,7 @@ describe('access-recorder.ts', () => { }); it('prevents assignment of values', () => { - expect(computeTemplateAccesses('<%= const value = 1 + 2 %>')).toEqual({ + expect(engine.computeTemplateAccesses('<%= const value = 1 + 2 %>')).toEqual({ accesses: [], unableToCompute: true, }); diff --git a/packages/builder/src/access-recorder.ts b/packages/builder/src/access-recorder.ts index e29a960c2..04e1c7b52 100644 --- a/packages/builder/src/access-recorder.ts +++ b/packages/builder/src/access-recorder.ts @@ -12,7 +12,7 @@ class ExtendableProxy { constructor(defaultValue?: any) { return new Proxy(this, { get: (obj: any, prop: string) => { - if (prop === 'accessed' || prop === 'getAccesses') { + if (prop === 'accessed' || prop === 'getAccesses' || prop === 'clearAccesses') { return obj[prop]; } if (!this.accessed.has(prop)) { @@ -52,13 +52,17 @@ export class AccessRecorder extends ExtendableProxy { return acc; } + + clearAccesses() { + this.accessed.clear(); + } } export type AccessComputationResult = { accesses: string[]; unableToCompute: boolean }; type AccessRecorderMap = { [k: string]: AccessRecorder }; -type TemplateContext = { +export type TemplateContext = { [k: string]: AccessRecorder | AccessRecorderMap | unknown; }; @@ -67,7 +71,7 @@ type TemplateContext = { * @param possibleNames - The possible names to setup the context for * @returns The template context */ -function setupTemplateContext(possibleNames: string[] = []): TemplateContext { +export function setupTemplateContext(possibleNames: string[] = []): TemplateContext { // Create a fake helper context, so the render works but no real functions are called const fakeHelperContext = _createDeepNoopObject(CannonHelperContext); @@ -85,7 +89,7 @@ function setupTemplateContext(possibleNames: string[] = []): TemplateContext { imports: new AccessRecorder(), extras: new AccessRecorder(), txns: new AccessRecorder(), - // For settings, we give it a zeroAddress as a best case scenarion that is going + // For settings, we give it a zeroAddress as a best case scenario that is going // to be working for most cases. // e.g., when calculating a setting value for 'settings.owners.split(',')' or 'settings.someNumber' will work. settings: new AccessRecorder(viem.zeroAddress), @@ -137,29 +141,44 @@ function collectAccesses(recorders: TemplateContext, possibleNames: string[]): s return accesses; } -/** - * Compute the accesses from the template. - * @param str - The template to compute accesses from - * @param possibleNames - The possible names to compute accesses from - * @returns The accesses - */ -export function computeTemplateAccesses(str?: string, possibleNames: string[] = []): AccessComputationResult { - if (!str) { - return { accesses: [], unableToCompute: false }; +export class AccessRecorderEngine { + readonly possibleNames: string[] = []; + readonly templateContext: TemplateContext; + + constructor(possibleNames: string[]) { + this.possibleNames = possibleNames; + this.templateContext = setupTemplateContext(possibleNames); } - const recorders = setupTemplateContext(possibleNames); - - try { - // we give it "true" for safeContext to avoid cloning and freezing of the object - // this is because we want to keep the access recorder, and is not a security risk - // if the user can modify that object - template(str, recorders, true); - const accesses = collectAccesses(recorders, possibleNames); - return { accesses, unableToCompute: false }; - } catch (err) { - debug('Template execution failed:', err); - return { accesses: [], unableToCompute: true }; + /** + * Compute the accesses from the template. + * @param str - The template to compute accesses from + * @param possibleNames - The possible names to compute accesses from + * @returns The accesses + */ + computeTemplateAccesses(str?: string): AccessComputationResult { + // here we have an early return if there are no templates in the string at all-this saves a huge amount of compute. + if (!str || !str.includes('<%=')) { + return { accesses: [], unableToCompute: false }; + } + + for (const r in this.templateContext) { + if (this.templateContext[r] instanceof AccessRecorder) { + this.templateContext[r].clearAccesses(); + } + } + + try { + // we give it "true" for safeContext to avoid cloning and freezing of the object + // this is because we want to keep the access recorder, and is not a security risk + // if the user can modify that object + template(str, this.templateContext, true); + const accesses = collectAccesses(this.templateContext, this.possibleNames); + return { accesses, unableToCompute: false }; + } catch (err) { + debug('Template execution failed:', err); + return { accesses: [], unableToCompute: true }; + } } } diff --git a/packages/builder/src/actions.ts b/packages/builder/src/actions.ts index 6559488b8..6c7fb986b 100644 --- a/packages/builder/src/actions.ts +++ b/packages/builder/src/actions.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { AccessComputationResult } from './access-recorder'; +import { AccessComputationResult, AccessRecorderEngine } from './access-recorder'; import { handleZodErrors } from './error/zod'; import { ChainBuilderRuntime } from './runtime'; import { chainDefinitionSchema } from './schemas'; @@ -33,7 +33,7 @@ export interface CannonAction { /** * Returns a list of state keys that this operation consumes (used for dependency inference) */ - getInputs?: (config: Config, possibleFields: string[], packageState: PackageState) => AccessComputationResult; + getInputs?: (config: Config, engine: AccessRecorderEngine, packageState: PackageState) => AccessComputationResult; /** * Returns a list of state keys this operation produces (used for dependency inference) diff --git a/packages/builder/src/definition.ts b/packages/builder/src/definition.ts index 2977f6c4b..13c218a8d 100644 --- a/packages/builder/src/definition.ts +++ b/packages/builder/src/definition.ts @@ -10,6 +10,7 @@ import { template } from './utils/template'; import { PackageReference } from './package-reference'; import { ZodIssue } from 'zod'; +import { AccessRecorderEngine } from './access-recorder'; const debug = Debug('cannon:builder:definition'); const debugVerbose = Debug('cannon:verbose:builder:definition'); @@ -73,6 +74,8 @@ export class ChainDefinition { readonly dependencyFor = new Map(); readonly resolvedDependencies = new Map(); + accessRecorderEngine: AccessRecorderEngine | null = null; + readonly danglingDependencies = new Set<`${string}:${string}`>(); constructor(def: RawChainDefinition, sensitiveDependencies = false) { @@ -230,6 +233,10 @@ export class ChainDefinition { * @returns direct dependencies for the specified node */ computeDependencies(node: string) { + if (!this.accessRecorderEngine) { + this.computePossibleNames(); + } + if (!_.get(this.raw, node)) { const stepName = node.split('.')[0]; const possibleSteps = _.get(this.raw, stepName); @@ -254,20 +261,7 @@ export class ChainDefinition { } if (ActionKinds[n].getInputs) { - const possibleFields: string[] = []; - for (const k of this.dependencyFor.keys()) { - const baseName = k.split('.')[0]; - if ( - baseName !== 'contracts' && - baseName !== 'imports' && - baseName !== 'settings' && - baseName !== 'extras' && - baseName !== 'txns' - ) { - possibleFields.push(baseName); - } - } - const accessComputationResults = ActionKinds[n].getInputs!(_.get(this.raw, node), possibleFields, { + const accessComputationResults = ActionKinds[n].getInputs!(_.get(this.raw, node), this.accessRecorderEngine!, { ref: null, currentLabel: node, }); @@ -452,9 +446,33 @@ export class ChainDefinition { } } + this.computePossibleNames(); + return outputClashes; } + computePossibleNames() { + if (this.allActionNames.length > 0 && this.dependencyFor.size == 0) { + this.checkOutputClash(); + } + + const possibleNames = []; + for (const k of this.dependencyFor.keys()) { + const baseName = k.split('.')[0]; + if ( + baseName !== 'contracts' && + baseName !== 'imports' && + baseName !== 'settings' && + baseName !== 'extras' && + baseName !== 'txns' + ) { + possibleNames.push(baseName); + } + } + + this.accessRecorderEngine = new AccessRecorderEngine(possibleNames); + } + /** * Checks for any dependency actions which aren't defined among the given list of dependencies to check * @param actions which actions to check for missing dependencies diff --git a/packages/builder/src/index.ts b/packages/builder/src/index.ts index a462ad431..dc18fef9a 100644 --- a/packages/builder/src/index.ts +++ b/packages/builder/src/index.ts @@ -6,7 +6,7 @@ if (!Object.prototype.hasOwnProperty.call(BigInt.prototype, 'toJSON')) { } export { createInitialContext, build, getArtifacts, addOutputsToContext, getOutputs } from './builder'; -export { computeTemplateAccesses, mergeTemplateAccesses } from './access-recorder'; +export { mergeTemplateAccesses } from './access-recorder'; export { registerAction, ActionKinds } from './actions'; export type { CannonAction, RawChainDefinition } from './actions'; export { ChainDefinition } from './definition'; diff --git a/packages/builder/src/steps/clone.test.ts b/packages/builder/src/steps/clone.test.ts index 78950eba9..0bb023278 100644 --- a/packages/builder/src/steps/clone.test.ts +++ b/packages/builder/src/steps/clone.test.ts @@ -5,6 +5,7 @@ import action from './clone'; import deployAction from './deploy'; import { fakeCtx, fakeRuntime } from './utils.test.helper'; import { PackageReference } from '../package-reference'; +import { AccessRecorderEngine } from '..'; jest.mock('../loader'); jest.mock('./deploy'); @@ -60,7 +61,7 @@ describe('steps/clone.ts', () => { var: { woot: '<%= settings.b %>', wah: '<%= settings.c %>' }, options: { woot: '<%= settings.d %>', wah: '<%= settings.e %>', tags: '<%= settings.f %>' }, }, - [] + new AccessRecorderEngine([]) ) ).toEqual({ accesses: ['settings.a', 'settings.b', 'settings.c', 'settings.d', 'settings.e', 'settings.f'], diff --git a/packages/builder/src/steps/clone.ts b/packages/builder/src/steps/clone.ts index a245dcfa4..b3b94c77a 100644 --- a/packages/builder/src/steps/clone.ts +++ b/packages/builder/src/steps/clone.ts @@ -3,7 +3,7 @@ import Debug from 'debug'; import _ from 'lodash'; import { z } from 'zod'; import pkg from '../../package.json'; -import { computeTemplateAccesses, mergeTemplateAccesses } from '../access-recorder'; +import { mergeTemplateAccesses } from '../access-recorder'; import { build, createInitialContext, getOutputs } from '../builder'; import { CANNON_CHAIN_ID } from '../constants'; import { ChainDefinition } from '../definition'; @@ -77,28 +77,22 @@ const cloneSpec = { return config; }, - getInputs(config, possibleFields) { - let accesses = computeTemplateAccesses(config.source); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.target, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.sourcePreset, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.targetPreset, possibleFields)); + getInputs(config, engine) { + let accesses = engine.computeTemplateAccesses(config.source); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.target)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.sourcePreset)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.targetPreset)); if (config.var) { - _.forEach(config.var, (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(a, possibleFields)))); + _.forEach(config.var, (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(a)))); } if (config.options) { - _.forEach( - config.options, - (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(a, possibleFields))) - ); + _.forEach(config.options, (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(a)))); } if (config.tags) { - _.forEach( - config.tags, - (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(a, possibleFields))) - ); + _.forEach(config.tags, (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(a)))); } return accesses; diff --git a/packages/builder/src/steps/deploy.test.ts b/packages/builder/src/steps/deploy.test.ts index b5def0c24..b4fc8d8fd 100644 --- a/packages/builder/src/steps/deploy.test.ts +++ b/packages/builder/src/steps/deploy.test.ts @@ -5,6 +5,7 @@ import { ContractArtifact } from '../types'; import action from './deploy'; import { fakeCtx, fakeRuntime, makeFakeSigner } from './utils.test.helper'; import { PackageReference } from '../package-reference'; +import { AccessRecorderEngine } from '..'; const DEFAULT_ARACHNID_ADDRESS = '0x4e59b44847b379578588920cA78FbF26c0B4956C'; @@ -159,7 +160,7 @@ describe('steps/deploy.ts', () => { args: ['<%= contracts.h %>', '<%= contracts.i %>'], salt: '<%= contracts.j %>', }, - [] + new AccessRecorderEngine([]) ) .accesses.sort() ).toEqual([ diff --git a/packages/builder/src/steps/deploy.ts b/packages/builder/src/steps/deploy.ts index efb77f911..4018c8d38 100644 --- a/packages/builder/src/steps/deploy.ts +++ b/packages/builder/src/steps/deploy.ts @@ -2,7 +2,7 @@ import Debug from 'debug'; import _ from 'lodash'; import * as viem from 'viem'; import { z } from 'zod'; -import { computeTemplateAccesses, mergeTemplateAccesses } from '../access-recorder'; +import { mergeTemplateAccesses } from '../access-recorder'; import { ARACHNID_DEFAULT_DEPLOY_ADDR, ensureArachnidCreate2Exists, makeArachnidCreate2Txn } from '../create2'; import { CannonError, handleTxnError } from '../error'; import { deploySchema } from '../schemas'; @@ -195,37 +195,31 @@ const deploySpec = { return config; }, - getInputs(config, possibleFields) { - let accesses = computeTemplateAccesses(config.from); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.nonce, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.artifact, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.value, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.abi, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.salt, possibleFields)); + getInputs(config, engine) { + let accesses = engine.computeTemplateAccesses(config.from); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.nonce)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.artifact)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.value)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.abi)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.salt)); if (config.abiOf) { - _.forEach( - config.abiOf, - (v) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(v, possibleFields))) - ); + _.forEach(config.abiOf, (v) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(v)))); } if (config.args) { _.forEach( config.args, - (v) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(JSON.stringify(v), possibleFields))) + (v) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(JSON.stringify(v)))) ); } if (config.libraries) { - _.forEach( - config.libraries, - (v) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(v, possibleFields))) - ); + _.forEach(config.libraries, (v) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(v)))); } if (config?.overrides?.gasLimit) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.overrides.gasLimit, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.overrides.gasLimit)); } return accesses; diff --git a/packages/builder/src/steps/diamond.ts b/packages/builder/src/steps/diamond.ts index 8e8ad8aa2..2362d8a33 100644 --- a/packages/builder/src/steps/diamond.ts +++ b/packages/builder/src/steps/diamond.ts @@ -3,7 +3,7 @@ import _ from 'lodash'; import * as viem from 'viem'; import { z } from 'zod'; import { ARACHNID_DEFAULT_DEPLOY_ADDR, ensureArachnidCreate2Exists, makeArachnidCreate2Txn } from '../create2'; -import { computeTemplateAccesses, mergeTemplateAccesses } from '../access-recorder'; +import { mergeTemplateAccesses } from '../access-recorder'; import { ChainBuilderRuntime } from '../runtime'; import { diamondSchema } from '../schemas'; import { ContractArtifact, ContractMap, PackageState } from '../types'; @@ -94,23 +94,23 @@ const diamondStep = { return config; }, - getInputs(config, possibleFields) { - let accesses = computeTemplateAccesses(config.diamondArgs.owner, possibleFields); + getInputs(config, engine) { + let accesses = engine.computeTemplateAccesses(config.diamondArgs.owner); if (config.diamondArgs.init) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.diamondArgs.init, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.diamondArgs.init)); } if (config.diamondArgs.initCalldata) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.diamondArgs.initCalldata, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.diamondArgs.initCalldata)); } - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.salt, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.salt)); accesses.accesses.push( ...config.contracts.map((c) => (c.includes('.') ? `imports.${c.split('.')[0]}` : `contracts.${c}`)) ); if (config?.overrides) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.overrides.gasLimit, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.overrides.gasLimit)); } return accesses; diff --git a/packages/builder/src/steps/invoke.test.ts b/packages/builder/src/steps/invoke.test.ts index f0d673a3f..d1001fbd4 100644 --- a/packages/builder/src/steps/invoke.test.ts +++ b/packages/builder/src/steps/invoke.test.ts @@ -3,6 +3,7 @@ import { validateConfig } from '../actions'; import action from './invoke'; import { fakeCtx, fakeRuntime } from './utils.test.helper'; import { PackageReference } from '../package-reference'; +import { AccessRecorderEngine } from '..'; describe('steps/invoke.ts', () => { const fakeContractInfo = { @@ -174,7 +175,7 @@ describe('steps/invoke.ts', () => { args: ['<%= contracts.h %>', '<%= contracts.i %>'], overrides: { gasLimit: '<%= contracts.j %>' }, }, - [] + new AccessRecorderEngine([]) ) .accesses.sort() ).toEqual([ diff --git a/packages/builder/src/steps/invoke.ts b/packages/builder/src/steps/invoke.ts index 2f8fa362c..458a62fd8 100644 --- a/packages/builder/src/steps/invoke.ts +++ b/packages/builder/src/steps/invoke.ts @@ -2,7 +2,7 @@ import Debug from 'debug'; import _ from 'lodash'; import * as viem from 'viem'; import { z } from 'zod'; -import { computeTemplateAccesses, mergeTemplateAccesses } from '../access-recorder'; +import { mergeTemplateAccesses } from '../access-recorder'; import { invokeSchema } from '../schemas'; import { CannonSigner, @@ -440,11 +440,11 @@ const invokeSpec = { return config; }, - getInputs(config, possibleFields) { - let accesses = computeTemplateAccesses(config.abi, possibleFields); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.func, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.from, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.value, possibleFields)); + getInputs(config, engine) { + let accesses = engine.computeTemplateAccesses(config.abi); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.func)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.from)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.value)); if (typeof config.target === 'string') { config.target = [config.target as string]; @@ -460,7 +460,7 @@ const invokeSpec = { accesses.accesses.push(`imports.${(target as string).split('.')[0]}`); } else if (isTemplateString(target)) { for (const match of getTemplateMatches(target)) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(match, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(match)); } } } @@ -468,37 +468,37 @@ const invokeSpec = { if (config.args) { _.forEach( config.args, - (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(JSON.stringify(a), possibleFields))) + (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(JSON.stringify(a)))) ); } if (config.fromCall) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.fromCall.func, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.fromCall.func)); _.forEach( config.fromCall.args, - (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(JSON.stringify(a), possibleFields))) + (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(JSON.stringify(a)))) ); } if (config?.overrides) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.overrides.gasLimit, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.overrides.gasLimit)); } for (const name in config.factory) { const f = config.factory[name]; - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(f.event, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(f.artifact, possibleFields)); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(f.abi, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(f.event)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(f.artifact)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(f.abi)); - _.forEach(f.abiOf, (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(a, possibleFields)))); + _.forEach(f.abiOf, (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(a)))); } const varsConfig = config.var || config.extra; for (const name in varsConfig) { const f = varsConfig[name]; - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(f.event, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(f.event)); } return accesses; diff --git a/packages/builder/src/steps/pull.ts b/packages/builder/src/steps/pull.ts index d8c801df9..118bec877 100644 --- a/packages/builder/src/steps/pull.ts +++ b/packages/builder/src/steps/pull.ts @@ -2,7 +2,7 @@ import Debug from 'debug'; import _ from 'lodash'; import { z } from 'zod'; import { Events } from '../runtime'; -import { computeTemplateAccesses, mergeTemplateAccesses } from '../access-recorder'; +import { mergeTemplateAccesses } from '../access-recorder'; import { getOutputs } from '../builder'; import { ChainDefinition } from '../definition'; import { PackageReference } from '../package-reference'; @@ -59,9 +59,9 @@ const pullSpec = { return config; }, - getInputs(config, possibleFields) { - let accesses = computeTemplateAccesses(config.source, possibleFields); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.preset, possibleFields)); + getInputs(config, engine) { + let accesses = engine.computeTemplateAccesses(config.source); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.preset)); return accesses; }, diff --git a/packages/builder/src/steps/router.ts b/packages/builder/src/steps/router.ts index 1e7952cc9..d5199231a 100644 --- a/packages/builder/src/steps/router.ts +++ b/packages/builder/src/steps/router.ts @@ -5,7 +5,7 @@ import { z } from 'zod'; import { generateRouter } from '@usecannon/router'; import { ARACHNID_DEFAULT_DEPLOY_ADDR, ensureArachnidCreate2Exists, makeArachnidCreate2Txn } from '../create2'; import { CannonError } from '../error'; -import { computeTemplateAccesses, mergeTemplateAccesses } from '../access-recorder'; +import { mergeTemplateAccesses } from '../access-recorder'; import { routerSchema } from '../schemas'; import { ContractMap } from '../types'; import { @@ -125,19 +125,19 @@ const routerStep = { return config; }, - getInputs(config, possibleFields) { - let accesses = computeTemplateAccesses(config.from); - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.salt, possibleFields)); + getInputs(config, engine) { + let accesses = engine.computeTemplateAccesses(config.from); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.salt)); accesses = mergeTemplateAccesses( accesses, - computeTemplateAccesses(typeof config.create2 === 'string' ? config.create2 : '', possibleFields) + engine.computeTemplateAccesses(typeof config.create2 === 'string' ? config.create2 : '') ); accesses.accesses.push( ...config.contracts.map((c) => (c.includes('.') ? `imports.${c.split('.')[0]}` : `contracts.${c}`)) ); if (config?.overrides) { - accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(config.overrides.gasLimit, possibleFields)); + accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(config.overrides.gasLimit)); } return accesses; diff --git a/packages/builder/src/steps/var.ts b/packages/builder/src/steps/var.ts index 7c24e1297..172a70b2a 100644 --- a/packages/builder/src/steps/var.ts +++ b/packages/builder/src/steps/var.ts @@ -1,7 +1,7 @@ import Debug from 'debug'; import _ from 'lodash'; import { z } from 'zod'; -import { computeTemplateAccesses, mergeTemplateAccesses } from '../access-recorder'; +import { mergeTemplateAccesses } from '../access-recorder'; import { varSchema } from '../schemas'; import { template } from '../utils/template'; import { CannonAction } from '../actions'; @@ -42,11 +42,11 @@ const varSpec = { return config; }, - getInputs(config, possibleFields) { - let accesses = computeTemplateAccesses('', possibleFields); + getInputs(config, engine) { + let accesses = engine.computeTemplateAccesses(''); for (const c in _.omit(config, 'depends')) { - const fields = computeTemplateAccesses(config[c], possibleFields); + const fields = engine.computeTemplateAccesses(config[c]); accesses = mergeTemplateAccesses(accesses, fields); } diff --git a/packages/cli/src/custom-steps/run.ts b/packages/cli/src/custom-steps/run.ts index 76983d14b..8ef56159e 100644 --- a/packages/cli/src/custom-steps/run.ts +++ b/packages/cli/src/custom-steps/run.ts @@ -1,10 +1,10 @@ import { createRequire } from 'node:module'; import path from 'node:path'; import { + AccessRecorderEngine, ChainArtifacts, ChainBuilderContext, ChainBuilderRuntimeInfo, - computeTemplateAccesses, mergeTemplateAccesses, PackageState, registerAction, @@ -137,12 +137,12 @@ const runAction = { return config; }, - getInputs(config: Config) { - let accesses = computeTemplateAccesses(config.exec); + getInputs(config: Config, engine: AccessRecorderEngine) { + let accesses = engine.computeTemplateAccesses(config.exec); - _.forEach(config.modified, (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(a)))); - _.forEach(config.args, (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(a)))); - _.forEach(config.env, (a) => (accesses = mergeTemplateAccesses(accesses, computeTemplateAccesses(a)))); + _.forEach(config.modified, (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(a)))); + _.forEach(config.args, (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(a)))); + _.forEach(config.env, (a) => (accesses = mergeTemplateAccesses(accesses, engine.computeTemplateAccesses(a)))); return accesses; }, From 049c0c451f3fae1f5a9ee0df3604fabea7ddcb6c Mon Sep 17 00:00:00 2001 From: dbeal Date: Sat, 7 Mar 2026 16:14:38 +0900 Subject: [PATCH 08/13] fix(builder): prevent flaky/inconsistent rpcs from failing the build (#1848) Co-authored-by: saturn --- packages/builder/package.json | 2 + packages/builder/src/builder.ts | 10 +- packages/builder/src/helpers.test.ts | 29 +- packages/builder/src/helpers.ts | 12 +- packages/builder/src/runtime.ts | 3 +- packages/builder/src/steps/deploy.test.ts | 9 +- packages/builder/src/steps/deploy.ts | 4 +- packages/builder/src/steps/invoke.ts | 3 +- packages/builder/src/steps/router.ts | 3 +- pnpm-lock.yaml | 1712 +++------------------ 10 files changed, 289 insertions(+), 1498 deletions(-) diff --git a/packages/builder/package.json b/packages/builder/package.json index 385538617..b72cc23a0 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -38,6 +38,7 @@ "@types/jest": "^29.5.14", "@types/lodash": "^4.17.16", "@types/pako": "^2.0.3", + "@types/promise-retry": "^1.1.6", "jest": "^29.7.0", "rollup": "^4.39.0", "ts-jest": "^29.3.1", @@ -60,6 +61,7 @@ "lodash": "^4.17.21", "pako": "^2.1.0", "promise-events": "^0.2.4", + "promise-retry": "^2.0.1", "rfdc": "^1.4.1", "ses": "^1.12.0", "typestub-ipfs-only-hash": "^4.0.0", diff --git a/packages/builder/src/builder.ts b/packages/builder/src/builder.ts index 1aecc764f..14757d339 100644 --- a/packages/builder/src/builder.ts +++ b/packages/builder/src/builder.ts @@ -3,7 +3,6 @@ import Debug from 'debug'; import _ from 'lodash'; import * as viem from 'viem'; import { ContractMap, DeploymentState, TransactionMap } from './'; -import { ActionKinds } from './actions'; import { BUILD_VERSION } from './constants'; import { ChainDefinition } from './definition'; import { ChainBuilderRuntime, Events } from './runtime'; @@ -64,6 +63,9 @@ ${printChainDefinitionProblems(problems)}`); debug('build', initialCtx.settings); + // Use awaited imports to prevent import cycle within the builder module + const { ActionKinds } = await import('./actions'); + // sanity check the network await runtime.checkNetwork(); @@ -197,6 +199,9 @@ export async function buildLayer( tainted: Set = new Set(), built: Map = new Map() ) { + // Use awaited imports to prevent import cycle within the builder module + const { ActionKinds } = await import('./actions'); + const layers = def.getStateLayers(); const layer = layers[cur]; @@ -349,6 +354,9 @@ export async function buildLayer( } export async function runStep(runtime: ChainBuilderRuntime, pkgState: PackageState, cfg: any, ctx: ChainBuilderContext) { + // Use awaited imports to prevent import cycle within the builder module + const { ActionKinds } = await import('./actions'); + const [type, label] = pkgState.currentLabel.split('.') as [keyof typeof ActionKinds, string]; if (cfg && cfg.chains && !cfg.chains.includes(runtime.chainId)) { diff --git a/packages/builder/src/helpers.test.ts b/packages/builder/src/helpers.test.ts index d02306dd5..e21d47918 100644 --- a/packages/builder/src/helpers.test.ts +++ b/packages/builder/src/helpers.test.ts @@ -1,4 +1,5 @@ -import { getDefaultStorage, getCannonContract } from './helpers'; +import * as viem from 'viem'; +import { getDefaultStorage, getCannonContract, getBlockRetried } from './helpers'; import { IPFSLoader, InMemoryLoader } from './loader'; import { InMemoryRegistry, FallbackRegistry } from './registry'; import { CannonStorage } from './runtime'; @@ -11,6 +12,32 @@ describe('helpers.test.ts', () => { expect(storage.loaders.ipfs).toBeInstanceOf(IPFSLoader); expect(storage.registry).toBeInstanceOf(FallbackRegistry); }); + + describe('getBlockRetried', () => { + it('should retry twice and succeed on the third attempt', async () => { + // 1. Setup the mock + const mockBlock = { number: 100n, hash: '0x123' }; + const mockHash = '0x123'; + + const mockGetBlock = jest + .fn() + .mockRejectedValueOnce(new Error('RPC Error 1')) // Attempt 1: Fail + .mockRejectedValueOnce(new Error('RPC Error 2')) // Attempt 2: Fail + .mockResolvedValueOnce(mockBlock); // Attempt 3: Success + + const mockProvider = { + getBlock: mockGetBlock, + } as unknown as viem.PublicClient; + + // 2. Execute + const result = await getBlockRetried(mockProvider, mockHash as any); + + // 3. Assert + expect(result).toEqual(mockBlock); + expect(mockGetBlock).toHaveBeenCalledTimes(3); + expect(mockGetBlock).toHaveBeenCalledWith({ blockHash: mockHash }); + }); + }); }); // Skipping test for now as it is a function that is not used anywhere diff --git a/packages/builder/src/helpers.ts b/packages/builder/src/helpers.ts index df5e3ab95..3a0a877ee 100644 --- a/packages/builder/src/helpers.ts +++ b/packages/builder/src/helpers.ts @@ -1,8 +1,8 @@ import * as viem from 'viem'; import { mainnet, optimism } from 'viem/chains'; +import promiseRetry from 'promise-retry'; import { getArtifacts } from './builder'; import { CANNON_CHAIN_ID, DEFAULT_REGISTRY_ADDRESS, DEFAULT_REGISTRY_CONFIG, getCannonRepoRegistryUrl } from './constants'; -import { ChainDefinition } from './definition'; import { IPFSLoader } from './loader'; import { PackageReference } from './package-reference'; import { OnChainRegistry, FallbackRegistry, InMemoryRegistry } from './registry'; @@ -49,6 +49,7 @@ export async function getCannonContract(args: { throw new Error(`cannon package not found: ${args.package} (${args.chainId})`); } + const { ChainDefinition } = await import('./definition'); const artifacts = getArtifacts(new ChainDefinition(deployInfo.def), deployInfo.state); const contract = getContractFromPath(artifacts, args.contractName); @@ -67,3 +68,12 @@ export async function loadPrecompiles(provider: viem.TestClient) { for (const precompileCall of precompiles.default) await provider.setCode(precompileCall); } +// due to flaky RPC issues (ex. load balancer where the state propagates unevenly), it is sometimes the case that the block +// due to flaky RPC issues (ex. load balancer where hte state propogates unevenly), it is sometimes the case that the block +// information comes in *after* the receipt is available. This function is intended to provide an auto-retry capability +// for any errors that could be encountered on this specific problematic call +export async function getBlockRetried(provider: viem.PublicClient, blockHash: viem.Hash) { + return await promiseRetry({ retries: 5, minTimeout: 50 }, (retry) => { + return provider.getBlock({ blockHash }).catch(retry); + }); +} diff --git a/packages/builder/src/runtime.ts b/packages/builder/src/runtime.ts index 52345c376..18d44f227 100644 --- a/packages/builder/src/runtime.ts +++ b/packages/builder/src/runtime.ts @@ -3,7 +3,8 @@ import Debug from 'debug'; import { EventEmitter } from 'events'; import _ from 'lodash'; import * as viem from 'viem'; -import { CannonSigner, ChainArtifacts, PackageReference } from './'; +import { CannonSigner, ChainArtifacts } from './types'; +import { PackageReference } from './package-reference'; import { traceActions } from './error'; import { CannonLoader, IPFSLoader } from './loader'; import { CannonRegistry } from './registry'; diff --git a/packages/builder/src/steps/deploy.test.ts b/packages/builder/src/steps/deploy.test.ts index b4fc8d8fd..c42bda3c5 100644 --- a/packages/builder/src/steps/deploy.test.ts +++ b/packages/builder/src/steps/deploy.test.ts @@ -48,6 +48,7 @@ describe('steps/deploy.ts', () => { jest.mocked((fakeRuntime.provider as any).sendTransaction).mockResolvedValue('0x1234'); jest.mocked(fakeRuntime.provider.waitForTransactionReceipt).mockResolvedValue(fakeRx); + jest.mocked(fakeRuntime.provider.getBlock).mockResolvedValue({ timestamp: BigInt(123444) } as any); }); describe('validate', () => { @@ -284,7 +285,7 @@ describe('steps/deploy.ts', () => { contractName: undefined, deployTxnHash: fakeRx.transactionHash, deployTxnBlockNumber: '0', - deployTimestamp: '', + deployTimestamp: '123444', deployedOn: 'contract.Woot', linkedLibraries: {}, sourceName: undefined, @@ -327,7 +328,7 @@ describe('steps/deploy.ts', () => { contractName: undefined, deployTxnHash: fakeRx.transactionHash, deployTxnBlockNumber: '0', - deployTimestamp: '', + deployTimestamp: '123444', deployedOn: 'contract.Woot', linkedLibraries: {}, sourceName: undefined, @@ -375,7 +376,7 @@ describe('steps/deploy.ts', () => { deployTxnHash: fakeRx.transactionHash, deployedOn: 'contract.Woot', deployTxnBlockNumber: '0', - deployTimestamp: '', + deployTimestamp: '123444', linkedLibraries: {}, sourceName: undefined, highlight: undefined, @@ -413,7 +414,7 @@ describe('steps/deploy.ts', () => { deployTxnHash: fakeRx.transactionHash, deployedOn: 'contract.Woot', deployTxnBlockNumber: '0', - deployTimestamp: '', + deployTimestamp: '123444', linkedLibraries: {}, sourceName: undefined, highlight: undefined, diff --git a/packages/builder/src/steps/deploy.ts b/packages/builder/src/steps/deploy.ts index 4018c8d38..e9a990445 100644 --- a/packages/builder/src/steps/deploy.ts +++ b/packages/builder/src/steps/deploy.ts @@ -10,6 +10,7 @@ import { ChainArtifacts, ChainBuilderContext, ContractArtifact } from '../types' import { encodeDeployData, getContractDefinitionFromPath, getMergedAbiFromContractPaths } from '../util'; import { template } from '../utils/template'; import { CannonAction } from '../actions'; +import { getBlockRetried } from '../helpers'; const debug = Debug('cannon:builder:deploy'); @@ -408,8 +409,7 @@ const deploySpec = { } } - const block = await runtime.provider.getBlock({ blockNumber: receipt?.blockNumber }); - + const block = receipt ? await getBlockRetried(runtime.provider, receipt.blockHash) : null; return generateOutputs(config, ctx, artifactData, receipt, block, deployAddress, packageState.currentLabel); }, diff --git a/packages/builder/src/steps/invoke.ts b/packages/builder/src/steps/invoke.ts index 458a62fd8..d65288726 100644 --- a/packages/builder/src/steps/invoke.ts +++ b/packages/builder/src/steps/invoke.ts @@ -21,6 +21,7 @@ import { getMergedAbiFromContractPaths, } from '../util'; import { template, getTemplateMatches, isTemplateString } from '../utils/template'; +import { getBlockRetried } from '../helpers'; import { isStepPath, isStepName } from '../utils/matchers'; import { CannonAction } from '../actions'; @@ -583,7 +584,7 @@ ${getAllContractPaths(ctx).join('\n')}`); const [receipt, txnEvents] = await runTxn(runtime, config, contract, mainSigner, packageState); - const block = await runtime.provider.getBlock({ blockHash: receipt.blockHash }); + const block = await getBlockRetried(runtime.provider, receipt.blockHash); const splitLabel = packageState.currentLabel.split('.')[1]; diff --git a/packages/builder/src/steps/router.ts b/packages/builder/src/steps/router.ts index d5199231a..4f3c8fa34 100644 --- a/packages/builder/src/steps/router.ts +++ b/packages/builder/src/steps/router.ts @@ -8,6 +8,7 @@ import { CannonError } from '../error'; import { mergeTemplateAccesses } from '../access-recorder'; import { routerSchema } from '../schemas'; import { ContractMap } from '../types'; +import { getBlockRetried } from '../helpers'; import { encodeDeployData, getContractDefinitionFromPath, @@ -299,7 +300,7 @@ const routerStep = { deployAddress = receipt.contractAddress!; } - const block = receipt ? await runtime.provider.getBlock({ blockHash: receipt.blockHash }) : null; + const block = receipt ? await getBlockRetried(runtime.provider, receipt.blockHash) : null; return { contracts: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fdb7caa10..75eb1a7cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,19 +23,19 @@ importers: devDependencies: '@babel/core': specifier: ^7.22.1 - version: 7.25.2 + version: 7.26.10 '@babel/plugin-proposal-private-property-in-object': specifier: ^7.21.11 - version: 7.21.11(@babel/core@7.25.2) + version: 7.21.11(@babel/core@7.26.10) '@babel/plugin-transform-runtime': specifier: ^7.17.0 - version: 7.25.4(@babel/core@7.25.2) + version: 7.25.4(@babel/core@7.26.10) '@babel/preset-env': specifier: ^7.16.11 - version: 7.25.4(@babel/core@7.25.2) + version: 7.25.4(@babel/core@7.26.10) '@babel/preset-typescript': specifier: ^7.16.7 - version: 7.24.7(@babel/core@7.25.2) + version: 7.24.7(@babel/core@7.26.10) '@typescript-eslint/eslint-plugin': specifier: ^5.13.0 version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0)(typescript@5.8.3) @@ -50,7 +50,7 @@ importers: version: 8.10.0(eslint@8.43.0) eslint-plugin-import: specifier: ^2.25.4 - version: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0) + version: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0) eslint-plugin-prettier: specifier: ^4.0.0 version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.43.0))(eslint@8.43.0)(prettier@2.8.8) @@ -101,16 +101,16 @@ importers: devDependencies: '@nomiclabs/hardhat-ethers': specifier: ^2.2.3 - version: 2.2.3(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 2.2.3(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@nomiclabs/hardhat-etherscan': specifier: ^3.1.7 - version: 3.1.8(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 3.1.8(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@typechain/ethers-v5': specifier: ^7.2.0 version: 7.2.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@5.2.0(typescript@5.8.3))(typescript@5.8.3) '@typechain/hardhat': specifier: ^2.3.1 - version: 2.3.1(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(lodash@4.17.21)(typechain@5.2.0(typescript@5.8.3)) + version: 2.3.1(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(lodash@4.17.21)(typechain@5.2.0(typescript@5.8.3)) '@types/chai': specifier: ^4.3.0 version: 4.3.17 @@ -131,16 +131,16 @@ importers: version: 5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) hardhat: specifier: ^2.13.1 - version: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + version: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) hardhat-cannon: specifier: workspace:* version: link:../../packages/hardhat-cannon hardhat-gas-reporter: specifier: ^1.0.9 - version: 1.0.10(bufferutil@4.0.9)(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + version: 1.0.10(bufferutil@4.0.9)(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) solidity-coverage: specifier: ^0.8.5 - version: 0.8.12(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 0.8.12(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.14.0)(typescript@5.8.3) @@ -155,10 +155,10 @@ importers: devDependencies: '@nomicfoundation/hardhat-toolbox': specifier: ^4.0.0 - version: 4.0.0(4ef034ff627b366ebcbbe411d94ead71) + version: 4.0.0(2604d88557b4077c3933a8de59f3ae9a) hardhat: specifier: ^2.19.2 - version: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + version: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) hardhat-cannon: specifier: workspace:* version: link:../../packages/hardhat-cannon @@ -182,7 +182,7 @@ importers: version: 2.8.5 dotenv: specifier: ^16.4.5 - version: 16.4.5 + version: 16.4.7 envalid: specifier: ^8.0.0 version: 8.0.0 @@ -197,13 +197,13 @@ importers: version: 7.0.0(prom-client@15.1.3) express-rate-limit: specifier: ^7.2.0 - version: 7.4.0(express@5.0.0-beta.3) + version: 7.5.0(express@5.0.0-beta.3) fastest-levenshtein: specifier: ^1.0.16 version: 1.0.16 fuse.js: specifier: ^7.0.0 - version: 7.0.0 + version: 7.1.0 helmet: specifier: ^7.1.0 version: 7.1.0 @@ -243,7 +243,7 @@ importers: version: 0.5.1 acorn: specifier: ^8.14.1 - version: 8.14.1 + version: 8.15.0 axios: specifier: ^1.9.0 version: 1.9.0(debug@4.4.0) @@ -277,6 +277,9 @@ importers: promise-events: specifier: ^0.2.4 version: 0.2.4 + promise-retry: + specifier: ^2.0.1 + version: 2.0.1 rfdc: specifier: ^1.4.1 version: 1.4.1 @@ -320,6 +323,9 @@ importers: '@types/pako': specifier: ^2.0.3 version: 2.0.3 + '@types/promise-retry': + specifier: ^1.1.6 + version: 1.1.6 jest: specifier: ^29.7.0 version: 29.7.0(@types/node@22.14.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3)) @@ -531,7 +537,7 @@ importers: version: 5.31.2 dotenv: specifier: ^16.4.5 - version: 16.4.5 + version: 16.4.7 envalid: specifier: ^8.0.0 version: 8.0.0 @@ -572,13 +578,13 @@ importers: devDependencies: zod-to-json-schema: specifier: ^3.21.4 - version: 3.23.2(zod@3.24.2) + version: 3.24.5(zod@3.24.2) packages/registry: devDependencies: '@nomiclabs/hardhat-ethers': specifier: 2.0.6 - version: 2.0.6(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 2.0.6(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@openzeppelin/contracts': specifier: ^5.2.0 version: 5.2.0 @@ -590,7 +596,7 @@ importers: version: 10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))(typescript@5.8.3) '@typechain/hardhat': specifier: 6.1.2 - version: 6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))(typescript@5.8.3))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3)) + version: 6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))(typescript@5.8.3))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3)) '@types/mocha': specifier: ^10.0.10 version: 10.0.10 @@ -617,16 +623,16 @@ importers: version: 5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) hardhat: specifier: ^2.22.3 - version: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + version: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) hardhat-cannon: specifier: 2.21.0 - version: 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.2) + version: 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.2) hardhat-contract-sizer: specifier: ^2.7.0 - version: 2.10.0(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + version: 2.10.0(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) hardhat-gas-reporter: specifier: ^1.0.9 - version: 1.0.10(bufferutil@4.0.9)(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + version: 1.0.10(bufferutil@4.0.9)(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) mocha: specifier: 10.0.0 version: 10.0.0 @@ -671,7 +677,7 @@ importers: version: 5.0.0-beta.3 express-rate-limit: specifier: ^7.2.0 - version: 7.4.0(express@5.0.0-beta.3) + version: 7.5.0(express@5.0.0-beta.3) helmet: specifier: ^7.1.0 version: 7.1.0 @@ -771,7 +777,7 @@ importers: version: 2.0.0(@types/node@22.14.0)(typescript@5.8.3) vitest: specifier: ^2.1.8 - version: 2.1.8(@types/node@22.14.0)(jsdom@26.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(sass@1.86.3)(terser@5.39.0) + version: 2.1.9(@types/node@22.14.0)(jsdom@26.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(sass@1.86.3)(terser@5.39.0) optionalDependencies: redis-memory-server: specifier: ^0.11.0 @@ -781,10 +787,10 @@ importers: dependencies: express: specifier: ^4.18.2 - version: 4.19.2 + version: 4.21.2 express-rate-limit: specifier: ^7.5.0 - version: 7.5.0(express@4.19.2) + version: 7.5.0(express@4.21.2) helmet: specifier: ^8.0.0 version: 8.1.0 @@ -839,7 +845,7 @@ importers: version: 4.6.0 '@mdx-js/loader': specifier: ^3.1.0 - version: 3.1.0(acorn@8.14.1)(webpack@5.94.0(esbuild@0.23.1)) + version: 3.1.0(acorn@8.15.0)(webpack@5.94.0(esbuild@0.23.1)) '@mdx-js/react': specifier: ^3.1.0 version: 3.1.0(@types/react@18.2.37)(react@18.3.1) @@ -884,7 +890,7 @@ importers: version: 1.1.2(@types/react-dom@18.2.6)(@types/react@18.2.37)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.1.2 - version: 1.1.2(@types/react@18.2.37)(react@18.3.1) + version: 1.2.3(@types/react@18.2.37)(react@18.3.1) '@radix-ui/react-switch': specifier: ^1.1.3 version: 1.1.3(@types/react-dom@18.2.6)(@types/react@18.2.37)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1384,18 +1390,10 @@ packages: resolution: {integrity: sha512-dn1mX+EeqivoLYnY7p2qLrir0waPnCgS/0YdRCAVU2x14FgfUYCH6Im3w3oi2dMwhxfKY5lYVB5NKvZu7uI9lQ==} engines: {node: '>=16.0.0'} - '@babel/code-frame@7.24.7': - resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} - engines: {node: '>=6.9.0'} - '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.25.4': - resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} - engines: {node: '>=6.9.0'} - '@babel/compat-data@7.25.9': resolution: {integrity: sha512-yD+hEuJ/+wAJ4Ox2/rpNv5HIuPG82x3ZlQvYVn8iYCprdxzE7P1udpGF1jyjQVBU4dgznN+k2h103vxZ7NdPyw==} engines: {node: '>=6.9.0'} @@ -1408,18 +1406,10 @@ packages: resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} engines: {node: '>=6.9.0'} - '@babel/core@7.25.2': - resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} - engines: {node: '>=6.9.0'} - '@babel/core@7.26.10': resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} engines: {node: '>=6.9.0'} - '@babel/generator@7.25.5': - resolution: {integrity: sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.27.0': resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==} engines: {node: '>=6.9.0'} @@ -1436,10 +1426,6 @@ packages: resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.2': - resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} - engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.26.5': resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} engines: {node: '>=6.9.0'} @@ -1578,23 +1564,10 @@ packages: resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.25.0': - resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==} - engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.0': resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.7': - resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.25.4': - resolution: {integrity: sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.27.0': resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} engines: {node: '>=6.0.0'} @@ -2123,14 +2096,6 @@ packages: resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} - '@babel/template@7.25.0': - resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.26.8': - resolution: {integrity: sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==} - engines: {node: '>=6.9.0'} - '@babel/template@7.27.0': resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} engines: {node: '>=6.9.0'} @@ -2139,10 +2104,6 @@ packages: resolution: {integrity: sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.26.8': - resolution: {integrity: sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==} - engines: {node: '>=6.9.0'} - '@babel/traverse@7.27.0': resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} engines: {node: '>=6.9.0'} @@ -2151,10 +2112,6 @@ packages: resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.26.8': - resolution: {integrity: sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==} - engines: {node: '>=6.9.0'} - '@babel/types@7.27.0': resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} engines: {node: '>=6.9.0'} @@ -3679,66 +3636,34 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@nomicfoundation/edr-darwin-arm64@0.5.2': - resolution: {integrity: sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A==} - engines: {node: '>= 18'} - '@nomicfoundation/edr-darwin-arm64@0.8.0': resolution: {integrity: sha512-sKTmOu/P5YYhxT0ThN2Pe3hmCE/5Ag6K/eYoiavjLWbR7HEb5ZwPu2rC3DpuUk1H+UKJqt7o4/xIgJxqw9wu6A==} engines: {node: '>= 18'} - '@nomicfoundation/edr-darwin-x64@0.5.2': - resolution: {integrity: sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg==} - engines: {node: '>= 18'} - '@nomicfoundation/edr-darwin-x64@0.8.0': resolution: {integrity: sha512-8ymEtWw1xf1Id1cc42XIeE+9wyo3Dpn9OD/X8GiaMz9R70Ebmj2g+FrbETu8o6UM+aL28sBZQCiCzjlft2yWAg==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-gnu@0.5.2': - resolution: {integrity: sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA==} - engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-gnu@0.8.0': resolution: {integrity: sha512-h/wWzS2EyQuycz+x/SjMRbyA+QMCCVmotRsgM1WycPARvVZWIVfwRRsKoXKdCftsb3S8NTprqBdJlOmsFyETFA==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-musl@0.5.2': - resolution: {integrity: sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg==} - engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-musl@0.8.0': resolution: {integrity: sha512-gnWxDgdkka0O9GpPX/gZT3REeKYV28Guyg13+Vj/bbLpmK1HmGh6Kx+fMhWv+Ht/wEmGDBGMCW1wdyT/CftJaQ==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-gnu@0.5.2': - resolution: {integrity: sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A==} - engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-gnu@0.8.0': resolution: {integrity: sha512-DTMiAkgAx+nyxcxKyxFZk1HPakXXUCgrmei7r5G7kngiggiGp/AUuBBWFHi8xvl2y04GYhro5Wp+KprnLVoAPA==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-musl@0.5.2': - resolution: {integrity: sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA==} - engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-musl@0.8.0': resolution: {integrity: sha512-iTITWe0Zj8cNqS0xTblmxPbHVWwEtMiDC+Yxwr64d7QBn/1W0ilFQ16J8gB6RVVFU3GpfNyoeg3tUoMpSnrm6Q==} engines: {node: '>= 18'} - '@nomicfoundation/edr-win32-x64-msvc@0.5.2': - resolution: {integrity: sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w==} - engines: {node: '>= 18'} - '@nomicfoundation/edr-win32-x64-msvc@0.8.0': resolution: {integrity: sha512-mNRDyd/C3j7RMcwapifzv2K57sfA5xOw8g2U84ZDvgSrXVXLC99ZPxn9kmolb+dz8VMm9FONTZz9ESS6v8DTnA==} engines: {node: '>= 18'} - '@nomicfoundation/edr@0.5.2': - resolution: {integrity: sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw==} - engines: {node: '>= 18'} - '@nomicfoundation/edr@0.8.0': resolution: {integrity: sha512-dwWRrghSVBQDpt0wP+6RXD8BMz2i/9TI34TcmZqeEAZuCLei3U9KZRgGTKVAM1rMRvrpf5ROfPqrWNetKVUTag==} engines: {node: '>= 18'} @@ -6280,9 +6205,6 @@ packages: '@types/bn.js@4.11.6': resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} - '@types/bn.js@5.1.5': - resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} - '@types/bn.js@5.1.6': resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} @@ -6974,23 +6896,9 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 - '@vitest/expect@2.1.8': - resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} - '@vitest/expect@2.1.9': resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} - '@vitest/mocker@2.1.8': - resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - '@vitest/mocker@2.1.9': resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} peerDependencies: @@ -7002,33 +6910,18 @@ packages: vite: optional: true - '@vitest/pretty-format@2.1.8': - resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} - '@vitest/pretty-format@2.1.9': resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} - '@vitest/runner@2.1.8': - resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} - '@vitest/runner@2.1.9': resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} - '@vitest/snapshot@2.1.8': - resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} - '@vitest/snapshot@2.1.9': resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} - '@vitest/spy@2.1.8': - resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} - '@vitest/spy@2.1.9': resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} - '@vitest/utils@2.1.8': - resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} - '@vitest/utils@2.1.9': resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} @@ -7063,6 +6956,7 @@ packages: '@walletconnect/ethereum-provider@2.19.2': resolution: {integrity: sha512-NzPzNcjMLqow6ha2nssB1ciMD0cdHZesYcHSQKjCi9waIDMov9Fr2yEJccbiVFE3cxek7f9dCPsoZez2q8ihvg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/events@1.0.1': resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} @@ -7104,6 +6998,7 @@ packages: '@walletconnect/modal@2.7.0': resolution: {integrity: sha512-RQVt58oJ+rwqnPcIvRFeMGKuXb9qkgSmwz4noF8JZGUym3gUAzVs+uW2NQ1Owm9XOJAV+sANrtJ+VoVq1ftElw==} + deprecated: Please follow the migration guide on https://docs.reown.com/appkit/upgrade/wcm '@walletconnect/relay-api@1.0.11': resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} @@ -7116,6 +7011,7 @@ packages: '@walletconnect/sign-client@2.19.2': resolution: {integrity: sha512-a/K5PRIFPCjfHq5xx3WYKHAAF8Ft2I1LtxloyibqiQOoUtNLfKgFB1r8sdMvXM7/PADNPe4iAw4uSE6PrARrfg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/time@1.0.2': resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} @@ -7125,6 +7021,7 @@ packages: '@walletconnect/universal-provider@2.19.2': resolution: {integrity: sha512-LkKg+EjcSUpPUhhvRANgkjPL38wJPIWumAYD8OK/g4OFuJ4W3lS/XTCKthABQfFqmiNbNbVllmywiyE44KdpQg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/utils@2.19.2': resolution: {integrity: sha512-VU5CcUF4sZDg8a2/ov29OJzT3KfLuZqJUM0GemW30dlipI5fkpb0VPenZK7TcdLPXc1LN+Q+7eyTqHRoAu/BIA==} @@ -7262,11 +7159,6 @@ packages: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -7501,10 +7393,6 @@ packages: resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} engines: {node: '>= 0.4'} - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} - array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} @@ -7796,10 +7684,6 @@ packages: bn.js@5.2.1: resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -9223,10 +9107,6 @@ packages: resolution: {integrity: sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==} engines: {node: '>=12'} - dotenv@16.4.5: - resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} - engines: {node: '>=12'} - dotenv@16.4.7: resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} @@ -9410,9 +9290,6 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} - es-module-lexer@1.5.4: - resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} - es-module-lexer@1.6.0: resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} @@ -9576,42 +9453,11 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-module-utils@2.8.1: - resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - eslint-plugin-cypress@3.6.0: resolution: {integrity: sha512-7IAMcBbTVu5LpWeZRn5a9mQ30y4hKp3AfTz+6nSD/x/7YyLMoBI6X7XjDLYI6zFvuy4Q4QVGl563AGEXGW/aSA==} peerDependencies: eslint: '>=7' - eslint-plugin-import@2.29.1: - resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint-plugin-import@2.31.0: resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} @@ -9900,10 +9746,6 @@ packages: resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} engines: {node: '>=12.0.0'} - expect-type@1.2.1: - resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} - engines: {node: '>=12.0.0'} - expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -9920,22 +9762,12 @@ packages: peerDependencies: prom-client: '>=15.0.0' - express-rate-limit@7.4.0: - resolution: {integrity: sha512-v1204w3cXu5gCDmAvgvzI6qjzZzoMWKnyVDk3ACgfswTQLYiGen+r8w0VnXnGMmzEN/g8fwIQ4JrFFd4ZP6ssg==} - engines: {node: '>= 16'} - peerDependencies: - express: 4 || 5 || ^5.0.0-beta.1 - express-rate-limit@7.5.0: resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} engines: {node: '>= 16'} peerDependencies: express: ^4.11 || 5 || ^5.0.0-beta.1 - express@4.19.2: - resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} - engines: {node: '>= 0.10.0'} - express@4.21.2: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} @@ -10276,10 +10108,6 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - fuse.js@7.0.0: - resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==} - engines: {node: '>=10'} - fuse.js@7.1.0: resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} engines: {node: '>=10'} @@ -10594,18 +10422,6 @@ packages: typescript: optional: true - hardhat@2.22.9: - resolution: {integrity: sha512-sWiuI/yRdFUPfndIvL+2H18Vs2Gav0XacCFYY5msT5dHOWkhLxESJySIk9j83mXL31aXL8+UMA9OgViFLexklg==} - hasBin: true - peerDependencies: - ts-node: '*' - typescript: '*' - peerDependenciesMeta: - ts-node: - optional: true - typescript: - optional: true - has-ansi@4.0.1: resolution: {integrity: sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==} engines: {node: '>=8'} @@ -11656,11 +11472,6 @@ packages: canvas: optional: true - jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -11793,6 +11604,7 @@ packages: keygrip@1.1.0: resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} engines: {node: '>= 0.6'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. keyv@3.1.0: resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==} @@ -12957,6 +12769,7 @@ packages: next@14.2.26: resolution: {integrity: sha512-b81XSLihMwCfwiUVRRja3LphLo4uBBMZEzBBWMaISbKTwOmq3wPknIETy/8000tr7Gq4WmbuFYPS7jOYIf+ZJw==} engines: {node: '>=18.17.0'} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -13563,9 +13376,6 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - path-to-regexp@3.2.0: resolution: {integrity: sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==} @@ -14638,10 +14448,6 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} - engines: {node: '>= 0.8.0'} - send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} @@ -14659,10 +14465,6 @@ packages: serve-handler@6.1.6: resolution: {integrity: sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==} - serve-static@1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} - engines: {node: '>= 0.8.0'} - serve-static@1.16.2: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} @@ -14980,10 +14782,6 @@ packages: stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} - stacktrace-parser@0.1.10: - resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} - engines: {node: '>=6'} - stacktrace-parser@0.1.11: resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} engines: {node: '>=6'} @@ -15008,9 +14806,6 @@ packages: std-env@3.8.0: resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} @@ -15385,9 +15180,6 @@ packages: tinyexec@0.3.1: resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.12: resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} engines: {node: '>=12.0.0'} @@ -16264,11 +16056,6 @@ packages: typescript: optional: true - vite-node@2.1.8: - resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - vite-node@2.1.9: resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -16344,31 +16131,6 @@ packages: terser: optional: true - vitest@2.1.8: - resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.8 - '@vitest/ui': 2.1.8 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - vitest@2.1.9: resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} engines: {node: ^18.0.0 || >=20.0.0} @@ -16428,9 +16190,6 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - web-solc@0.5.1: - resolution: {integrity: sha512-Z/hBplZq1+4i4bYeIeD9N3vP1BLUBXpSDa4h0Ipm2Z2cHv7x7DtZ2zFb0E1L1VZo4BF+OJGVtGlT+nTUXGgncQ==} - web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -16726,6 +16485,7 @@ packages: whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} @@ -17106,11 +16866,6 @@ packages: peerDependencies: zod: ^3.13.2 - zod-to-json-schema@3.23.2: - resolution: {integrity: sha512-uSt90Gzc/tUfyNqxnjlfBs8W6WSGpNBv0rVsNxP/BVSMHMKGdthPYff4xtCHYloJGM0CFxFsb3NbC0eqPhfImw==} - peerDependencies: - zod: ^3.23.3 - zod-to-json-schema@3.24.5: resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} peerDependencies: @@ -17692,45 +17447,18 @@ snapshots: '@smithy/types': 3.7.1 tslib: 2.8.0 - '@babel/code-frame@7.24.7': - dependencies: - '@babel/highlight': 7.24.7 - picocolors: 1.1.1 - '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.25.4': {} - '@babel/compat-data@7.25.9': {} '@babel/compat-data@7.26.5': {} '@babel/compat-data@7.26.8': {} - '@babel/core@7.25.2': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.5 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) - '@babel/helpers': 7.25.0 - '@babel/parser': 7.25.4 - '@babel/template': 7.25.0 - '@babel/traverse': 7.25.4 - '@babel/types': 7.25.4 - convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/core@7.26.10': dependencies: '@ampproject/remapping': 2.3.0 @@ -17751,13 +17479,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.25.5': - dependencies: - '@babel/types': 7.25.4 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 2.5.2 - '@babel/generator@7.27.0': dependencies: '@babel/parser': 7.27.0 @@ -17781,14 +17502,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-compilation-targets@7.25.2': - dependencies: - '@babel/compat-data': 7.25.4 - '@babel/helper-validator-option': 7.24.8 - browserslist: 4.24.4 - lru-cache: 5.1.1 - semver: 6.3.1 - '@babel/helper-compilation-targets@7.26.5': dependencies: '@babel/compat-data': 7.26.5 @@ -17805,32 +17518,19 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.25.4(@babel/core@7.25.2)': + '@babel/helper-create-class-features-plugin@7.25.4(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-member-expression-to-functions': 7.24.8 '@babel/helper-optimise-call-expression': 7.24.7 - '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2) + '@babel/helper-replace-supers': 7.25.0(@babel/core@7.26.10) '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 '@babel/traverse': 7.25.4 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.25.2) - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/traverse': 7.27.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -17844,13 +17544,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-annotate-as-pure': 7.25.9 - regexpu-core: 6.1.1 - semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -17858,20 +17551,9 @@ snapshots: regexpu-core: 6.1.1 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.25.2)': + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 - '@babel/helper-compilation-targets': 7.27.0 - '@babel/helper-plugin-utils': 7.24.8 - debug: 4.4.0(supports-color@8.1.1) - lodash.debounce: 4.0.8 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color - - '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-compilation-targets': 7.27.0 '@babel/helper-plugin-utils': 7.24.8 debug: 4.4.0(supports-color@8.1.1) @@ -17893,14 +17575,14 @@ snapshots: '@babel/helper-member-expression-to-functions@7.24.8': dependencies: - '@babel/traverse': 7.25.4 + '@babel/traverse': 7.27.0 '@babel/types': 7.27.0 transitivePeerDependencies: - supports-color '@babel/helper-member-expression-to-functions@7.25.9': dependencies: - '@babel/traverse': 7.26.8 + '@babel/traverse': 7.27.0 '@babel/types': 7.27.0 transitivePeerDependencies: - supports-color @@ -17919,21 +17601,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': + '@babel/helper-module-transforms@7.25.2(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.24.7 '@babel/helper-simple-access': 7.24.7 '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.26.0(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color @@ -17959,15 +17632,6 @@ snapshots: '@babel/helper-plugin-utils@7.26.5': {} - '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-wrap-function': 7.25.9 - '@babel/traverse': 7.27.0 - transitivePeerDependencies: - - supports-color - '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -17977,21 +17641,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.25.0(@babel/core@7.25.2)': + '@babel/helper-replace-supers@7.25.0(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-member-expression-to-functions': 7.24.8 '@babel/helper-optimise-call-expression': 7.24.7 - '@babel/traverse': 7.25.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-replace-supers@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/traverse': 7.26.8 + '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color @@ -18000,20 +17655,20 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-member-expression-to-functions': 7.25.9 '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/traverse': 7.26.8 + '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color '@babel/helper-simple-access@7.24.7': dependencies: - '@babel/traverse': 7.25.4 - '@babel/types': 7.25.4 + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.24.7': dependencies: - '@babel/traverse': 7.25.4 + '@babel/traverse': 7.27.0 '@babel/types': 7.27.0 transitivePeerDependencies: - supports-color @@ -18045,76 +17700,33 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helpers@7.25.0': - dependencies: - '@babel/template': 7.25.0 - '@babel/types': 7.25.4 - '@babel/helpers@7.27.0': dependencies: '@babel/template': 7.27.0 '@babel/types': 7.27.0 - '@babel/highlight@7.24.7': - dependencies: - '@babel/helper-validator-identifier': 7.24.7 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/parser@7.25.4': - dependencies: - '@babel/types': 7.25.4 - '@babel/parser@7.27.0': dependencies: '@babel/types': 7.27.0 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.8 + '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.25.2) - transitivePeerDependencies: - - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18124,45 +17736,28 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.8 + '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 - '@babel/plugin-proposal-private-property-in-object@7.21.11(@babel/core@7.25.2)': + '@babel/plugin-proposal-private-property-in-object@7.21.11(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.25.2) + '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.10) transitivePeerDependencies: - supports-color - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18173,61 +17768,31 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18238,29 +17803,19 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.10)': @@ -18268,89 +17823,49 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-typescript@7.25.4(@babel/core@7.25.2)': + '@babel/plugin-syntax-typescript@7.25.4(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.10)': @@ -18358,52 +17873,23 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-async-generator-functions@7.26.8(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.25.2) - '@babel/traverse': 7.26.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-async-generator-functions@7.26.8(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.10) - '@babel/traverse': 7.26.8 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.25.2) + '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color @@ -18416,34 +17902,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18452,15 +17920,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18470,106 +17929,52 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.25.2) - '@babel/traverse': 7.26.8 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-compilation-targets': 7.27.0 '@babel/helper-plugin-utils': 7.26.5 '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.10) - '@babel/traverse': 7.26.8 + '@babel/traverse': 7.27.0 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/template': 7.26.8 - '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/template': 7.26.8 - - '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/template': 7.27.0 '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.10) - '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7 - '@babel/helper-plugin-utils': 7.26.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18578,26 +17983,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.26.10) - '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18606,74 +17997,36 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 - '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-compilation-targets': 7.27.0 '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.8 + '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.10) - '@babel/plugin-transform-literals@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18682,23 +18035,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.25.2)': + '@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/core': 7.26.10 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-simple-access': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18707,31 +18052,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.25.0(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.26.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-systemjs@7.25.0(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.26.8 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/traverse': 7.27.0 transitivePeerDependencies: - supports-color @@ -18743,70 +18070,34 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-nullish-coalescing-operator@7.26.6(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-nullish-coalescing-operator@7.26.6(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 - '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-compilation-targets': 7.27.0 '@babel/helper-plugin-utils': 7.26.5 '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.25.2) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18815,24 +18106,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18841,24 +18119,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18867,15 +18132,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18885,11 +18141,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18905,58 +18156,34 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - regenerator-transform: 0.15.2 - '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-runtime@7.25.4(@babel/core@7.25.2)': + '@babel/plugin-transform-runtime@7.25.4(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.10) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.10) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.10) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-spread@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -18965,182 +18192,55 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-typescript@7.25.2(@babel/core@7.25.2)': + '@babel/plugin-transform-typescript@7.25.2(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.25.2) + '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - '@babel/plugin-syntax-typescript': 7.25.4(@babel/core@7.25.2) + '@babel/plugin-syntax-typescript': 7.25.4(@babel/core@7.26.10) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-sets-regex@7.25.4(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.2) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-unicode-sets-regex@7.25.4(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.10) '@babel/helper-plugin-utils': 7.26.5 - '@babel/preset-env@7.25.4(@babel/core@7.25.2)': - dependencies: - '@babel/compat-data': 7.26.8 - '@babel/core': 7.25.2 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.3(@babel/core@7.25.2) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.0(@babel/core@7.25.2) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.0(@babel/core@7.25.2) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.0(@babel/core@7.25.2) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.25.2) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.25.2) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.25.2) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.25.2) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.0(@babel/core@7.25.2) - '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.25.2) - '@babel/plugin-transform-modules-systemjs': 7.25.0(@babel/core@7.25.2) - '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.25.2) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-typeof-symbol': 7.24.8(@babel/core@7.25.2) - '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.25.2) - '@babel/plugin-transform-unicode-sets-regex': 7.25.4(@babel/core@7.25.2) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.25.2) - babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.25.2) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2) - babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.25.2) - core-js-compat: 3.38.1 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/preset-env@7.25.4(@babel/core@7.26.10)': dependencies: '@babel/compat-data': 7.26.8 @@ -19230,28 +18330,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/types': 7.26.8 - esutils: 2.0.3 - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 - '@babel/types': 7.26.8 + '@babel/types': 7.27.0 esutils: 2.0.3 - '@babel/preset-typescript@7.24.7(@babel/core@7.25.2)': + '@babel/preset-typescript@7.24.7(@babel/core@7.26.10)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-validator-option': 7.24.8 - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) - '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.25.2) - '@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2) + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.26.10) + '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.26.10) + '@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.26.10) transitivePeerDependencies: - supports-color @@ -19263,18 +18356,6 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/template@7.25.0': - dependencies: - '@babel/code-frame': 7.24.7 - '@babel/parser': 7.25.4 - '@babel/types': 7.25.4 - - '@babel/template@7.26.8': - dependencies: - '@babel/code-frame': 7.26.2 - '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 - '@babel/template@7.27.0': dependencies: '@babel/code-frame': 7.26.2 @@ -19282,18 +18363,6 @@ snapshots: '@babel/types': 7.27.0 '@babel/traverse@7.25.4': - dependencies: - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.5 - '@babel/parser': 7.25.4 - '@babel/template': 7.25.0 - '@babel/types': 7.25.4 - debug: 4.4.0(supports-color@8.1.1) - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - - '@babel/traverse@7.26.8': dependencies: '@babel/code-frame': 7.26.2 '@babel/generator': 7.27.0 @@ -19323,11 +18392,6 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 - '@babel/types@7.26.8': - dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/types@7.27.0': dependencies: '@babel/helper-string-parser': 7.25.9 @@ -19707,7 +18771,7 @@ snapshots: '@cucumber/ci-environment': 10.0.1 '@cucumber/cucumber-expressions': 17.1.0 '@cucumber/gherkin': 28.0.0 - '@cucumber/gherkin-streams': 5.0.1(@cucumber/gherkin@28.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@25.0.1))(@cucumber/messages@24.1.0) + '@cucumber/gherkin-streams': 5.0.1(@cucumber/gherkin@28.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@24.1.0))(@cucumber/messages@24.1.0) '@cucumber/gherkin-utils': 9.0.0 '@cucumber/html-formatter': 21.6.0(@cucumber/messages@24.1.0) '@cucumber/message-streams': 4.0.1(@cucumber/messages@24.1.0) @@ -19747,7 +18811,7 @@ snapshots: yaml: 2.7.1 yup: 1.2.0 - '@cucumber/gherkin-streams@5.0.1(@cucumber/gherkin@28.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@25.0.1))(@cucumber/messages@24.1.0)': + '@cucumber/gherkin-streams@5.0.1(@cucumber/gherkin@28.0.0)(@cucumber/message-streams@4.0.1(@cucumber/messages@24.1.0))(@cucumber/messages@24.1.0)': dependencies: '@cucumber/gherkin': 28.0.0 '@cucumber/message-streams': 4.0.1(@cucumber/messages@24.1.0) @@ -21134,9 +20198,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@mdx-js/loader@3.1.0(acorn@8.14.1)(webpack@5.94.0(esbuild@0.23.1))': + '@mdx-js/loader@3.1.0(acorn@8.15.0)(webpack@5.94.0(esbuild@0.23.1))': dependencies: - '@mdx-js/mdx': 3.1.0(acorn@8.14.1) + '@mdx-js/mdx': 3.1.0(acorn@8.15.0) source-map: 0.7.4 optionalDependencies: webpack: 5.94.0(esbuild@0.23.1) @@ -21166,7 +20230,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@mdx-js/mdx@3.1.0(acorn@8.14.1)': + '@mdx-js/mdx@3.1.0(acorn@8.15.0)': dependencies: '@types/estree': 1.0.7 '@types/estree-jsx': 1.0.5 @@ -21180,7 +20244,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.6 markdown-extensions: 2.0.0 recma-build-jsx: 1.0.0 - recma-jsx: 1.0.0(acorn@8.14.1) + recma-jsx: 1.0.0(acorn@8.15.0) recma-stringify: 1.0.0 rehype-recma: 1.0.0 remark-mdx: 3.1.0 @@ -21553,44 +20617,20 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@nomicfoundation/edr-darwin-arm64@0.5.2': {} - '@nomicfoundation/edr-darwin-arm64@0.8.0': {} - '@nomicfoundation/edr-darwin-x64@0.5.2': {} - '@nomicfoundation/edr-darwin-x64@0.8.0': {} - '@nomicfoundation/edr-linux-arm64-gnu@0.5.2': {} - '@nomicfoundation/edr-linux-arm64-gnu@0.8.0': {} - '@nomicfoundation/edr-linux-arm64-musl@0.5.2': {} - '@nomicfoundation/edr-linux-arm64-musl@0.8.0': {} - '@nomicfoundation/edr-linux-x64-gnu@0.5.2': {} - '@nomicfoundation/edr-linux-x64-gnu@0.8.0': {} - '@nomicfoundation/edr-linux-x64-musl@0.5.2': {} - '@nomicfoundation/edr-linux-x64-musl@0.8.0': {} - '@nomicfoundation/edr-win32-x64-msvc@0.5.2': {} - '@nomicfoundation/edr-win32-x64-msvc@0.8.0': {} - '@nomicfoundation/edr@0.5.2': - dependencies: - '@nomicfoundation/edr-darwin-arm64': 0.5.2 - '@nomicfoundation/edr-darwin-x64': 0.5.2 - '@nomicfoundation/edr-linux-arm64-gnu': 0.5.2 - '@nomicfoundation/edr-linux-arm64-musl': 0.5.2 - '@nomicfoundation/edr-linux-x64-gnu': 0.5.2 - '@nomicfoundation/edr-linux-x64-musl': 0.5.2 - '@nomicfoundation/edr-win32-x64-msvc': 0.5.2 - '@nomicfoundation/edr@0.8.0': dependencies: '@nomicfoundation/edr-darwin-arm64': 0.8.0 @@ -21621,59 +20661,59 @@ snapshots: '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 - '@nomicfoundation/hardhat-chai-matchers@2.0.7(@nomicfoundation/hardhat-ethers@3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)))(chai@5.2.0)(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@nomicfoundation/hardhat-chai-matchers@2.0.7(@nomicfoundation/hardhat-ethers@3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)))(chai@5.2.0)(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-ethers': 3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@types/chai-as-promised': 7.1.8 chai: 5.2.0 chai-as-promised: 7.1.2(chai@5.2.0) deep-eql: 4.1.4 ethers: 6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) ordinal: 1.0.3 - '@nomicfoundation/hardhat-ethers@3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@nomicfoundation/hardhat-ethers@3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: debug: 4.4.0(supports-color@8.1.1) ethers: 6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) lodash.isequal: 4.5.0 transitivePeerDependencies: - supports-color - '@nomicfoundation/hardhat-network-helpers@1.0.11(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@nomicfoundation/hardhat-network-helpers@1.0.11(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) - '@nomicfoundation/hardhat-toolbox@4.0.0(4ef034ff627b366ebcbbe411d94ead71)': + '@nomicfoundation/hardhat-toolbox@4.0.0(2604d88557b4077c3933a8de59f3ae9a)': dependencies: - '@nomicfoundation/hardhat-chai-matchers': 2.0.7(@nomicfoundation/hardhat-ethers@3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)))(chai@5.2.0)(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) - '@nomicfoundation/hardhat-ethers': 3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) - '@nomicfoundation/hardhat-network-helpers': 1.0.11(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) - '@nomicfoundation/hardhat-verify': 2.0.9(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-chai-matchers': 2.0.7(@nomicfoundation/hardhat-ethers@3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)))(chai@5.2.0)(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-ethers': 3.0.7(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-network-helpers': 1.0.11(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-verify': 2.0.9(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) '@typechain/ethers-v6': 0.5.1(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))(typescript@5.8.3) - '@typechain/hardhat': 6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))(typescript@5.8.3))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3)) + '@typechain/hardhat': 6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))(typescript@5.8.3))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3)) '@types/chai': 4.3.17 '@types/mocha': 10.0.10 '@types/node': 22.14.0 chai: 5.2.0 ethers: 6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) - hardhat-gas-reporter: 1.0.10(bufferutil@4.0.9)(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) - solidity-coverage: 0.8.12(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat-gas-reporter: 1.0.10(bufferutil@4.0.9)(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + solidity-coverage: 0.8.12(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)) ts-node: 10.9.2(@types/node@22.14.0)(typescript@5.8.3) typechain: 8.3.2(typescript@5.8.3) typescript: 5.8.3 - '@nomicfoundation/hardhat-verify@2.0.9(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@nomicfoundation/hardhat-verify@2.0.9(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: '@ethersproject/abi': 5.8.0 '@ethersproject/address': 5.8.0 cbor: 8.1.0 chalk: 2.4.2 debug: 4.4.0(supports-color@8.1.1) - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) lodash.clonedeep: 4.5.0 semver: 6.3.1 table: 6.9.0 @@ -21712,22 +20752,22 @@ snapshots: '@nomicfoundation/solidity-analyzer-linux-x64-musl': 0.1.2 '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.2 - '@nomiclabs/hardhat-ethers@2.0.6(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@nomiclabs/hardhat-ethers@2.0.6(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: ethers: 5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) - '@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: ethers: 5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) '@nomiclabs/hardhat-ethers@2.2.3(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: ethers: 6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) - '@nomiclabs/hardhat-etherscan@3.1.8(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': + '@nomiclabs/hardhat-etherscan@3.1.8(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))': dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/address': 5.7.0 @@ -21735,7 +20775,7 @@ snapshots: chalk: 2.4.2 debug: 4.4.0(supports-color@8.1.1) fs-extra: 7.0.1 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) lodash: 4.17.21 semver: 6.3.1 table: 6.9.0 @@ -24547,32 +23587,32 @@ snapshots: typechain: 8.3.2(typescript@5.8.3) typescript: 5.8.3 - '@typechain/hardhat@2.3.1(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(lodash@4.17.21)(typechain@5.2.0(typescript@5.8.3))': + '@typechain/hardhat@2.3.1(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(lodash@4.17.21)(typechain@5.2.0(typescript@5.8.3))': dependencies: fs-extra: 9.1.0 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) lodash: 4.17.21 typechain: 5.2.0(typescript@5.8.3) - '@typechain/hardhat@6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))(typescript@5.8.3))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))': + '@typechain/hardhat@6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))(typescript@5.8.3))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))': dependencies: '@ethersproject/abi': 5.8.0 '@ethersproject/providers': 5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@typechain/ethers-v5': 10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.1.0(typescript@5.8.3))(typescript@5.8.3) ethers: 5.7.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) fs-extra: 9.1.0 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) lodash: 4.17.21 typechain: 8.1.0(typescript@5.8.3) - '@typechain/hardhat@6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))(typescript@5.8.3))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))': + '@typechain/hardhat@6.1.2(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@typechain/ethers-v5@10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))(typescript@5.8.3))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))': dependencies: '@ethersproject/abi': 5.8.0 '@ethersproject/providers': 5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@typechain/ethers-v5': 10.1.0(@ethersproject/abi@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(ethers@6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(typescript@5.8.3))(typescript@5.8.3) ethers: 6.13.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) fs-extra: 9.1.0 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) lodash: 4.17.21 typechain: 8.3.2(typescript@5.8.3) @@ -24613,10 +23653,6 @@ snapshots: dependencies: '@types/node': 22.14.0 - '@types/bn.js@5.1.5': - dependencies: - '@types/node': 22.14.0 - '@types/bn.js@5.1.6': dependencies: '@types/node': 22.14.0 @@ -25322,7 +24358,7 @@ snapshots: dependencies: '@usecannon/router': 4.1.3 '@usecannon/web-solc': 0.5.1 - acorn: 8.14.1 + acorn: 8.15.0 axios: 1.9.0(debug@4.4.0) axios-retry: 4.5.0(axios@1.9.0) buffer: 6.0.3 @@ -25350,7 +24386,7 @@ snapshots: dependencies: '@usecannon/router': 4.1.3 '@usecannon/web-solc': 0.5.1 - acorn: 8.14.1 + acorn: 8.15.0 axios: 1.9.0(debug@4.4.0) axios-retry: 4.5.0(axios@1.9.0) buffer: 6.0.3 @@ -25437,9 +24473,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@usecannon/web-solc@0.5.1': - dependencies: - web-solc: 0.5.1 + '@usecannon/web-solc@0.5.1': {} '@vanilla-extract/css@1.15.5(babel-plugin-macros@3.1.0)': dependencies: @@ -25484,13 +24518,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/expect@2.1.8': - dependencies: - '@vitest/spy': 2.1.8 - '@vitest/utils': 2.1.8 - chai: 5.1.2 - tinyrainbow: 1.2.0 - '@vitest/expect@2.1.9': dependencies: '@vitest/spy': 2.1.9 @@ -25498,66 +24525,33 @@ snapshots: chai: 5.2.0 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.8(vite@5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0))': - dependencies: - '@vitest/spy': 2.1.8 - estree-walker: 3.0.3 - magic-string: 0.30.14 - optionalDependencies: - vite: 5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) - - '@vitest/mocker@2.1.9(vite@5.4.17(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0))': + '@vitest/mocker@2.1.9(vite@5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0))': dependencies: '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 5.4.17(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) - - '@vitest/pretty-format@2.1.8': - dependencies: - tinyrainbow: 1.2.0 + vite: 5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) '@vitest/pretty-format@2.1.9': dependencies: tinyrainbow: 1.2.0 - '@vitest/runner@2.1.8': - dependencies: - '@vitest/utils': 2.1.8 - pathe: 1.1.2 - '@vitest/runner@2.1.9': dependencies: '@vitest/utils': 2.1.9 pathe: 1.1.2 - '@vitest/snapshot@2.1.8': - dependencies: - '@vitest/pretty-format': 2.1.8 - magic-string: 0.30.14 - pathe: 1.1.2 - '@vitest/snapshot@2.1.9': dependencies: '@vitest/pretty-format': 2.1.9 magic-string: 0.30.17 pathe: 1.1.2 - '@vitest/spy@2.1.8': - dependencies: - tinyspy: 3.0.2 - '@vitest/spy@2.1.9': dependencies: tinyspy: 3.0.2 - '@vitest/utils@2.1.8': - dependencies: - '@vitest/pretty-format': 2.1.8 - loupe: 3.1.2 - tinyrainbow: 1.2.0 - '@vitest/utils@2.1.9': dependencies: '@vitest/pretty-format': 2.1.9 @@ -26126,23 +25120,17 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-attributes@1.9.5(acorn@8.14.1): - dependencies: - acorn: 8.14.1 - acorn-import-attributes@1.9.5(acorn@8.15.0): dependencies: acorn: 8.15.0 - acorn-jsx@5.3.2(acorn@8.14.1): + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: - acorn: 8.14.1 + acorn: 8.15.0 acorn-walk@8.3.4: dependencies: - acorn: 8.14.1 - - acorn@8.14.1: {} + acorn: 8.15.0 acorn@8.15.0: {} @@ -26309,7 +25297,7 @@ snapshots: array-buffer-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-array-buffer: 3.0.4 array-buffer-byte-length@1.0.2: @@ -26358,16 +25346,6 @@ snapshots: es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 - array.prototype.findlastindex@1.2.6: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.23.9 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-shim-unscopables: 1.1.0 - array.prototype.flat@1.3.2: dependencies: call-bind: 1.0.7 @@ -26407,7 +25385,7 @@ snapshots: arraybuffer.prototype.slice@1.0.3: dependencies: array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 @@ -26586,20 +25564,11 @@ snapshots: resolve: 1.22.10 optional: true - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.25.2): + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.26.10): dependencies: '@babel/compat-data': 7.25.9 - '@babel/core': 7.25.2 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.25.2): - dependencies: - '@babel/compat-data': 7.26.8 - '@babel/core': 7.25.2 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.25.2) + '@babel/core': 7.26.10 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.10) semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -26613,14 +25582,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.25.2): - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.25.2) - core-js-compat: 3.38.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.10): dependencies: '@babel/core': 7.26.10 @@ -26629,17 +25590,10 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.25.2): + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.26.10): dependencies: - '@babel/core': 7.25.2 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2) - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.25.2): - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.25.2) + '@babel/core': 7.26.10 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.10) transitivePeerDependencies: - supports-color @@ -26746,23 +25700,6 @@ snapshots: bn.js@5.2.1: {} - body-parser@1.20.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - body-parser@1.20.3: dependencies: bytes: 3.1.2 @@ -28056,7 +26993,7 @@ snapshots: data-view-buffer@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 @@ -28068,7 +27005,7 @@ snapshots: data-view-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 @@ -28080,7 +27017,7 @@ snapshots: data-view-byte-offset@1.0.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 @@ -28371,14 +27308,12 @@ snapshots: dotenv-expand@11.0.6: dependencies: - dotenv: 16.4.5 + dotenv: 16.4.7 dotenv@10.0.0: {} dotenv@16.0.1: {} - dotenv@16.4.5: {} - dotenv@16.4.7: {} dunder-proto@1.0.1: @@ -28696,8 +27631,6 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 - es-module-lexer@1.5.4: {} - es-module-lexer@1.6.0: {} es-object-atoms@1.0.0: @@ -28900,7 +27833,7 @@ snapshots: eslint: 8.43.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0))(eslint@8.43.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@8.43.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.43.0) eslint-plugin-react: 7.37.5(eslint@8.43.0) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.43.0) @@ -28934,28 +27867,28 @@ snapshots: tinyglobby: 0.2.12 unrs-resolver: 1.3.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0))(eslint@8.43.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@8.43.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0))(eslint@8.43.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.43.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 8.29.0(eslint@8.43.0)(typescript@5.8.3) + '@typescript-eslint/parser': 5.62.0(eslint@8.43.0)(typescript@5.8.3) eslint: 8.43.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.43.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0))(eslint@8.43.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.43.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.29.0(eslint@8.43.0)(typescript@5.8.3) eslint: 8.43.0 eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0) transitivePeerDependencies: - supports-color @@ -28964,8 +27897,9 @@ snapshots: eslint: 8.43.0 globals: 13.24.0 - eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0): dependencies: + '@rtsao/scc': 1.1.0 array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -28974,7 +27908,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.43.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.43.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.43.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -28983,6 +27917,7 @@ snapshots: object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 + string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.43.0)(typescript@5.8.3) @@ -28991,25 +27926,25 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0))(eslint@8.43.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@8.43.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 debug: 3.2.7(supports-color@8.1.1) doctrine: 2.1.0 eslint: 8.43.0 eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@8.43.0)(typescript@5.8.3))(eslint@8.43.0))(eslint@8.43.0))(eslint@8.43.0) hasown: 2.0.2 - is-core-module: 2.16.1 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 object.groupby: 1.0.3 - object.values: 1.2.1 + object.values: 1.2.0 semver: 6.3.1 string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 @@ -29140,8 +28075,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 esprima@1.2.2: {} @@ -29551,8 +28486,6 @@ snapshots: expect-type@1.1.0: {} - expect-type@1.2.1: {} - expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 @@ -29570,56 +28503,20 @@ snapshots: express-prom-bundle@7.0.0(prom-client@15.1.3): dependencies: '@types/express': 4.17.21 - express: 4.19.2 + express: 4.21.2 on-finished: 2.4.1 prom-client: 15.1.3 url-value-parser: 2.2.0 transitivePeerDependencies: - supports-color - express-rate-limit@7.4.0(express@5.0.0-beta.3): + express-rate-limit@7.5.0(express@4.21.2): dependencies: - express: 5.0.0-beta.3 - - express-rate-limit@7.5.0(express@4.19.2): - dependencies: - express: 4.19.2 + express: 4.21.2 - express@4.19.2: + express-rate-limit@7.5.0(express@5.0.0-beta.3): dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.2 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.6.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.11.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color + express: 5.0.0-beta.3 express@4.21.2: dependencies: @@ -30041,7 +28938,7 @@ snapshots: function.prototype.name@1.1.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.3 functions-have-names: 1.2.3 @@ -30057,8 +28954,6 @@ snapshots: functions-have-names@1.2.3: {} - fuse.js@7.0.0: {} - fuse.js@7.1.0: {} gauge@4.0.4: @@ -30141,7 +29036,7 @@ snapshots: get-symbol-description@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 get-intrinsic: 1.2.4 @@ -30453,7 +29348,7 @@ snapshots: hard-rejection@2.1.0: {} - hardhat-cannon@2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.2): + hardhat-cannon@2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.2): dependencies: '@iarna/toml': 3.0.0 '@usecannon/builder': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) @@ -30461,7 +29356,7 @@ snapshots: chalk: 4.1.2 debug: 4.4.0(supports-color@8.1.1) fs-extra: 11.3.0 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) viem: 2.30.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.2) transitivePeerDependencies: - bufferutil @@ -30471,18 +29366,18 @@ snapshots: - utf-8-validate - zod - hardhat-contract-sizer@2.10.0(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)): + hardhat-contract-sizer@2.10.0(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)): dependencies: chalk: 4.1.2 cli-table3: 0.6.5 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) strip-ansi: 6.0.1 - hardhat-gas-reporter@1.0.10(bufferutil@4.0.9)(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10): + hardhat-gas-reporter@1.0.10(bufferutil@4.0.9)(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10): dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27(bufferutil@4.0.9)(utf-8-validate@5.0.10) - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -30545,60 +29440,6 @@ snapshots: - supports-color - utf-8-validate - hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10): - dependencies: - '@ethersproject/abi': 5.7.0 - '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/edr': 0.5.2 - '@nomicfoundation/ethereumjs-common': 4.0.4 - '@nomicfoundation/ethereumjs-tx': 5.0.4 - '@nomicfoundation/ethereumjs-util': 9.0.4 - '@nomicfoundation/solidity-analyzer': 0.1.2 - '@sentry/node': 5.30.0 - '@types/bn.js': 5.1.5 - '@types/lru-cache': 5.1.1 - adm-zip: 0.4.16 - aggregate-error: 3.1.0 - ansi-escapes: 4.3.2 - boxen: 5.1.2 - chalk: 2.4.2 - chokidar: 3.6.0 - ci-info: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) - enquirer: 2.4.1 - env-paths: 2.2.1 - ethereum-cryptography: 1.2.0 - ethereumjs-abi: 0.6.8 - find-up: 2.1.0 - fp-ts: 1.19.3 - fs-extra: 7.0.1 - glob: 7.2.0 - immutable: 4.3.7 - io-ts: 1.10.4 - keccak: 3.0.4 - lodash: 4.17.21 - mnemonist: 0.38.5 - mocha: 10.0.0 - p-map: 4.0.0 - raw-body: 2.5.2 - resolve: 1.17.0 - semver: 6.3.1 - solc: 0.8.26(debug@4.4.0) - source-map-support: 0.5.21 - stacktrace-parser: 0.1.10 - tsort: 0.0.1 - undici: 5.28.4 - uuid: 8.3.2 - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - ts-node: 10.9.2(@types/node@22.14.0)(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - c-kzg - - supports-color - - utf-8-validate - has-ansi@4.0.1: dependencies: ansi-regex: 4.1.1 @@ -31008,8 +29849,8 @@ snapshots: import-in-the-middle@1.13.1: dependencies: - acorn: 8.14.1 - acorn-import-attributes: 1.9.5(acorn@8.14.1) + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) cjs-module-lexer: 1.4.3 module-details-from-path: 1.0.3 @@ -31203,7 +30044,7 @@ snapshots: is-array-buffer@3.0.4: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 get-intrinsic: 1.2.4 is-array-buffer@3.0.5: @@ -31238,7 +30079,7 @@ snapshots: is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 is-boolean-object@1.2.2: @@ -31392,7 +30233,7 @@ snapshots: is-regex@1.1.4: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 is-regex@1.2.1: @@ -31408,7 +30249,7 @@ snapshots: is-shared-array-buffer@1.0.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-shared-array-buffer@1.0.4: dependencies: @@ -31469,7 +30310,7 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-weakref@1.1.1: dependencies: @@ -32004,8 +30845,6 @@ snapshots: - supports-color - utf-8-validate - jsesc@2.5.2: {} - jsesc@3.0.2: {} jsesc@3.1.0: {} @@ -33298,8 +32137,8 @@ snapshots: micromark-extension-mdxjs@1.0.1: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) micromark-extension-mdx-expression: 1.0.8 micromark-extension-mdx-jsx: 1.0.5 micromark-extension-mdx-md: 1.0.1 @@ -33309,8 +32148,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -34253,7 +33092,7 @@ snapshots: cli-cursor: 3.1.0 cli-spinners: 2.6.1 cliui: 8.0.1 - dotenv: 16.4.5 + dotenv: 16.4.7 dotenv-expand: 11.0.6 enquirer: 2.3.6 figures: 3.2.0 @@ -34376,7 +33215,7 @@ snapshots: object.assign@4.1.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 @@ -34803,8 +33642,6 @@ snapshots: path-to-regexp@0.1.12: {} - path-to-regexp@0.1.7: {} - path-to-regexp@3.2.0: {} path-to-regexp@3.3.0: {} @@ -35179,7 +34016,7 @@ snapshots: qs@6.13.0: dependencies: - side-channel: 1.0.6 + side-channel: 1.1.0 qs@6.14.0: dependencies: @@ -35438,9 +34275,9 @@ snapshots: estree-util-build-jsx: 3.0.1 vfile: 6.0.3 - recma-jsx@1.0.0(acorn@8.14.1): + recma-jsx@1.0.0(acorn@8.15.0): dependencies: - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn-jsx: 5.3.2(acorn@8.15.0) estree-util-to-js: 2.0.0 recma-parse: 1.0.0 recma-stringify: 1.0.0 @@ -35555,7 +34392,7 @@ snapshots: regexp.prototype.flags@1.5.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 @@ -35979,7 +34816,7 @@ snapshots: safe-array-concat@1.1.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 @@ -36092,24 +34929,6 @@ snapshots: semver@7.7.1: {} - send@0.18.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - send@0.19.0: dependencies: debug: 2.6.9 @@ -36163,15 +34982,6 @@ snapshots: path-to-regexp: 3.3.0 range-parser: 1.2.0 - serve-static@1.15.0: - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.18.0 - transitivePeerDependencies: - - supports-color - serve-static@1.16.2: dependencies: encodeurl: 2.0.0 @@ -36500,7 +35310,7 @@ snapshots: - supports-color - utf-8-validate - solidity-coverage@0.8.12(hardhat@2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)): + solidity-coverage@0.8.12(hardhat@2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10)): dependencies: '@ethersproject/abi': 5.7.0 '@solidity-parser/parser': 0.18.0 @@ -36511,7 +35321,7 @@ snapshots: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.22.9(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) + hardhat: 2.22.19(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.10) jsonschema: 1.4.1 lodash: 4.17.21 mocha: 10.7.3 @@ -36635,10 +35445,6 @@ snapshots: stackframe@1.3.4: {} - stacktrace-parser@0.1.10: - dependencies: - type-fest: 0.7.1 - stacktrace-parser@0.1.11: dependencies: type-fest: 0.7.1 @@ -36657,8 +35463,6 @@ snapshots: std-env@3.8.0: {} - std-env@3.9.0: {} - stdin-discarder@0.2.2: {} stream-shift@1.0.3: {} @@ -36742,10 +35546,10 @@ snapshots: string.prototype.trim@1.2.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string.prototype.trimend@1.0.9: dependencies: @@ -36756,9 +35560,9 @@ snapshots: string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string_decoder@1.1.1: dependencies: @@ -37065,7 +35869,7 @@ snapshots: terser@5.39.0: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.14.1 + acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -37142,8 +35946,6 @@ snapshots: tinyexec@0.3.1: {} - tinyexec@0.3.2: {} - tinyglobby@0.2.12: dependencies: fdir: 6.4.3(picomatch@4.0.2) @@ -37293,7 +36095,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 22.14.0 - acorn: 8.14.1 + acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 @@ -37459,7 +36261,7 @@ snapshots: typed-array-buffer@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-typed-array: 1.1.13 @@ -37471,7 +36273,7 @@ snapshots: typed-array-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 @@ -37488,7 +36290,7 @@ snapshots: typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 @@ -37506,7 +36308,7 @@ snapshots: typed-array-length@1.0.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 @@ -37596,7 +36398,7 @@ snapshots: unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -37763,7 +36565,7 @@ snapshots: unplugin@1.0.1: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.5.0 @@ -38045,24 +36847,6 @@ snapshots: - utf-8-validate - zod - vite-node@2.1.8(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0): - dependencies: - cac: 6.7.14 - debug: 4.4.0(supports-color@8.1.1) - es-module-lexer: 1.5.4 - pathe: 1.1.2 - vite: 5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - vite-node@2.1.9(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0): dependencies: cac: 6.7.14 @@ -38114,62 +36898,26 @@ snapshots: sass: 1.86.3 terser: 5.39.0 - vitest@2.1.8(@types/node@22.14.0)(jsdom@26.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(sass@1.86.3)(terser@5.39.0): - dependencies: - '@vitest/expect': 2.1.8 - '@vitest/mocker': 2.1.8(vite@5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0)) - '@vitest/pretty-format': 2.1.8 - '@vitest/runner': 2.1.8 - '@vitest/snapshot': 2.1.8 - '@vitest/spy': 2.1.8 - '@vitest/utils': 2.1.8 - chai: 5.1.2 - debug: 4.4.0(supports-color@8.1.1) - expect-type: 1.1.0 - magic-string: 0.30.14 - pathe: 1.1.2 - std-env: 3.8.0 - tinybench: 2.9.0 - tinyexec: 0.3.1 - tinypool: 1.0.2 - tinyrainbow: 1.2.0 - vite: 5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) - vite-node: 2.1.8(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 22.14.0 - jsdom: 26.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - vitest@2.1.9(@types/node@22.14.0)(jsdom@26.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(sass@1.86.3)(terser@5.39.0): dependencies: '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.17(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0)) + '@vitest/mocker': 2.1.9(vite@5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0)) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 - chai: 5.2.0 + chai: 5.1.2 debug: 4.4.0(supports-color@8.1.1) - expect-type: 1.2.1 - magic-string: 0.30.17 + expect-type: 1.1.0 + magic-string: 0.30.14 pathe: 1.1.2 - std-env: 3.9.0 + std-env: 3.8.0 tinybench: 2.9.0 - tinyexec: 0.3.2 + tinyexec: 0.3.1 tinypool: 1.0.2 tinyrainbow: 1.2.0 - vite: 5.4.17(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) + vite: 5.4.11(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) vite-node: 2.1.9(@types/node@22.14.0)(sass@1.86.3)(terser@5.39.0) why-is-node-running: 2.3.0 optionalDependencies: @@ -38249,10 +36997,6 @@ snapshots: web-namespaces@2.0.1: {} - web-solc@0.5.1: - dependencies: - semver: 7.7.1 - web-streams-polyfill@3.3.3: {} web3-bzz@1.10.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): @@ -38870,7 +37614,7 @@ snapshots: webpack-bundle-analyzer@4.10.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: '@discoveryjs/json-ext': 0.5.7 - acorn: 8.14.1 + acorn: 8.15.0 acorn-walk: 8.3.4 commander: 7.2.0 debounce: 1.2.1 @@ -38996,7 +37740,7 @@ snapshots: which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.2 @@ -39319,10 +38063,6 @@ snapshots: colorette: 2.0.20 zod: 3.24.2 - zod-to-json-schema@3.23.2(zod@3.24.2): - dependencies: - zod: 3.24.2 - zod-to-json-schema@3.24.5(zod@3.24.2): dependencies: zod: 3.24.2 From e776771668b58c35ef434633d3ad3dc5d0dca05b Mon Sep 17 00:00:00 2001 From: saturn Date: Sat, 7 Mar 2026 16:15:10 +0900 Subject: [PATCH 09/13] fix(cli): prevent spinner output corruption (#1858) Co-authored-by: dbeal --- packages/builder/src/index.ts | 1 + packages/builder/src/logger.ts | 41 ++++++++++++++++++++++++++++++++ packages/builder/src/registry.ts | 33 +++++++++++++------------ packages/cli/src/index.ts | 20 +++++++++------- packages/cli/src/util/console.ts | 13 ++++++++++ 5 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 packages/builder/src/logger.ts diff --git a/packages/builder/src/index.ts b/packages/builder/src/index.ts index dc18fef9a..b72103fb0 100644 --- a/packages/builder/src/index.ts +++ b/packages/builder/src/index.ts @@ -18,6 +18,7 @@ export type { TraceEntry } from './trace'; export { traceActions, CannonError } from './error'; export { prepareMulticall } from './multicall'; export { CannonRegistry, OnChainRegistry, InMemoryRegistry, FallbackRegistry } from './registry'; +export { setBuilderLogger, type Logger } from './logger'; export * from './package'; export { CANNON_CHAIN_ID, diff --git a/packages/builder/src/logger.ts b/packages/builder/src/logger.ts new file mode 100644 index 000000000..c6dc5d580 --- /dev/null +++ b/packages/builder/src/logger.ts @@ -0,0 +1,41 @@ +/** + * Logger interface for builder package + * Allows CLI to pass in spinner-aware logging functions + */ +export interface Logger { + log: (...args: any[]) => void; + error: (...args: any[]) => void; + warn: (...args: any[]) => void; +} + +/** + * Default console logger (used when no custom logger is provided) + */ +/* eslint-disable no-console */ +export const defaultLogger: Logger = { + // eslint-disable-next-line no-console + log: console.log.bind(console), + // eslint-disable-next-line no-console + error: console.error.bind(console), + // eslint-disable-next-line no-console + warn: console.warn.bind(console), +}; +/* eslint-enable no-console */ + +// Module-level logger that can be set by CLI to coordinate with spinner +let _logger: Logger = defaultLogger; + +/** + * Set the logger for the builder package. + * This should be called by the CLI at startup to provide a spinner-aware logger. + */ +export function setBuilderLogger(newLogger: Logger) { + _logger = newLogger; +} + +/** + * Get the current builder logger instance. + */ +export function getBuilderLogger(): Logger { + return _logger; +} diff --git a/packages/builder/src/registry.ts b/packages/builder/src/registry.ts index db48a9305..d8d3aa459 100644 --- a/packages/builder/src/registry.ts +++ b/packages/builder/src/registry.ts @@ -1,5 +1,3 @@ -/* eslint-disable no-console */ - import { blueBright, bold, yellow } from 'chalk'; import Debug from 'debug'; import _ from 'lodash'; @@ -10,6 +8,7 @@ import { getIpfsUrl } from './ipfs'; import { prepareMulticall, TxData } from './multicall'; import { PackageReference } from './package-reference'; import { CannonSigner } from './types'; +import { getBuilderLogger } from './logger'; const debug = Debug('cannon:builder:registry'); @@ -342,26 +341,26 @@ export class OnChainRegistry extends CannonRegistry { const variant = `${chainId}-${preset}`; const tags = refs.map((ref) => ref.version); - console.log(`Package: ${name}`); + getBuilderLogger().log(`Package: ${name}`); if (preset !== PackageReference.DEFAULT_PRESET) { - console.log(`Preset: ${preset}`); + getBuilderLogger().log(`Preset: ${preset}`); } - console.log(`Tags: ${tags.join(', ')}`); + getBuilderLogger().log(`Tags: ${tags.join(', ')}`); if (url) { - console.log(`Package URL: ${url}`); + getBuilderLogger().log(`Package URL: ${url}`); } if (metaUrl) { - console.log(`Metadata URL: ${metaUrl}`); + getBuilderLogger().log(`Metadata URL: ${metaUrl}`); } if (mutabilityOverride) { - console.log(`Mutability Override: ${mutabilityOverride}`); + getBuilderLogger().log(`Mutability Override: ${mutabilityOverride}`); } - console.log('\n'); + getBuilderLogger().log('\n'); return { name, variant, tags, url, metaUrl }; } @@ -472,7 +471,7 @@ export class OnChainRegistry extends CannonRegistry { metaUrl?: string, mutabilityOverride?: 'version' | 'tag' ): Promise { - console.log(bold(blueBright('\nPublishing package to the registry on-chain...\n'))); + getBuilderLogger().log(bold(blueBright('\nPublishing package to the registry on-chain...\n'))); const packageData = this._preparePackageData(packagesNames, chainId, url, metaUrl, mutabilityOverride); return [await this._publishPackages([packageData])]; } @@ -486,19 +485,19 @@ export class OnChainRegistry extends CannonRegistry { mutabilityOverride?: 'version' | 'tag'; }[] ): Promise { - console.log(bold(blueBright('\nPublishing packages to the registry on-chain...\n'))); + getBuilderLogger().log(bold(blueBright('\nPublishing packages to the registry on-chain...\n'))); const packageDatas = toPublish.map((p) => this._preparePackageData(p.packagesNames, p.chainId, p.url, p.metaUrl)); return [await this._publishPackages(packageDatas)]; } async unpublish(packagesNames: string[], chainId: number): Promise { - console.log(bold(blueBright('\nUnpublishing package to the registry on-chain...\n'))); + getBuilderLogger().log(bold(blueBright('\nUnpublishing package to the registry on-chain...\n'))); const packageData = this._preparePackageData(packagesNames, chainId); return [await this._unpublishPackages([packageData])]; } async unpublishMany(toUnpublish: { name: string[]; chainId: number }[]): Promise { - console.log(bold(blueBright('\nUnpublishing packages to the registry on-chain...\n'))); + getBuilderLogger().log(bold(blueBright('\nUnpublishing packages to the registry on-chain...\n'))); const packageDatas = toUnpublish.map((p) => this._preparePackageData(p.name, p.chainId)); return [await this._unpublishPackages(packageDatas)]; } @@ -817,15 +816,15 @@ export class OnChainRegistry extends CannonRegistry { ); } - console.log(`\nEstimated gas: ${simulatedGas} wei`); + getBuilderLogger().log(`\nEstimated gas: ${simulatedGas} wei`); const gasPrice = BigInt(this.overrides.maxFeePerGas || this.overrides.gasPrice || (await this.provider.getGasPrice())); - console.log(`\nGas price: ${viem.formatEther(gasPrice)} ETH`); + getBuilderLogger().log(`\nGas price: ${viem.formatEther(gasPrice)} ETH`); const transactionFeeWei = simulatedGas * gasPrice; - console.log(`\nEstimated transaction Fee: ${viem.formatEther(transactionFeeWei)} ETH\n\n`); + getBuilderLogger().log(`\nEstimated transaction Fee: ${viem.formatEther(transactionFeeWei)} ETH\n\n`); if (this.signer && userBalance < transactionFeeWei) { - console.log( + getBuilderLogger().warn( bold( yellow( `The address "${this.signer.address}" does not have enough funds to pay for the transaction, the transaction will likely revert.\n` diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 083369831..763d1f058 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -38,7 +38,7 @@ import { PackageSpecification } from './types'; import { doBuild } from './util/build'; import { setDebugLevel } from './util/debug-level'; -import { log, error, logSpinner, warnSpinner, errorSpinner, logSpinnerEnd, spinner } from './util/console'; +import { log, error, logSpinner, warnSpinner, logSpinnerEnd, spinner } from './util/console'; import { getContractsRecursive } from './util/contracts-recursive'; import { applyCommandsConfig } from './util/commands-config'; import { @@ -685,10 +685,12 @@ applyCommandsConfig(program.command('prune'), commandsConfig.prune).action(async ); if (pruneUrls.length) { - logSpinner(bold(`Found ${pruneUrls.length} storage artifacts to prune.`)); - logSpinner(`Matched with Registry: ${pruneStats.matchedFromRegistry}`); - logSpinner(`Not Expired: ${pruneStats.notExpired}`); - logSpinner(`Not Cannon Package: ${pruneStats.notCannonPackage}`); + logSpinnerEnd(); + log(bold(`Found ${pruneUrls.length} storage artifacts to prune.`)); + log(`Matched with Registry: ${pruneStats.matchedFromRegistry}`); + log(`Not Expired: ${pruneStats.notExpired}`); + log(`Not Cannon Package: ${pruneStats.notCannonPackage}`); + log(); if (options.dryRun) { process.exit(0); @@ -703,21 +705,21 @@ applyCommandsConfig(program.command('prune'), commandsConfig.prune).action(async }); if (!verification.confirmation) { - logSpinner('Cancelled'); + log('Cancelled'); process.exit(1); } } for (const url of pruneUrls) { - logSpinner(`delete ${url}`); + log(`delete ${url}`); try { await storage.deleteBlob(url); } catch (err: any) { - errorSpinner(`Failed to delete ${url}: ${err.message}`); + error(`Failed to delete ${url}: ${err.message}`); } } - logSpinner('Done!'); + log('Done!'); } else { logSpinner(bold('Nothing to prune.')); } diff --git a/packages/cli/src/util/console.ts b/packages/cli/src/util/console.ts index 9547b1942..bf0983571 100644 --- a/packages/cli/src/util/console.ts +++ b/packages/cli/src/util/console.ts @@ -1,5 +1,6 @@ /* eslint-disable no-console */ import { createSpinner } from 'nanospinner'; +import { setBuilderLogger, type Logger } from '@usecannon/builder'; // Detect if we're in a test environment or non-TTY environment const isTestEnv = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined; @@ -111,3 +112,15 @@ export const logSpinnerEnd = () => { // Ignore spinner errors on cleanup } }; + +/** + * Logger for builder package that coordinates with the CLI spinner + */ +export const builderLogger: Logger = { + log: logSpinner, + error: errorSpinner, + warn: warnSpinner, +}; + +// Wire up the builder logger to coordinate with CLI spinner +setBuilderLogger(builderLogger); From a735b85f014f3d49050f1ce614d269c6a84cfc90 Mon Sep 17 00:00:00 2001 From: saturn Date: Sat, 7 Mar 2026 16:17:31 +0900 Subject: [PATCH 10/13] feat(lsp): add cannonfile fragment schema and include field (#1857) --- packages/builder/src/schemas.ts | 234 ++++++++++++++----------- packages/lsp/scripts/generateSchema.js | 17 +- packages/lsp/src/schema-fragment.json | 1 + packages/lsp/src/schema.json | 2 +- 4 files changed, 153 insertions(+), 101 deletions(-) create mode 100644 packages/lsp/src/schema-fragment.json diff --git a/packages/builder/src/schemas.ts b/packages/builder/src/schemas.ts index c73355be7..bca04c1a7 100644 --- a/packages/builder/src/schemas.ts +++ b/packages/builder/src/schemas.ts @@ -880,6 +880,103 @@ export const varSchema = z }) .catchall(z.string()); +/** + * Shared schema for cannonfile actions (operations). + * Used by both the full cannonfile schema and the fragment schema. + */ +const cannonfileActionsSchema = z.object({ + /** + * Object that allows the definition of values for use in next operations + * ```toml + * [settings.owner] + * defaultValue: "some-eth-address" + * ``` + */ + setting: z + .record( + z + .object({ + /** + * Description of the operation + */ + description: z.string().describe('Description of the operation'), + /** + * Data type of the value being stored + */ + type: z.enum(['number', 'string', 'boolean']).describe('Data type of the value being stored'), + /** + * Stored value of the setting + */ + defaultValue: z.string().describe('Stored value of the setting'), + }) + .partial() + ) + .describe( + '⚠ Deprecated in favor of var. A setting is a variable that can be set (or overriden using the CLI) when building a Cannonfile. It is accessible elsewhere in the file a property of the settings object. For example, [setting.sampleSetting] can be referenced with <%= settings.sampleSetting %>' + ), + /** + * @internal + */ + pull: z + .record(pullSchema) + .describe( + 'Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to.' + ), + /** + * @internal + */ + import: z + .record(pullSchema) + .describe( + '⚠ Deprecated in favor of pull. Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to.' + ), + /** + * @internal + */ + clone: z + .record(cloneSchema) + .describe( + 'Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370).' + ), + /** + * @internal + */ + provision: z + .record(cloneSchema) + .describe( + '⚠ Deprecated in favor of clone. Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370).' + ), + /** + * @internal + */ + deploy: z.record(deploySchema).describe('Deploy a contract.'), + /** + * @internal + */ + contract: z.record(deploySchema).describe('⚠ Deprecated in favor of deploy. Deploy a contract.'), + /** + * @internal + */ + invoke: z.record(invokeSchema).describe('Call a function.'), + /** + * @internal + */ + router: z + .record(routerSchema) + .describe('Generate a contract that proxies calls to multiple contracts using the synthetix router codegen.'), + /** + * @internal + */ + diamond: z + .record(diamondSchema) + .describe('Generate a upgradable contract that proxies calls to multiple contracts using a ERC2535 Diamond standard.'), + /** + * @internal + */ + var: z.record(varSchema).describe('Apply a setting or intermediate value.'), + // ... there may be others that come from plugins +}); + /** * @internal NOTE: if you edit this schema, please also edit the constructor of ChainDefinition in 'definition.ts' to account for non-operation components */ @@ -915,6 +1012,16 @@ export const chainDefinitionSchema = z 'Preset of the package (Presets are useful for distinguishing multiple deployments of the same protocol on the same chain.) Defaults to "main".' ) .optional(), + /** + * List of additional TOML files to include and merge into this cannonfile. + * Files are merged in order, with later files overriding earlier ones. + */ + include: z + .array(z.string()) + .describe( + 'List of additional TOML files to include and merge into this cannonfile. Files are merged in order, with later files overriding earlier ones.' + ) + .optional(), /** * Whether or not source code from local package should be bundled in the package. * NOTE: If this is set to true, it will not be possible to verify your contracts on etherscan with cannon @@ -946,101 +1053,32 @@ export const chainDefinitionSchema = z .describe('Any deployers that could publish this package. Will be used for automatic version management.') .optional(), }) - .merge( - z - .object({ - /** - * Object that allows the definition of values for use in next operations - * ```toml - * [settings.owner] - * defaultValue: "some-eth-address" - * ``` - */ - setting: z - .record( - z - .object({ - /** - * Description of the operation - */ - description: z.string().describe('Description of the operation'), - /** - * Data type of the value being stored - */ - type: z.enum(['number', 'string', 'boolean']).describe('Data type of the value being stored'), - /** - * Stored value of the setting - */ - defaultValue: z.string().describe('Stored value of the setting'), - }) - .partial() - ) - .describe( - '⚠ Deprecated in favor of var. A setting is a variable that can be set (or overriden using the CLI) when building a Cannonfile. It is accessible elsewhere in the file a property of the settings object. For example, [setting.sampleSetting] can be referenced with <%= settings.sampleSetting %>' - ), - /** - * @internal - */ - pull: z - .record(pullSchema) - .describe( - 'Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to.' - ), - /** - * @internal - */ - import: z - .record(pullSchema) - .describe( - '⚠ Deprecated in favor of pull. Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to.' - ), - /** - * @internal - */ - clone: z - .record(cloneSchema) - .describe( - 'Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370).' - ), - /** - * @internal - */ - provision: z - .record(cloneSchema) - .describe( - '⚠ Deprecated in favor of clone. Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370).' - ), - /** - * @internal - */ - deploy: z.record(deploySchema).describe('Deploy a contract.'), - /** - * @internal - */ - contract: z.record(deploySchema).describe('⚠ Deprecated in favor of deploy. Deploy a contract.'), - /** - * @internal - */ - invoke: z.record(invokeSchema).describe('Call a function.'), - /** - * @internal - */ - router: z - .record(routerSchema) - .describe('Generate a contract that proxies calls to multiple contracts using the synthetix router codegen.'), - /** - * @internal - */ - diamond: z - .record(diamondSchema) - .describe( - 'Generate a upgradable contract that proxies calls to multiple contracts using a ERC2535 Diamond standard.' - ), - /** - * @internal - */ - var: z.record(varSchema).describe('Apply a setting or intermediate value.'), - // ... there may be others that come from plugins - }) - .deepPartial() - ); + .merge(cannonfileActionsSchema.deepPartial()); + +/** + * Schema for cannonfile fragments - TOML files that are meant to be included + * from a main cannonfile and don't require top-level package metadata. + * + * Fragments can contain all the same actions as a full cannonfile but omit: + * - name (required for publishing) + * - version (required for publishing) + * - preset (optional in both) + * - privateSourceCode (only main cannonfile should define) + * - description (only main cannonfile should define) + * - keywords (only main cannonfile should define) + * - deployers (only main cannonfile should define) + */ +export const cannonfileFragmentSchema = z + .object({ + /** + * List of additional TOML files to include and merge into this fragment. + * Files are merged in order, with later files overriding earlier ones. + */ + include: z + .array(z.string()) + .describe( + 'List of additional TOML files to include and merge into this fragment. Files are merged in order, with later files overriding earlier ones.' + ) + .optional(), + }) + .merge(cannonfileActionsSchema.deepPartial()); diff --git a/packages/lsp/scripts/generateSchema.js b/packages/lsp/scripts/generateSchema.js index 4b15ee7c6..346f96f02 100644 --- a/packages/lsp/scripts/generateSchema.js +++ b/packages/lsp/scripts/generateSchema.js @@ -1,8 +1,21 @@ -import { chainDefinitionSchema } from '@usecannon/builder/dist/src/schemas.js'; +import { + chainDefinitionSchema, + cannonfileFragmentSchema, +} from '@usecannon/builder/dist/src/schemas.js'; import { zodToJsonSchema } from 'zod-to-json-schema'; import fs from 'fs'; +import path from 'path'; +// Generate full cannonfile schema (requires name, version) fs.writeFileSync( - 'schema.json', + path.join('src', 'schema.json'), JSON.stringify(zodToJsonSchema(chainDefinitionSchema)) ); + +// Generate fragment schema (for included TOML files without header) +fs.writeFileSync( + path.join('src', 'schema-fragment.json'), + JSON.stringify(zodToJsonSchema(cannonfileFragmentSchema)) +); + +console.log('Generated schema.json and schema-fragment.json'); diff --git a/packages/lsp/src/schema-fragment.json b/packages/lsp/src/schema-fragment.json new file mode 100644 index 000000000..9bacce2fe --- /dev/null +++ b/packages/lsp/src/schema-fragment.json @@ -0,0 +1 @@ +{"type":"object","properties":{"include":{"type":"array","items":{"type":"string"},"description":"List of additional TOML files to include and merge into this fragment. Files are merged in order, with later files overriding earlier ones."},"setting":{"type":"object","additionalProperties":{"type":"object","properties":{"description":{"type":"string","description":"Description of the operation"},"type":{"type":"string","enum":["number","string","boolean"],"description":"Data type of the value being stored"},"defaultValue":{"type":"string","description":"Stored value of the setting"}},"additionalProperties":false},"description":"⚠ Deprecated in favor of var. A setting is a variable that can be set (or overriden using the CLI) when building a Cannonfile. It is accessible elsewhere in the file a property of the settings object. For example, [setting.sampleSetting] can be referenced with <%= settings.sampleSetting %>"},"pull":{"type":"object","additionalProperties":{"type":"object","properties":{"source":{"type":"string","description":"Source of the cannonfile package to import from. Can be a cannonfile operation name or package name"},"description":{"type":"string","description":"Description of the operation"},"chainId":{"type":"integer","description":"ID of the chain to import the package from"},"preset":{"type":"string","description":"Preset label of the package being imported"},"chains":{"type":"array","items":{"type":"integer"}},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["source"],"additionalProperties":false},"description":"Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to."},"import":{"type":"object","additionalProperties":{"$ref":"#/properties/pull/additionalProperties"},"description":"⚠ Deprecated in favor of pull. Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to."},"clone":{"type":"object","additionalProperties":{"type":"object","properties":{"source":{"type":"string","description":"Name of the package to provision"},"description":{"type":"string","description":"Description of the operation"},"chainId":{"type":"integer","description":"ID of the chain to import the package from. Default - 13370"},"sourcePreset":{"type":"string","description":"⚠ Deprecated in favor of appending @PRESET_NAME to source. Override the preset to use when provisioning this package. Default - \"main\""},"target":{"type":"string","description":"Name of the package to clone"},"targetPreset":{"type":"string","description":"⚠ Deprecated in favor using target only with format packageName:version@targetPreset. Set the new preset to use for this package. Default - \"main\""},"var":{"type":"object","additionalProperties":{"type":"string"},"description":"The settings to be used when initializing this Cannonfile. Overrides any defaults preset in the source package."},"options":{"type":"object","additionalProperties":{"type":"string"},"description":"⚠ Deprecated in favor of var. The settings to be used when initializing this Cannonfile. Overrides any defaults preset in the source package."},"tags":{"type":"array","items":{"type":"string"},"description":"Additional tags to set on the registry for when this provisioned package is published."},"chains":{"type":"array","items":{"type":"integer"}},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["source"],"additionalProperties":false},"description":"Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370)."},"provision":{"type":"object","additionalProperties":{"$ref":"#/properties/clone/additionalProperties"},"description":"⚠ Deprecated in favor of clone. Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370)."},"deploy":{"type":"object","additionalProperties":{"type":"object","properties":{"artifact":{"type":"string","description":"Artifact name of the target contract"},"description":{"type":"string","description":"Description of the operation"},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"},"create2":{"anyOf":[{"type":"boolean"},{"type":"string"}],"description":"Determines whether to deploy the contract using create2. If an address is specified, the arachnid create2 contract will be deployed/used from this address."},"ifExists":{"type":"string","enum":["continue"]},"from":{"type":"string","description":"Contract deployer address. Must match the ethereum address format"},"nonce":{"type":["string","number"],"description":"-"},"abi":{"type":"string","description":"Abi of the contract being deployed"},"abiOf":{"type":"array","items":{"type":"string"},"description":"An array of contract artifacts that have already been deployed with Cannon. This is useful when deploying proxy contracts."},"args":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"object","additionalProperties":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"}},{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"}}]},"description":"Constructor or initializer args"},"libraries":{"type":"object","additionalProperties":{"type":"string"},"description":"An array of contract operation names that deploy libraries this contract depends on."},"salt":{"type":"string","description":"Used to force new copy of a contract (not actually used)"},"value":{"type":"string","description":"Native currency value to send in the transaction"},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"},"simulate":{"type":"boolean"}},"additionalProperties":false,"description":"Override transaction settings"},"chains":{"type":"array","items":{"type":"integer"}},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["artifact"],"additionalProperties":false},"description":"Deploy a contract."},"contract":{"type":"object","additionalProperties":{"$ref":"#/properties/deploy/additionalProperties"},"description":"⚠ Deprecated in favor of deploy. Deploy a contract."},"invoke":{"type":"object","additionalProperties":{"type":"object","properties":{"target":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/properties/invoke/additionalProperties/properties/target/anyOf/0"},"minItems":1}],"description":"Names of the contract to call or contract operation that deployed the contract to call"},"func":{"type":"string","description":"Name of the function to call on the contract"},"description":{"type":"string","description":"Description of the operation"},"abi":{"type":"string","description":"JSON file of the contract ABI. Required if the target contains an address rather than a contract operation name."},"args":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"Arguments to use when invoking this call."},"from":{"type":"string","description":"The calling address to use when invoking this call."},"fromCall":{"type":"object","properties":{"func":{"type":"string","description":"The name of a view function to call on this contract. The result will be used as the from input."},"args":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"The arguments to pass into the function being called."}},"required":["func"],"additionalProperties":false,"description":"Specify a function to use as the 'from' value in a function call. Example `owner()`."},"value":{"type":"string","description":"The amount of ether/wei to send in the transaction."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"required":["gasLimit"],"additionalProperties":false,"description":"Override transaction settings"},"var":{"type":"object","additionalProperties":{"type":"object","properties":{"event":{"type":"string","description":"Name of the event to get data for"},"arg":{"type":"integer","description":"Data argument of the event output"},"expectCount":{"type":"integer","description":"Number of matching contract events which should be seen by this event (default 1) (set to 0 to make optional)"},"allowEmptyEvents":{"type":"boolean","description":"Bypass error messages if an event is expected in the invoke operation but none are emitted in the transaction."}},"required":["event","arg"],"additionalProperties":false},"description":"Object defined to hold transaction result data in a setting. For now its limited to getting event data so it can be reused in other operations"},"extra":{"type":"object","additionalProperties":{"$ref":"#/properties/invoke/additionalProperties/properties/var/additionalProperties"},"description":"⚠ Deprecated in favor of var. Object defined to hold transaction result data in a setting. For now its limited to getting event data so it can be reused in other operations. Use `var` instead."},"factory":{"type":"object","additionalProperties":{"type":"object","properties":{"event":{"type":"string","description":"Name of the event to get data for"},"arg":{"type":"integer","description":"Data argument of the event output"},"expectCount":{"type":"integer","description":"Number of matching contract events which should be seen by this event (default 1) (set to 0 to make optional)"},"artifact":{"type":"string","description":"Name of the contract artifact"},"abiOf":{"type":"array","items":{"type":"string"},"description":"An array of contract artifacts that have already been deployed with Cannon. Used if the code for the deployed contract is not available in the artifacts."},"abi":{"type":"string","description":"Abi of the contract being deployed"},"constructorArgs":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"Constructor or initializer args"},"allowEmptyEvents":{"type":"boolean","description":"Bypass error messages if an event is expected in the invoke operation but none are emitted in the transaction."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["event","arg"],"additionalProperties":false},"description":"Object defined to hold deployment transaction result data. For now its limited to getting deployment event data so it can be reused in other operations"},"chains":{"type":"array","items":{"type":"integer"},"description":"If specified, this action is only executed on the specified chain IDs."},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["target","func"],"additionalProperties":false},"description":"Call a function."},"router":{"type":"object","additionalProperties":{"type":"object","properties":{"contracts":{"type":"array","items":{"type":"string"},"description":"Set of contracts that will be passed to the router"},"description":{"type":"string","description":"Description of the operation"},"includeReceive":{"type":"boolean"},"includeDiamondCompatibility":{"type":"boolean"},"from":{"type":"string","description":"Address to pass to the from call"},"salt":{"type":"string","description":"Used to force new copy of a contract (not actually used)"},"create2":{"anyOf":[{"type":"boolean"},{"type":"string"}],"description":"Determines whether to deploy the contract using create2. If an address is specified, the arachnid create2 contract will be deployed/used from this address."},"ifExists":{"type":"string","enum":["continue"],"description":"When deploying a contract with CREATE2, determines the behavior when the target contract is already deployed (ex. due to same bytecode and salt). Set to continue to allow the build to continue if the contract is found to have already been deployed. By default, an error is thrown and the action is halted."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"additionalProperties":false,"description":"Override transaction settings"},"chains":{"type":"array","items":{"type":"integer"},"description":"If specified, this action is only executed on the specified chain IDs."},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["contracts"],"additionalProperties":false},"description":"Generate a contract that proxies calls to multiple contracts using the synthetix router codegen."},"diamond":{"type":"object","additionalProperties":{"type":"object","properties":{"contracts":{"type":"array","items":{"type":"string"},"description":"Set of contracts that should be facets of the Diamond proxy"},"description":{"type":"string","description":"Description of the action"},"salt":{"type":"string","description":"Used to force new copy of a contract."},"diamondArgs":{"type":"object","properties":{"owner":{"type":"string","description":"Address has permission to change Diamond facets (ie proxied contracts to upgrade)"},"init":{"type":"string","description":"Address to DELEGATECALL on diamondCut() or constructor after the facets have been set"},"initCalldata":{"type":"string","description":"Additional data to send to the `init` DELEGATECALL"}},"required":["owner"],"additionalProperties":false},"immutable":{"type":"boolean","description":"Prevents the diamond proxy from being modified in the future. Setting this value to `true` is irreversable once deployed."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"additionalProperties":false,"description":"Override transaction settings"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["contracts","salt","diamondArgs"],"additionalProperties":false},"description":"Generate a upgradable contract that proxies calls to multiple contracts using a ERC2535 Diamond standard."},"var":{"type":"object","additionalProperties":{"type":"object","properties":{"defaultValue":{"type":"string","description":"⚠ Deprecated in favor of var. The value to set in the setting"},"description":{"type":"string","description":"Description of the operation"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"additionalProperties":{"type":"string"}},"description":"Apply a setting or intermediate value."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"} \ No newline at end of file diff --git a/packages/lsp/src/schema.json b/packages/lsp/src/schema.json index fdc3dfce8..367de9803 100644 --- a/packages/lsp/src/schema.json +++ b/packages/lsp/src/schema.json @@ -1 +1 @@ -{"type":"object","properties":{"name":{"type":"string","minLength":3,"description":"Name of the package"},"version":{"type":"string","description":"Version of the package. Publishes as the \"latest\" version by default in addition to the version specified here."},"preset":{"type":"string","description":"Preset of the package (Presets are useful for distinguishing multiple deployments of the same protocol on the same chain.) Defaults to \"main\"."},"privateSourceCode":{"type":"boolean","description":"Turns off inclusion of source code in packages. When set to true, Cannon cannot verify contracts on Etherscan. Defaults to false."},"description":{"type":"string","description":"Description for the package"},"keywords":{"type":"array","items":{"type":"string"},"description":"Keywords for search indexing"},"deployers":{"type":"array","items":{"type":"string"},"description":"Any deployers that could publish this package. Will be used for automatic version management."},"setting":{"type":"object","additionalProperties":{"type":"object","properties":{"description":{"type":"string","description":"Description of the operation"},"type":{"type":"string","enum":["number","string","boolean"],"description":"Data type of the value being stored"},"defaultValue":{"type":"string","description":"Stored value of the setting"}},"additionalProperties":false},"description":"⚠ Deprecated in favor of var. A setting is a variable that can be set (or overriden using the CLI) when building a Cannonfile. It is accessible elsewhere in the file a property of the settings object. For example, [setting.sampleSetting] can be referenced with <%= settings.sampleSetting %>"},"pull":{"type":"object","additionalProperties":{"type":"object","properties":{"source":{"type":"string","description":"Source of the cannonfile package to import from. Can be a cannonfile operation name or package name"},"description":{"type":"string","description":"Description of the operation"},"chainId":{"type":"integer","description":"ID of the chain to import the package from"},"preset":{"type":"string","description":"Preset label of the package being imported"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["source"],"additionalProperties":false},"description":"Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to."},"import":{"type":"object","additionalProperties":{"$ref":"#/properties/pull/additionalProperties"},"description":"⚠ Deprecated in favor of pull. Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to."},"clone":{"type":"object","additionalProperties":{"type":"object","properties":{"source":{"type":"string","description":"Name of the package to provision"},"description":{"type":"string","description":"Description of the operation"},"chainId":{"type":"integer","description":"ID of the chain to import the package from. Default - 13370"},"sourcePreset":{"type":"string","description":"⚠ Deprecated in favor of appending @PRESET_NAME to source. Override the preset to use when provisioning this package. Default - \"main\""},"target":{"type":"string","description":"Name of the package to clone"},"targetPreset":{"type":"string","description":"⚠ Deprecated in favor using target only with format packageName:version@targetPreset. Set the new preset to use for this package. Default - \"main\""},"var":{"type":"object","additionalProperties":{"type":"string"},"description":"The settings to be used when initializing this Cannonfile. Overrides any defaults preset in the source package."},"options":{"type":"object","additionalProperties":{"type":"string"},"description":"⚠ Deprecated in favor of var. The settings to be used when initializing this Cannonfile. Overrides any defaults preset in the source package."},"tags":{"type":"array","items":{"type":"string"},"description":"Additional tags to set on the registry for when this provisioned package is published."},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["source"],"additionalProperties":false},"description":"Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370)."},"provision":{"type":"object","additionalProperties":{"$ref":"#/properties/clone/additionalProperties"},"description":"⚠ Deprecated in favor of clone. Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370)."},"deploy":{"type":"object","additionalProperties":{"type":"object","properties":{"artifact":{"type":"string","description":"Artifact name of the target contract"},"description":{"type":"string","description":"Description of the operation"},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"},"create2":{"anyOf":[{"type":"boolean"},{"type":"string"}],"description":"Determines whether to deploy the contract using create2. If an address is specified, the arachnid create2 contract will be deployed/used from this address."},"ifExists":{"type":"string","enum":["continue"]},"from":{"type":"string","description":"Contract deployer address. Must match the ethereum address format"},"nonce":{"type":["string","number"],"description":"-"},"abi":{"type":"string","description":"Abi of the contract being deployed"},"abiOf":{"type":"array","items":{"type":"string"},"description":"An array of contract artifacts that have already been deployed with Cannon. This is useful when deploying proxy contracts."},"args":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"object","additionalProperties":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"}},{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"}}]},"description":"Constructor or initializer args"},"libraries":{"type":"object","additionalProperties":{"type":"string"},"description":"An array of contract operation names that deploy libraries this contract depends on."},"salt":{"type":"string","description":"Used to force new copy of a contract (not actually used)"},"value":{"type":"string","description":"Native currency value to send in the transaction"},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"},"simulate":{"type":"boolean"}},"additionalProperties":false,"description":"Override transaction settings"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["artifact"],"additionalProperties":false},"description":"Deploy a contract."},"contract":{"type":"object","additionalProperties":{"$ref":"#/properties/deploy/additionalProperties"},"description":"⚠ Deprecated in favor of deploy. Deploy a contract."},"invoke":{"type":"object","additionalProperties":{"type":"object","properties":{"target":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/properties/invoke/additionalProperties/properties/target/anyOf/0"},"minItems":1}],"description":"Names of the contract to call or contract operation that deployed the contract to call"},"func":{"type":"string","description":"Name of the function to call on the contract"},"description":{"type":"string","description":"Description of the operation"},"abi":{"type":"string","description":"JSON file of the contract ABI. Required if the target contains an address rather than a contract operation name."},"args":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"Arguments to use when invoking this call."},"from":{"type":"string","description":"The calling address to use when invoking this call."},"fromCall":{"type":"object","properties":{"func":{"type":"string","description":"The name of a view function to call on this contract. The result will be used as the from input."},"args":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"The arguments to pass into the function being called."}},"required":["func"],"additionalProperties":false,"description":"Specify a function to use as the 'from' value in a function call. Example `owner()`."},"value":{"type":"string","description":"The amount of ether/wei to send in the transaction."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"required":["gasLimit"],"additionalProperties":false,"description":"Override transaction settings"},"var":{"type":"object","additionalProperties":{"type":"object","properties":{"event":{"type":"string","description":"Name of the event to get data for"},"arg":{"type":"integer","description":"Data argument of the event output"},"expectCount":{"type":"integer","description":"Number of matching contract events which should be seen by this event (default 1) (set to 0 to make optional)"},"allowEmptyEvents":{"type":"boolean","description":"Bypass error messages if an event is expected in the invoke operation but none are emitted in the transaction."}},"required":["event","arg"],"additionalProperties":false},"description":"Object defined to hold transaction result data in a setting. For now its limited to getting event data so it can be reused in other operations"},"extra":{"type":"object","additionalProperties":{"$ref":"#/properties/invoke/additionalProperties/properties/var/additionalProperties"},"description":"⚠ Deprecated in favor of var. Object defined to hold transaction result data in a setting. For now its limited to getting event data so it can be reused in other operations. Use `var` instead."},"factory":{"type":"object","additionalProperties":{"type":"object","properties":{"event":{"type":"string","description":"Name of the event to get data for"},"arg":{"type":"integer","description":"Data argument of the event output"},"expectCount":{"type":"integer","description":"Number of matching contract events which should be seen by this event (default 1) (set to 0 to make optional)"},"artifact":{"type":"string","description":"Name of the contract artifact"},"abiOf":{"type":"array","items":{"type":"string"},"description":"An array of contract artifacts that have already been deployed with Cannon. Used if the code for the deployed contract is not available in the artifacts."},"abi":{"type":"string","description":"Abi of the contract being deployed"},"constructorArgs":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"Constructor or initializer args"},"allowEmptyEvents":{"type":"boolean","description":"Bypass error messages if an event is expected in the invoke operation but none are emitted in the transaction."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["event","arg"],"additionalProperties":false},"description":"Object defined to hold deployment transaction result data. For now its limited to getting deployment event data so it can be reused in other operations"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["target","func"],"additionalProperties":false},"description":"Call a function."},"router":{"type":"object","additionalProperties":{"type":"object","properties":{"contracts":{"type":"array","items":{"type":"string"},"description":"Set of contracts that will be passed to the router"},"description":{"type":"string","description":"Description of the operation"},"includeReceive":{"type":"boolean"},"from":{"type":"string","description":"Address to pass to the from call"},"salt":{"type":"string","description":"Used to force new copy of a contract (not actually used)"},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"additionalProperties":false,"description":"Override transaction settings"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["contracts"],"additionalProperties":false},"description":"Generate a contract that proxies calls to multiple contracts using the synthetix router codegen."},"diamond":{"type":"object","additionalProperties":{"type":"object","properties":{"contracts":{"type":"array","items":{"type":"string"},"description":"Set of contracts that should be facets of the Diamond proxy"},"description":{"type":"string","description":"Description of the action"},"salt":{"type":"string","description":"Used to force new copy of a contract."},"diamondArgs":{"type":"object","properties":{"owner":{"type":"string","description":"Address has permission to change Diamond facets (ie proxied contracts to upgrade)"},"init":{"type":"string","description":"Address to DELEGATECALL on diamondCut() or constructor after the facets have been set"},"initCalldata":{"type":"string","description":"Additional data to send to the `init` DELEGATECALL"}},"required":["owner"],"additionalProperties":false},"immutable":{"type":"boolean","description":"Prevents the diamond proxy from being modified in the future. Setting this value to `true` is irreversable once deployed."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"additionalProperties":false,"description":"Override transaction settings"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["contracts","salt","diamondArgs"],"additionalProperties":false},"description":"Generate a upgradable contract that proxies calls to multiple contracts using a ERC2535 Diamond standard."},"var":{"type":"object","additionalProperties":{"type":"object","properties":{"defaultValue":{"type":"string","description":"⚠ Deprecated in favor of var. The value to set in the setting"},"description":{"type":"string","description":"Description of the operation"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"additionalProperties":{"type":"string"}},"description":"Apply a setting or intermediate value."}},"required":["name","version"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"} \ No newline at end of file +{"type":"object","properties":{"name":{"type":"string","minLength":3,"description":"Name of the package"},"version":{"type":"string","description":"Version of the package. Publishes as the \"latest\" version by default in addition to the version specified here."},"preset":{"type":"string","description":"Preset of the package (Presets are useful for distinguishing multiple deployments of the same protocol on the same chain.) Defaults to \"main\"."},"include":{"type":"array","items":{"type":"string"},"description":"List of additional TOML files to include and merge into this cannonfile. Files are merged in order, with later files overriding earlier ones."},"privateSourceCode":{"type":"boolean","description":"Turns off inclusion of source code in packages. When set to true, Cannon cannot verify contracts on Etherscan. Defaults to false."},"description":{"type":"string","description":"Description for the package"},"keywords":{"type":"array","items":{"type":"string"},"description":"Keywords for search indexing"},"deployers":{"type":"array","items":{"type":"string"},"description":"Any deployers that could publish this package. Will be used for automatic version management."},"setting":{"type":"object","additionalProperties":{"type":"object","properties":{"description":{"type":"string","description":"Description of the operation"},"type":{"type":"string","enum":["number","string","boolean"],"description":"Data type of the value being stored"},"defaultValue":{"type":"string","description":"Stored value of the setting"}},"additionalProperties":false},"description":"⚠ Deprecated in favor of var. A setting is a variable that can be set (or overriden using the CLI) when building a Cannonfile. It is accessible elsewhere in the file a property of the settings object. For example, [setting.sampleSetting] can be referenced with <%= settings.sampleSetting %>"},"pull":{"type":"object","additionalProperties":{"type":"object","properties":{"source":{"type":"string","description":"Source of the cannonfile package to import from. Can be a cannonfile operation name or package name"},"description":{"type":"string","description":"Description of the operation"},"chainId":{"type":"integer","description":"ID of the chain to import the package from"},"preset":{"type":"string","description":"Preset label of the package being imported"},"chains":{"type":"array","items":{"type":"integer"}},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["source"],"additionalProperties":false},"description":"Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to."},"import":{"type":"object","additionalProperties":{"$ref":"#/properties/pull/additionalProperties"},"description":"⚠ Deprecated in favor of pull. Import a package from the registry. This will make the output of that deployment, such as contract addresses, available to other operations in your Cannonfile. Imported packages must include deployments with chain ID that matches the chain ID of the network you are deploying to."},"clone":{"type":"object","additionalProperties":{"type":"object","properties":{"source":{"type":"string","description":"Name of the package to provision"},"description":{"type":"string","description":"Description of the operation"},"chainId":{"type":"integer","description":"ID of the chain to import the package from. Default - 13370"},"sourcePreset":{"type":"string","description":"⚠ Deprecated in favor of appending @PRESET_NAME to source. Override the preset to use when provisioning this package. Default - \"main\""},"target":{"type":"string","description":"Name of the package to clone"},"targetPreset":{"type":"string","description":"⚠ Deprecated in favor using target only with format packageName:version@targetPreset. Set the new preset to use for this package. Default - \"main\""},"var":{"type":"object","additionalProperties":{"type":"string"},"description":"The settings to be used when initializing this Cannonfile. Overrides any defaults preset in the source package."},"options":{"type":"object","additionalProperties":{"type":"string"},"description":"⚠ Deprecated in favor of var. The settings to be used when initializing this Cannonfile. Overrides any defaults preset in the source package."},"tags":{"type":"array","items":{"type":"string"},"description":"Additional tags to set on the registry for when this provisioned package is published."},"chains":{"type":"array","items":{"type":"integer"}},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["source"],"additionalProperties":false},"description":"Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370)."},"provision":{"type":"object","additionalProperties":{"$ref":"#/properties/clone/additionalProperties"},"description":"⚠ Deprecated in favor of clone. Deploy a new instance of a package from the registry. Packages may only be provisioned if they include a local, Cannon deployment (Chain ID: 13370)."},"deploy":{"type":"object","additionalProperties":{"type":"object","properties":{"artifact":{"type":"string","description":"Artifact name of the target contract"},"description":{"type":"string","description":"Description of the operation"},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"},"create2":{"anyOf":[{"type":"boolean"},{"type":"string"}],"description":"Determines whether to deploy the contract using create2. If an address is specified, the arachnid create2 contract will be deployed/used from this address."},"ifExists":{"type":"string","enum":["continue"]},"from":{"type":"string","description":"Contract deployer address. Must match the ethereum address format"},"nonce":{"type":["string","number"],"description":"-"},"abi":{"type":"string","description":"Abi of the contract being deployed"},"abiOf":{"type":"array","items":{"type":"string"},"description":"An array of contract artifacts that have already been deployed with Cannon. This is useful when deploying proxy contracts."},"args":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"object","additionalProperties":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"}},{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"}}]},"description":"Constructor or initializer args"},"libraries":{"type":"object","additionalProperties":{"type":"string"},"description":"An array of contract operation names that deploy libraries this contract depends on."},"salt":{"type":"string","description":"Used to force new copy of a contract (not actually used)"},"value":{"type":"string","description":"Native currency value to send in the transaction"},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"},"simulate":{"type":"boolean"}},"additionalProperties":false,"description":"Override transaction settings"},"chains":{"type":"array","items":{"type":"integer"}},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["artifact"],"additionalProperties":false},"description":"Deploy a contract."},"contract":{"type":"object","additionalProperties":{"$ref":"#/properties/deploy/additionalProperties"},"description":"⚠ Deprecated in favor of deploy. Deploy a contract."},"invoke":{"type":"object","additionalProperties":{"type":"object","properties":{"target":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/properties/invoke/additionalProperties/properties/target/anyOf/0"},"minItems":1}],"description":"Names of the contract to call or contract operation that deployed the contract to call"},"func":{"type":"string","description":"Name of the function to call on the contract"},"description":{"type":"string","description":"Description of the operation"},"abi":{"type":"string","description":"JSON file of the contract ABI. Required if the target contains an address rather than a contract operation name."},"args":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"Arguments to use when invoking this call."},"from":{"type":"string","description":"The calling address to use when invoking this call."},"fromCall":{"type":"object","properties":{"func":{"type":"string","description":"The name of a view function to call on this contract. The result will be used as the from input."},"args":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"The arguments to pass into the function being called."}},"required":["func"],"additionalProperties":false,"description":"Specify a function to use as the 'from' value in a function call. Example `owner()`."},"value":{"type":"string","description":"The amount of ether/wei to send in the transaction."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"required":["gasLimit"],"additionalProperties":false,"description":"Override transaction settings"},"var":{"type":"object","additionalProperties":{"type":"object","properties":{"event":{"type":"string","description":"Name of the event to get data for"},"arg":{"type":"integer","description":"Data argument of the event output"},"expectCount":{"type":"integer","description":"Number of matching contract events which should be seen by this event (default 1) (set to 0 to make optional)"},"allowEmptyEvents":{"type":"boolean","description":"Bypass error messages if an event is expected in the invoke operation but none are emitted in the transaction."}},"required":["event","arg"],"additionalProperties":false},"description":"Object defined to hold transaction result data in a setting. For now its limited to getting event data so it can be reused in other operations"},"extra":{"type":"object","additionalProperties":{"$ref":"#/properties/invoke/additionalProperties/properties/var/additionalProperties"},"description":"⚠ Deprecated in favor of var. Object defined to hold transaction result data in a setting. For now its limited to getting event data so it can be reused in other operations. Use `var` instead."},"factory":{"type":"object","additionalProperties":{"type":"object","properties":{"event":{"type":"string","description":"Name of the event to get data for"},"arg":{"type":"integer","description":"Data argument of the event output"},"expectCount":{"type":"integer","description":"Number of matching contract events which should be seen by this event (default 1) (set to 0 to make optional)"},"artifact":{"type":"string","description":"Name of the contract artifact"},"abiOf":{"type":"array","items":{"type":"string"},"description":"An array of contract artifacts that have already been deployed with Cannon. Used if the code for the deployed contract is not available in the artifacts."},"abi":{"type":"string","description":"Abi of the contract being deployed"},"constructorArgs":{"type":"array","items":{"$ref":"#/properties/deploy/additionalProperties/properties/args/items"},"description":"Constructor or initializer args"},"allowEmptyEvents":{"type":"boolean","description":"Bypass error messages if an event is expected in the invoke operation but none are emitted in the transaction."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["event","arg"],"additionalProperties":false},"description":"Object defined to hold deployment transaction result data. For now its limited to getting deployment event data so it can be reused in other operations"},"chains":{"type":"array","items":{"type":"integer"},"description":"If specified, this action is only executed on the specified chain IDs."},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"required":["target","func"],"additionalProperties":false},"description":"Call a function."},"router":{"type":"object","additionalProperties":{"type":"object","properties":{"contracts":{"type":"array","items":{"type":"string"},"description":"Set of contracts that will be passed to the router"},"description":{"type":"string","description":"Description of the operation"},"includeReceive":{"type":"boolean"},"includeDiamondCompatibility":{"type":"boolean"},"from":{"type":"string","description":"Address to pass to the from call"},"salt":{"type":"string","description":"Used to force new copy of a contract (not actually used)"},"create2":{"anyOf":[{"type":"boolean"},{"type":"string"}],"description":"Determines whether to deploy the contract using create2. If an address is specified, the arachnid create2 contract will be deployed/used from this address."},"ifExists":{"type":"string","enum":["continue"],"description":"When deploying a contract with CREATE2, determines the behavior when the target contract is already deployed (ex. due to same bytecode and salt). Set to continue to allow the build to continue if the contract is found to have already been deployed. By default, an error is thrown and the action is halted."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"additionalProperties":false,"description":"Override transaction settings"},"chains":{"type":"array","items":{"type":"integer"},"description":"If specified, this action is only executed on the specified chain IDs."},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["contracts"],"additionalProperties":false},"description":"Generate a contract that proxies calls to multiple contracts using the synthetix router codegen."},"diamond":{"type":"object","additionalProperties":{"type":"object","properties":{"contracts":{"type":"array","items":{"type":"string"},"description":"Set of contracts that should be facets of the Diamond proxy"},"description":{"type":"string","description":"Description of the action"},"salt":{"type":"string","description":"Used to force new copy of a contract."},"diamondArgs":{"type":"object","properties":{"owner":{"type":"string","description":"Address has permission to change Diamond facets (ie proxied contracts to upgrade)"},"init":{"type":"string","description":"Address to DELEGATECALL on diamondCut() or constructor after the facets have been set"},"initCalldata":{"type":"string","description":"Additional data to send to the `init` DELEGATECALL"}},"required":["owner"],"additionalProperties":false},"immutable":{"type":"boolean","description":"Prevents the diamond proxy from being modified in the future. Setting this value to `true` is irreversable once deployed."},"overrides":{"type":"object","properties":{"gasLimit":{"type":"string"}},"additionalProperties":false,"description":"Override transaction settings"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."},"highlight":{"type":"boolean","description":"Determines whether contract should get priority in displays"}},"required":["contracts","salt","diamondArgs"],"additionalProperties":false},"description":"Generate a upgradable contract that proxies calls to multiple contracts using a ERC2535 Diamond standard."},"var":{"type":"object","additionalProperties":{"type":"object","properties":{"defaultValue":{"type":"string","description":"⚠ Deprecated in favor of var. The value to set in the setting"},"description":{"type":"string","description":"Description of the operation"},"depends":{"type":"array","items":{"type":"string"},"description":"List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies."}},"additionalProperties":{"type":"string"}},"description":"Apply a setting or intermediate value."}},"required":["name","version"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"} \ No newline at end of file From 841feb02e2f151ab16252f0530046630ac5d1b30 Mon Sep 17 00:00:00 2001 From: AkihisaY <76488710+AkihisaY@users.noreply.github.com> Date: Sun, 8 Mar 2026 18:04:45 +0900 Subject: [PATCH 11/13] feat(website): add pagination feature (#1826) Co-authored-by: Saturn --- packages/website/public/_redirects | 3 +- packages/website/src/constants/pagination.ts | 1 + .../src/features/Address/AddressDataTable.tsx | 27 ++- .../src/features/Address/AddressPage.tsx | 8 +- .../src/features/Address/AddressTxLists.tsx | 5 +- .../features/Txs/AddressTransactionPage.tsx | 42 ++++ .../Txs/TransactionsPaginatedList.tsx | 206 ++++++++++++++++++ .../features/Txs/TransactionsPagination.tsx | 107 +++++++++ .../src/features/Txs/TransactionsSection.tsx | 147 +++++++++++++ .../src/hooks/useAddressTransactions.ts | 14 +- packages/website/src/hooks/useBlockPages.ts | 116 ++++++++++ packages/website/src/pages/txs/index.tsx | 21 ++ packages/website/vercel.json | 4 + 13 files changed, 690 insertions(+), 11 deletions(-) create mode 100644 packages/website/src/constants/pagination.ts create mode 100644 packages/website/src/features/Txs/AddressTransactionPage.tsx create mode 100644 packages/website/src/features/Txs/TransactionsPaginatedList.tsx create mode 100644 packages/website/src/features/Txs/TransactionsPagination.tsx create mode 100644 packages/website/src/features/Txs/TransactionsSection.tsx create mode 100644 packages/website/src/hooks/useBlockPages.ts create mode 100644 packages/website/src/pages/txs/index.tsx diff --git a/packages/website/public/_redirects b/packages/website/public/_redirects index 08db25419..17fce5035 100644 --- a/packages/website/public/_redirects +++ b/packages/website/public/_redirects @@ -9,4 +9,5 @@ /packages/:name/:tag/:variant/cannonfile /packages/[name]/[tag]/[variant]/cannonfile.html 200 /deploy/txn/:chainId/:safeAddress/:nonce/:sigHash /deploy/txn/[chainId]/[safeAddress]/[nonce]/[sigHash].html 200 /address/:chainId/:address /address/[chainId]/[address].html 200 -/tx/:chainId/:txHash /tx/[chainId]/[txHash].html 200 \ No newline at end of file +/tx/:chainId/:txHash /tx/[chainId]/[txHash].html 200 +/txs /txs.html 200 \ No newline at end of file diff --git a/packages/website/src/constants/pagination.ts b/packages/website/src/constants/pagination.ts new file mode 100644 index 000000000..fb42c4a0b --- /dev/null +++ b/packages/website/src/constants/pagination.ts @@ -0,0 +1 @@ +export const MAX_PAGE_SIZE = 100; diff --git a/packages/website/src/features/Address/AddressDataTable.tsx b/packages/website/src/features/Address/AddressDataTable.tsx index 96ba8d6c3..73a77d9b6 100644 --- a/packages/website/src/features/Address/AddressDataTable.tsx +++ b/packages/website/src/features/Address/AddressDataTable.tsx @@ -3,18 +3,24 @@ import { Table, TableBody, TableCell, + TableFooter, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { flexRender } from '@tanstack/react-table'; -import { Inbox } from 'lucide-react'; +import { Inbox, MoveRight } from 'lucide-react'; +import Link from 'next/link'; type AddressDataTableProps = { table: any; + url?: string; }; -const AddressDataTable: React.FC = ({ table }) => { +const AddressDataTable: React.FC = ({ + table, + url = '', +}) => { return ( <> @@ -87,6 +93,23 @@ const AddressDataTable: React.FC = ({ table }) => { )} + {url && ( + + + +
+ + VIEW ALL TRANSACTIONS + + +
+
+
+
+ )}
); diff --git a/packages/website/src/features/Address/AddressPage.tsx b/packages/website/src/features/Address/AddressPage.tsx index 2c6d67be9..73f492520 100644 --- a/packages/website/src/features/Address/AddressPage.tsx +++ b/packages/website/src/features/Address/AddressPage.tsx @@ -23,13 +23,16 @@ const AddressPage = () => { const { getChainById } = useCannonChains(); const chain = getChainById(Number(chainId)); const displayAddress = Array.isArray(address) ? address[0] : address; + const { data: transactionData, isLoading, isError, } = useAddressTransactions( parseInt(chainId as string) || 0, - displayAddress ?? '' + displayAddress ?? '', + '0', + true ); if (isLoading) { @@ -54,7 +57,7 @@ const AddressPage = () => { ); } - const { txs, receipts, oldReceipts } = transactionData; + const { txs, receipts, oldReceipts, isLastPage } = transactionData; const renderContent = () => { if (displayAddress) { @@ -70,6 +73,7 @@ const AddressPage = () => { chain={chain} txs={txs} receipts={receipts} + isLastPage={isLastPage} /> ); } diff --git a/packages/website/src/features/Address/AddressTxLists.tsx b/packages/website/src/features/Address/AddressTxLists.tsx index 1022d79b1..49c053935 100644 --- a/packages/website/src/features/Address/AddressTxLists.tsx +++ b/packages/website/src/features/Address/AddressTxLists.tsx @@ -33,6 +33,7 @@ type AddressListsProps = { chain: Chain; txs: OtterscanTransaction[]; receipts: OtterscanReceipt[]; + isLastPage: boolean; }; const AddressLists: React.FC = ({ @@ -40,6 +41,7 @@ const AddressLists: React.FC = ({ chain, txs, receipts, + isLastPage, }) => { const [isDate, setIsDate] = useState(false); const [isGasPrice, setIsGasPrice] = useState(false); @@ -52,6 +54,7 @@ const AddressLists: React.FC = ({ const columnHelper = createColumnHelper(); const [openToolTipIndex, setOpenTooltipIndex] = useState(); + const url = isLastPage ? '' : `/txs?a=${address}&c=${chain?.id}`; const columns = [ columnHelper.accessor('detail', { cell: (info: any) => ( @@ -164,7 +167,7 @@ const AddressLists: React.FC = ({
- +
diff --git a/packages/website/src/features/Txs/AddressTransactionPage.tsx b/packages/website/src/features/Txs/AddressTransactionPage.tsx new file mode 100644 index 000000000..06f8472d3 --- /dev/null +++ b/packages/website/src/features/Txs/AddressTransactionPage.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { useRouter } from 'next/router'; +import { useCannonChains } from '@/providers/CannonProvidersProvider'; +import TransactionsSection from '@/features/Txs/TransactionsSection'; +import Link from 'next/link'; + +const AddressTransactionPage = () => { + const router = useRouter(); + const { a, c, p } = router.query; + const chainId = Array.isArray(c) ? c[0] : c; + const { getChainById, getExplorerUrl } = useCannonChains(); + const chain = getChainById(Number(chainId)); + const displayAddress = Array.isArray(a) ? a[0] : a; + + const pageIndex = Array.isArray(p) ? p[0] : p; + const explorerUrl = getExplorerUrl(chain?.id || 0, displayAddress ?? ''); + + return ( +
+
+

Transactions

+
+
+ For + + {displayAddress} + +
+
+ +
+ ); +}; + +export default AddressTransactionPage; diff --git a/packages/website/src/features/Txs/TransactionsPaginatedList.tsx b/packages/website/src/features/Txs/TransactionsPaginatedList.tsx new file mode 100644 index 000000000..fcdf99f24 --- /dev/null +++ b/packages/website/src/features/Txs/TransactionsPaginatedList.tsx @@ -0,0 +1,206 @@ +import React, { useState } from 'react'; +import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; +import { CircleHelp } from 'lucide-react'; +import { + createColumnHelper, + useReactTable, + getCoreRowModel, +} from '@tanstack/react-table'; +import AddressAdditionalInfo from '@/features/Address/AddressAdditionalDialog'; +import { Chain } from '@/types/Chain'; +import { mapToTransactionList } from '@/lib/address'; +import { + TransactionRow, + OtterscanTransaction, + OtterscanReceipt, +} from '@/types/AddressList'; +import AmountColumn from '@/features/Address/column/AmountColumn'; +import FromColumn from '@/features/Address/column/FromColumn'; +import ToColumn from '@/features/Address/column/ToColumn'; +import HashColumn from '@/features/Address/column/HashColumn'; +import MethodColumn from '@/features/Address/column/MethodColumn'; +import MethodHeader from '@/features/Address/column/MethodHeader'; +import AgeColumn from '@/features/Address/column/AgeColumn'; +import AgeHeader from '@/features/Address/column/AgeHeader'; +import TxFeeHeader from '@/features/Address/column/TxFeeHeader'; +import TxFeeColumn from '@/features/Address/column/TxFeeColumn'; +import BlockColumn from '@/features/Address/column/BlockColumn'; +import AddressDataTable from '@/features/Address/AddressDataTable'; +import DownloadListButton from '@/features/Address/DownloadListButton'; +import TransactionsPagination from '@/features/Txs/TransactionsPagination'; +import { Alert, AlertDescription } from '@/components/ui/alert'; +import { MAX_PAGE_SIZE } from '@/constants/pagination'; + +type TransactionsPaginatedListProps = { + address: string; + chain: Chain; + txs: OtterscanTransaction[]; + receipts: OtterscanReceipt[]; + isLastPage: boolean; + isFirstPage: boolean; + currentPageIndex: number; // 1-indexed + totalPages: number | null; // null if unknown + totalTxs: number; +}; + +const TransactionsPaginatedList: React.FC = ({ + address, + chain, + txs, + receipts, + isLastPage, + isFirstPage, + currentPageIndex, + totalPages, + totalTxs, +}) => { + const [isDate, setIsDate] = useState(false); + const [isGasPrice, setIsGasPrice] = useState(false); + const [hoverId, setHoverId] = useState(''); + const chainId = chain?.id ?? 0; + const data = React.useMemo(() => { + return mapToTransactionList(txs, receipts); + }, [txs, receipts]); + + const columnHelper = createColumnHelper(); + const [openToolTipIndex, setOpenTooltipIndex] = useState(); + + const columns = [ + columnHelper.accessor('detail', { + cell: (info: any) => ( + + ), + header: () => , + }), + columnHelper.accessor('hash', { + cell: (info: any) => , + header: 'Transaction Hash', + }), + columnHelper.accessor('method', { + cell: (info: any) => , + header: () => , + }), + columnHelper.accessor('blockNumber', { + cell: (info: any) => , + header: 'Block', + }), + columnHelper.accessor('age', { + cell: (info: any) => , + header: () => , + }), + columnHelper.accessor('from', { + cell: (info: any) => ( + + ), + header: 'From', + }), + columnHelper.accessor('to', { + cell: (info: any) => ( + + ), + header: 'To', + }), + columnHelper.accessor('amount', { + cell: (info: any) => ( + + ), + header: 'Amount', + }), + columnHelper.accessor('txnFee', { + cell: (info: any) => , + header: () => ( + + ), + }), + columnHelper.accessor('gasPrice', { + enableHiding: true, + cell: () => null, + header: () => null, + }), + columnHelper.accessor('contractAddress', { + enableHiding: true, + cell: () => null, + header: () => null, + }), + ]; + + const table = useReactTable({ + columns, + data, + getCoreRowModel: getCoreRowModel(), + }); + + const isMaxPage = currentPageIndex >= MAX_PAGE_SIZE; + + return ( + <> + + + {table.getRowModel().rows.length > 0 && ( + <> + +
+
+ + A total of {totalTxs.toLocaleString()} transactions found + +
+
+ + +
+
+ {!isLastPage && isMaxPage && ( + + + This is the maximum number of pages currently supported + by this website. + + + )} +
+ + )} +
+ +
+ +
+
+
+ + ); +}; + +export default TransactionsPaginatedList; diff --git a/packages/website/src/features/Txs/TransactionsPagination.tsx b/packages/website/src/features/Txs/TransactionsPagination.tsx new file mode 100644 index 000000000..77de013f7 --- /dev/null +++ b/packages/website/src/features/Txs/TransactionsPagination.tsx @@ -0,0 +1,107 @@ +import Link from 'next/link'; +import { ChevronRight, ChevronLeft } from 'lucide-react'; +import { MAX_PAGE_SIZE } from '@/constants/pagination'; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from '@/components/ui/tooltip'; + +type TransactionPaginationProp = { + address: string; + chainId: number; + currentPageIndex: number; // 1-indexed page number + isFirstPage: boolean; + isLastPage: boolean; + totalPages: number | null; // null means we don't know yet +}; + +const TransactionsPagination: React.FC = ({ + address, + chainId, + currentPageIndex, + isFirstPage, + isLastPage, + totalPages, +}) => { + const pageClass = (disabled: boolean) => + `items-center px-3 py-1 text-xs border border-gray-500 text-gray-200 rounded ${ + disabled ? 'pointer-events-none opacity-50' : '' + }`; + + const getPageHref = (page: number) => + page === 1 + ? `/txs?a=${address}&c=${chainId}` + : `/txs?a=${address}&c=${chainId}&p=${page}`; + + const displayTotal = totalPages ?? '?'; + const isMaxPage = currentPageIndex >= MAX_PAGE_SIZE; + + return ( +
+ {/* First */} + + First + + + {/* Prev */} + {!isFirstPage ? ( + + + + + + + Go to Previous + + ) : ( + e.preventDefault()}> + + + )} + + {/* Page Info */} + + Page {currentPageIndex}/{displayTotal} + + + {/* Next */} + {isLastPage || isMaxPage ? ( + e.preventDefault()}> + + + ) : ( + + + + + + + Go to Next + + )} + + {/* Last - only show if we know the total */} + {totalPages !== null ? ( + + Last + + ) : ( + e.preventDefault()}> + Last + + )} +
+ ); +}; + +export default TransactionsPagination; diff --git a/packages/website/src/features/Txs/TransactionsSection.tsx b/packages/website/src/features/Txs/TransactionsSection.tsx new file mode 100644 index 000000000..638cd3069 --- /dev/null +++ b/packages/website/src/features/Txs/TransactionsSection.tsx @@ -0,0 +1,147 @@ +import React, { useEffect } from 'react'; +import { Chain } from '@/types/Chain'; +import { useCannonChains } from '@/providers/CannonProvidersProvider'; +import { useAddressTransactions } from '@/hooks/useAddressTransactions'; +import { useBlockPages } from '@/hooks/useBlockPages'; +import { Alert, AlertDescription } from '@/components/ui/alert'; +import Link from 'next/link'; +import { CustomSpinner } from '@/components/CustomSpinner'; +import TransactionsPaginatedList from '@/features/Txs/TransactionsPaginatedList'; +import { Card, CardContent } from '@/components/ui/card'; +import { Inbox } from 'lucide-react'; +import { MAX_PAGE_SIZE } from '@/constants/pagination'; + +type TransactionsSectionProps = { + address: string; + chain: Chain; + pageIndex: string | undefined; +}; + +const TransactionsSection: React.FC = ({ + address, + chain, + pageIndex, +}) => { + const cannonChains = useCannonChains(); + const apiUrl = cannonChains.otterscanApis[chain?.id ?? 0]?.rpcUrl; + + const numericPageIndex = Math.max(Number(pageIndex) || 1, 1); + + const { + totalPages, + totalTxs, + isLoading: isBlockLoading, + isError: isBlockError, + ensurePage, + getBlockForPage, + } = useBlockPages(apiUrl, address); + + // Ensure we have page boundaries for the current page + useEffect(() => { + if (apiUrl && address && numericPageIndex > 1) { + ensurePage(numericPageIndex - 1); + } + }, [apiUrl, address, numericPageIndex, ensurePage]); + + const blockBefore = getBlockForPage(numericPageIndex); + const canFetchTransactions = numericPageIndex === 1 || totalPages !== null || blockBefore !== '0'; + + const { + data: transactionData, + isLoading: isTransactionLoading, + isError: isTransactionError, + } = useAddressTransactions( + chain?.id || 0, + address, + blockBefore, + canFetchTransactions + ); + + const isLoading = isTransactionLoading || isBlockLoading; + + if (isLoading) { + return ( +
+
+
+ +

+ {isBlockLoading ? 'Loading' : 'Parsing'} transaction data... +

+
+
+
+ ); + } + + if (isTransactionError || isBlockError || !transactionData) { + return ( +
+ + + Transaction data is not available. This chain may not be set up with + block explorer (Otterscan API) support. Please set up a block + explorer API on the Settings page. + + +
+ ); + } + + // Check if we've exceeded the max page limit + if (numericPageIndex > MAX_PAGE_SIZE) { + return ( + + +
+ + + +

Max Page Limit

+ + This is the maximum number of pages currently supported by this + website. + +
+
+
+ ); + } + + const { txs, receipts, isLastPage, isFirstPage } = transactionData; + + // Handle case where page has no transactions (page doesn't exist) + if (!txs || txs.length === 0) { + return ( + + +
+ + + +

No Transactions Found

+ + This page does not contain any transactions. + +
+
+
+ ); + } + + return ( + + ); +}; + +export default TransactionsSection; diff --git a/packages/website/src/hooks/useAddressTransactions.ts b/packages/website/src/hooks/useAddressTransactions.ts index ac5848790..5d23cae13 100644 --- a/packages/website/src/hooks/useAddressTransactions.ts +++ b/packages/website/src/hooks/useAddressTransactions.ts @@ -3,20 +3,22 @@ import { searchTransactions, getMethods, matchFunctionName } from '@/lib/address import { OtterscanTransaction, OtterscanReceipt } from '@/types/AddressList'; import { useCannonChains } from '@/providers/CannonProvidersProvider'; -export function useAddressTransactions(chainId: number, address: string) { +export function useAddressTransactions(chainId: number, address: string, blockNumber: string, pagesReady: boolean) { // get the otterscan API from the settings store const cannonChains = useCannonChains(); const apiUrl = cannonChains.otterscanApis[chainId]?.rpcUrl; + const enabled = !!chainId && !!address && !!blockNumber && pagesReady; + return useQuery({ - queryKey: ['transaction-details', apiUrl, address], + queryKey: ['transaction-details', apiUrl, address, blockNumber], queryFn: async () => { if (!apiUrl) { return null; } - const data = await searchTransactions(apiUrl, address, 'before'); + const data = await searchTransactions(apiUrl, address, 'before', Number(blockNumber)); if (!data) { return null; } @@ -31,10 +33,12 @@ export function useAddressTransactions(chainId: number, address: string) { }; }); const receipts: OtterscanReceipt[] = data.result.receipts; + const isLastPage = data.result.lastPage; + const isFirstPage = data.result.firstPage; const oldData = await searchTransactions(apiUrl, address, 'after'); const oldReceipts: OtterscanReceipt[] = oldData.result.receipts; - return { txs, receipts, oldReceipts }; + return { txs, receipts, oldReceipts, isLastPage, isFirstPage }; }, - enabled: !!chainId && !!address, + enabled: enabled, }); } diff --git a/packages/website/src/hooks/useBlockPages.ts b/packages/website/src/hooks/useBlockPages.ts new file mode 100644 index 000000000..d21922f1b --- /dev/null +++ b/packages/website/src/hooks/useBlockPages.ts @@ -0,0 +1,116 @@ +import { useState, useCallback } from 'react'; +import { searchTransactions } from '@/lib/address'; +import { MAX_PAGE_SIZE } from '@/constants/pagination'; + +type PageCache = { + pages: string[]; // block numbers for each page boundary (index 0 = page 2's block, etc.) + totalPages: number | null; // null means we haven't reached the last page yet + totalTxs: number; +}; + +/** + * Lazy-loading page boundary tracker. + * Instead of fetching all pages upfront, we discover page boundaries as we navigate. + * Pages are stored as block numbers - page N's block is the last block of page N-1. + */ +export function useBlockPages(apiUrl: string, address: string) { + const [cache, setCache] = useState({ + pages: [], + totalPages: null, + totalTxs: 0, + }); + const [isLoading, setIsLoading] = useState(false); + const [isError, setIsError] = useState(false); + + // Fetch page boundaries up to a target page index + // This is called when we need a page that we haven't discovered yet + const ensurePage = useCallback( + async (targetPageIndex: number) => { + // If we already have this page or know we've reached the end, no need to fetch + if (cache.pages.length >= targetPageIndex || cache.totalPages !== null) { + return; + } + + setIsLoading(true); + setIsError(false); + + try { + const newPages: string[] = [...cache.pages]; + let totalTxs = cache.totalTxs; + let block = newPages.length > 0 ? Number(newPages[newPages.length - 1]) : 0; + let isLastPage = false; + + // Fetch pages until we have the target or reach the end + while (newPages.length < targetPageIndex && !isLastPage) { + const data = await searchTransactions(apiUrl, address, 'before', block); + + const receipts = data.result?.receipts ?? []; + if (!receipts.length) { + isLastPage = true; + break; + } + + totalTxs += receipts.length; + isLastPage = !!data.result?.lastPage; + + if (!isLastPage) { + const lastReceipt = receipts[receipts.length - 1]; + const nextBlock = String(parseInt(lastReceipt.blockNumber.slice(2), 16)); + newPages.push(nextBlock); + block = Number(nextBlock); + } + + // Safety limit + if (newPages.length >= MAX_PAGE_SIZE - 1) { + break; + } + } + + setCache({ + pages: newPages, + totalPages: isLastPage ? newPages.length + 1 : null, + totalTxs, + }); + } catch { + setIsError(true); + } finally { + setIsLoading(false); + } + }, + [apiUrl, address, cache] + ); + + // Get the block number to use for fetching a specific page (1-indexed) + const getBlockForPage = useCallback( + (pageIndex: number): string => { + if (pageIndex <= 1) return '0'; + // Page 2 uses pages[0], page 3 uses pages[1], etc. + return cache.pages[pageIndex - 2] ?? '0'; + }, + [cache.pages] + ); + + // Check if a page exists (for disabling next button) + const hasPage = useCallback( + (pageIndex: number): boolean => { + if (pageIndex <= 1) return true; // Page 1 always exists + if (cache.totalPages !== null) { + return pageIndex <= cache.totalPages; + } + // If we haven't reached the end, assume the page might exist + return true; + }, + [cache.totalPages] + ); + + return { + pages: cache.pages, + totalPages: cache.totalPages, + totalTxs: cache.totalTxs, + isLoading, + isError, + ensurePage, + getBlockForPage, + hasPage, + }; +} diff --git a/packages/website/src/pages/txs/index.tsx b/packages/website/src/pages/txs/index.tsx new file mode 100644 index 000000000..3d59861bf --- /dev/null +++ b/packages/website/src/pages/txs/index.tsx @@ -0,0 +1,21 @@ +import { NextSeo } from 'next-seo'; +import defaultSEO from '@/constants/defaultSeo'; +import AddressTransactionPage from '@/features/Txs/AddressTransactionPage'; + +export default function Transaction() { + return ( + <> + + + + ); +} diff --git a/packages/website/vercel.json b/packages/website/vercel.json index d47596fdb..4c54d53fe 100644 --- a/packages/website/vercel.json +++ b/packages/website/vercel.json @@ -63,6 +63,10 @@ { "source": "/tx/:chainId/:txHash", "destination": "/tx/[chainId]/[txHash]" + }, + { + "source": "/txs", + "destination": "/txs" } ], "framework": null, From 41be2129184b4344968eac1a02e9a8122e46dab4 Mon Sep 17 00:00:00 2001 From: saturn Date: Mon, 9 Mar 2026 22:48:30 +0900 Subject: [PATCH 12/13] feat(skill): add AI agent skill package for Cannon (#1862) --- packages/skill/README.md | 48 +++ packages/skill/SKILL.md | 403 ++++++++++++++++++++++++ packages/skill/package.json | 27 ++ packages/skill/references/cannonfile.md | 217 +++++++++++++ packages/skill/references/cli.md | 212 +++++++++++++ packages/skill/references/registry.md | 147 +++++++++ packages/skill/references/testing.md | 135 ++++++++ 7 files changed, 1189 insertions(+) create mode 100644 packages/skill/README.md create mode 100644 packages/skill/SKILL.md create mode 100644 packages/skill/package.json create mode 100644 packages/skill/references/cannonfile.md create mode 100644 packages/skill/references/cli.md create mode 100644 packages/skill/references/registry.md create mode 100644 packages/skill/references/testing.md diff --git a/packages/skill/README.md b/packages/skill/README.md new file mode 100644 index 000000000..20b03aa47 --- /dev/null +++ b/packages/skill/README.md @@ -0,0 +1,48 @@ +# @usecannon/skill + +AI agent skill for Cannon. Enables AI assistants (Claude, GPT-4, etc.) to help with Ethereum deployments using Cannon. + +## What is this? + +This package contains a skill definition that can be used with AI agent frameworks like OpenClaw. The skill provides: + +- Complete Cannon CLI reference +- Cannonfile syntax documentation +- Deployment workflows and best practices +- Debugging and troubleshooting guides +- GitOps and migration patterns + +## Usage + +### OpenClaw + +Copy `SKILL.md` and the `references/` folder to your OpenClaw skills directory: + +```bash +cp -r packages/skill/* ~/.openclaw/workspace/skills/cannon/ +``` + +### Other AI Frameworks + +The `SKILL.md` file is designed to be used as a system prompt or context document for AI assistants. Point your AI framework to this file when working on Cannon-related tasks. + +## Contents + +- `SKILL.md` - Main skill definition with safety warnings, CLI reference, and workflows +- `references/cli.md` - Detailed CLI command reference +- `references/cannonfile.md` - Complete cannonfile specification +- `references/testing.md` - Testing patterns with cannon-std +- `references/registry.md` - Registry and publishing guide + +## Safety + +⚠️ **Blockchain deployments are irreversible.** This skill includes prominent safety warnings and requires AI assistants to: + +1. Explain operations before executing +2. Use dry-run mode first +3. Confirm before deploying with real keys +4. Test locally before mainnet + +## License + +MIT diff --git a/packages/skill/SKILL.md b/packages/skill/SKILL.md new file mode 100644 index 000000000..f63cfacea --- /dev/null +++ b/packages/skill/SKILL.md @@ -0,0 +1,403 @@ +--- +name: cannon +description: Cannon package manager for Ethereum deployments. Use when building, testing, deploying, or inspecting Cannon packages. Covers cannonfile syntax, CLI commands (build, run, test, publish, inspect), actions (deploy, invoke, clone, pull, router, diamond), and package workflows. NOT for general Solidity development questions. +--- + +# Cannon + +## ⚠️ CRITICAL: Read This First + +**Some Cannon commands are IRREVERSIBLE and handle real value.** Be careful with: + +- `cannon build` (without `--dry-run`) — deploys contracts on real networks +- `cannon publish` — publishes to on-chain registry (permanent) +- `cannon register` — registers package names on-chain +- `cannon publishers` — manages package publisher permissions + +Safe commands: `cannon build --dry-run`, `cannon inspect`, `cannon run`, `cannon test`, `cannon decode`, `cannon trace`, `cannon clean` + +Rules: +1. **Always use `--dry-run` first** — Simulate before executing on real networks +2. **Make every operation clear to the user** — Explain what will happen before running +3. **Confirm before deploying** — Never use a real private key without explicit approval +4. **Test locally first** — Use chain 13370 (Cannon Network) before target chains +5. **Protect private keys** — Use `CANNON_PRIVATE_KEY` env var or `--impersonate` (recommended) + +## Model Recommendation + +**Use state-of-the-art models for Cannon tasks.** Deployment scripts handle real value — don't skimp on model quality. Prefer Claude, GPT-4, or equivalent high-capability models over cheaper alternatives. + +## Schema Reference + +For complete cannonfile syntax validation and autocomplete, refer to the official JSON schemas: + +- **Full schema:** https://raw.githubusercontent.com/usecannon/cannon/refs/heads/dev/packages/lsp/src/schema.json +- **Fragment schema:** https://raw.githubusercontent.com/usecannon/cannon/refs/heads/dev/packages/lsp/src/schema-fragment.json + +For editor validation, add the schema reference at the top of your `cannonfile.toml`: + +```toml +#:schema https://raw.githubusercontent.com/usecannon/cannon/refs/heads/dev/packages/lsp/src/schema.json + +name = "my-package" +version = "1.0.0" +... +``` + +This enables autocomplete and validation in editors with TOML LSP support (like taplo). + +--- + +Cannon is a package manager and deployment system for Ethereum smart contracts. It uses declarative cannonfiles to define deployment workflows and supports both local development and on-chain deployments. + +## Prerequisites + +Before using this skill, ensure these tools are installed: + +- **Node.js 18+** and **pnpm** - `npm install -g pnpm` +- **Foundry** (forge, anvil, cast) - `curl -L https://foundry.paradigm.xyz | bash && foundryup` +- **Cannon CLI** - `pnpm add -g @usecannon/cli` + +Verify installation: +```bash +node --version && pnpm --version +forge --version && anvil --version +cannon --version +``` + +## Quick Reference + +For complete CLI options, see [references/cli.md](references/cli.md). + +### CLI Commands +```bash +cannon build # Build package locally (starts anvil, deploys contracts) +cannon run # Run a deployed package (shorthand: cannon ) +cannon test # Run forge tests with deployment context +cannon inspect # View package details +cannon publish # Publish to on-chain registry + IPFS ⚠️ IRREVERSIBLE +cannon clean # Delete cache directories +cannon verify # Verify contracts on Etherscan/Sourcify +``` + +### Package Reference Format +``` +:@ +``` +Examples: +- `greeter-foundry:2.24.0` +- `safe:1.4.1` +- `synthetix-omnibus:3.1.4@main` + +## Cannonfile Syntax + +### Package Metadata & Includes +```toml +name = "my-package" +version = "1.0.0" +description = "My package description" +tags = ["defi", "token"] +preset = "main" + +# Include additional files containing actions (for larger packages) +include = ["./deposits.toml", "./withdrawals.toml"] +``` + +Use `include` to split large cannonfiles into multiple files. Included files use the fragment schema and can contain any actions (deploy, invoke, clone, etc.). + +Modern syntax uses `[var.label]` for settings (deprecated: `[setting.name]`). + +### Variables +```toml +[var.chainId] +defaultValue = 1 + +[var.owner] +defaultValue = "0x..." +``` + +### Deploy Contract +```toml +[deploy.MyContract] +artifact = "MyContract" +args = ["<%= settings.owner %>"] +``` + +### Invoke Function +```toml +[invoke.initialize] +target = ["<%= contracts.MyContract.address %>"] +func = "initialize" +args = ["<%= settings.owner %>"] +``` + +### Import/Clone Package +```toml +[clone.safe] +source = "safe:1.4.1" +target = "safe" +``` + +**When to use clone vs import:** +- **`clone`** — Use another package as a "blueprint" to deploy it anew. Always set `target` appropriately (same as source if you own it, or a new name if not). +- **`import`** — Pull in data from an already-deployed package without re-deploying. + +### Pull Data from Package +```toml +[pull.usdc] +source = "usdc:1.0.0@main" +``` + +Access: `<%= imports.usdc.contracts.USDC.address %>` + +## Template Strings + +Use ERB-style templates to reference values: +- `<%= settings.varName %>` — settings +- `<%= contracts.ContractName.address %>` — deployed contract address +- `<%= contracts.ContractName.abi %>` — contract ABI +- `<%= imports.pkg.contracts.Contract.address %>` — imported contract + +## Actions + +| Action | Description | +|--------|-------------| +| `deploy` | Deploy a contract | +| `invoke` | Call a contract function | +| `clone` | Deploy another package as a blueprint | +| `import` | Pull data from an already-deployed package | +| `pull` | (deprecated) Alias for import | +| `var` | Define computed variables | +| `router` | Create a router contract to bypass size limits (pairs well with UUPS proxy) | +| `diamond` | Create an EIP-2535 Diamond with facets | + +## Local Development + +**⚠️ Always use chain 13370 (Cannon Network) for local testing before deploying to target chains.** + +Default chain ID: **13370** (Cannon Network) + +```bash +# Build with local anvil +cannon build + +# Build for specific chain +cannon build --chain-id 1 --rpc-url $RPC_URL + +# Dry run (simulation only) +cannon build --dry-run --impersonate-all + +# Run a package locally +cannon run greeter-foundry:2.24.0 +``` + +## On-Chain Deployment + +**⚠️ Always use `--dry-run` first to verify deployments before executing on real networks.** + +```bash +# Deploy to mainnet +cannon build --chain-id 1 --rpc-url $RPC_URL --private-key $KEY + +# Publish to registry +cannon publish --chain-id 1 --rpc-url $RPC_URL --private-key $KEY + +# For simulation before actual deploy +cannon build --chain-id 1 --rpc-url $RPC_URL --dry-run +``` + +## Testing + +```bash +# Run tests with forge +cannon test + +# Test specific contract +cannon test --match-path "test/MyContract.t.sol" +``` + +Use `cannon-std` in Forge tests: +```solidity +import {Cannon} from "cannon-std/Test.sol"; + +contract MyTest is Cannon { + function setUp() public { + // Load deployed contracts + address myContract = getAddress("MyContract"); + } +} +``` + +## Storage Locations + +| Directory | Contents | +|-----------|----------| +| `~/.local/share/cannon/tags/` | Package reference files | +| `~/.local/share/cannon/ipfs_cache/` | Cached IPFS artifacts | +| `~/.local/share/cannon/build_results/` | Build outputs | +| `~/.local/share/cannon/blobs/` | Large binary blobs | + +## Common Patterns + +### Router Pattern (Bypass Contract Size Limits) +Create a router contract that efficiently passes calls to downstream contracts. Powerful when combined with a UUPS proxy. + +```toml +[deploy.CoreImplementation] +artifact = "Core" + +[deploy.AnotherImplementation] +artifact = "Another" + +[router.CoreRouter] +dependencies = ["CoreImplementation", "AnotherImplementation"] +``` + +### Diamond Pattern (EIP-2535) +```toml +[deploy.Diamond] +artifact = "Diamond" + +[deploy.FacetA] +artifact = "FacetA" + +[deploy.FacetB] +artifact = "FacetB" + +[diamond.Diamond] +facets = ["FacetA", "FacetB"] +``` + +### Linked Libraries +```toml +[deploy.Library] +artifact = "Library" + +[deploy.Contract] +artifact = "Contract" +libraries = { Library = "<%= contracts.Library.address %>" } +``` + +## Debugging Tools + +Cannon provides commands to decode bytecode, trace transactions, and interact with deployed contracts. + +### Decode +Decode hex data (function calls, events, errors) using package ABIs: +```bash +cannon decode synthetix-omnibus --chain-id 8453 --preset main 0x... +``` + +### Trace +Get human-readable stack traces for transactions: +```bash +cannon trace --chain-id 1 --rpc-url $RPC_URL +``` + +### Interact +Send transactions to deployed contracts through the CLI: +```bash +cannon interact synthetix-omnibus --chain-id 8453 --contract CoreProxy +``` + +## Package State Manipulation (`alter`) + +The `alter` command modifies existing Cannon packages outside the regular build process. Use for troubleshooting, migrations, or fixing broken package state. + +⚠️ **Only use `alter` when no other option exists.** + +### Subcommands + +| Command | Description | +|---------|-------------| +| `import` | Import existing artifacts into a deployment step (for migrations) | +| `set-contract-address` | Change a contract's address in the deployment | +| `mark-complete` | Mark a deployment step as complete | +| `mark-incomplete` | Mark a deployment step as incomplete | +| `set-url` | Update the deployment URL reference | +| `set-misc` | Update miscellaneous data URL | +| `clean-unused` | Remove unused deployment states | +| `migrate-212` | Migrate packages from version 2.12 format | + +### Example: Import existing deployment +```bash +# Import a deployed contract by its creation transaction +cannon alter my-package:1.0.0 --chain-id 1 import deploy MyContract 0x...txhash + +# Import an executed transaction +cannon alter my-package:1.0.0 --chain-id 1 import invoke initialize 0x...txhash +``` + +## GitOps Workflows + +Cannon supports GitOps-style deployments through the website interface. + +### Queue with GitOps +Deploy packages directly from GitHub repositories or IPFS hashes via the Cannon website: +- Preview transactions before execution +- View Git Diff of changes +- Execute through Safe multisig wallets +- Publish to registry after deployment + +See: https://usecannon.com/deploy + +### Deployments Repository +Create a dedicated Git repository for deployment configurations (separate from source code): +- Keep smart contract source private while maintaining transparent deployments +- Enable team collaboration on deployments +- Maintain clear audit trail + +## Migration from Other Tools + +Migrating from hardhat-deploy, Foundry scripts, or other deployment frameworks: + +1. **Recreate deployment as cannonfile.toml** (manual but usually quick) +2. **Build locally** to create template: `cannon build` (save the IPFS hash) +3. **For each network**, import existing deployments: + ```bash + # Set the package URL to local template + cannon alter my-package --chain-id 1 set-url + + # Import each deployed contract/transaction + cannon alter my-package --chain-id 1 import deploy MyContract 0x...txhash + ``` +4. **Verify** by running build (no steps should execute): `cannon build --chain-id 1` + +## Advanced Topics + +For detailed information on: +- **CLI reference**: See [references/cli.md](references/cli.md) +- **Cannonfile specification**: See [references/cannonfile.md](references/cannonfile.md) +- **Testing patterns**: See [references/testing.md](references/testing.md) +- **Registry and publishing**: See [references/registry.md](references/registry.md) + +## Troubleshooting + +| Issue | Solution | +|-------|----------| +| "deployment not found" | Package not published for this chain ID. Check `--chain-id` | +| Build fails with "artifact not found" | Run `forge build` first, or check `artifact` path | +| IPFS timeout | Check network connection, may need IPFS gateway | +| Registry publish fails | Verify you have write permissions for the package name | +| **Wrong chain deployed** | Always double-check `--chain-id` — deployments cannot be undone | +| **Published incorrect package** | Registry publishes are permanent — verify version and artifacts first | + +## Development Workflow + +1. **Develop contracts** with Foundry +2. **Write cannonfile.toml** to define deployment +3. **Build locally** with `cannon build` (chain 13370) +4. **Test** with `cannon test` +5. **Simulate** with `--dry-run` for target chain ⚠️ ALWAYS DO THIS FIRST +6. **Deploy** with `cannon build --chain-id ` ⚠️ IRREVERSIBLE on non-local networks (safe on chain 13370) +7. **Verify** contracts on Etherscan with `cannon verify` +8. **Publish** with `cannon publish` ⚠️ PERMANENT ON-CHAIN + +## Key Files + +| File | Purpose | +|------|---------| +| `cannonfile.toml` | Package definition | +| `cannonfile.lock` | Locked dependencies | +| `.cannon/` | Build cache (gitignored) | +| `deployments/` | Deployment artifacts | diff --git a/packages/skill/package.json b/packages/skill/package.json new file mode 100644 index 000000000..ff89a5bce --- /dev/null +++ b/packages/skill/package.json @@ -0,0 +1,27 @@ +{ + "name": "@usecannon/skill", + "version": "1.0.0", + "description": "AI agent skill for Cannon - enables AI assistants to help with Ethereum deployments using Cannon", + "main": "SKILL.md", + "files": [ + "SKILL.md", + "references" + ], + "keywords": [ + "cannon", + "ethereum", + "deployment", + "ai", + "agent", + "skill", + "llm" + ], + "author": "Saturn", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/usecannon/cannon.git", + "directory": "packages/skill" + }, + "homepage": "https://usecannon.com" +} diff --git a/packages/skill/references/cannonfile.md b/packages/skill/references/cannonfile.md new file mode 100644 index 000000000..c469fe603 --- /dev/null +++ b/packages/skill/references/cannonfile.md @@ -0,0 +1,217 @@ +# Cannonfile Specification + +## Structure + +A cannonfile.toml defines a Cannon package with metadata, variables, and actions. + +```toml +#:schema https://raw.githubusercontent.com/usecannon/cannon/refs/heads/dev/packages/lsp/src/schema.json + +name = "my-package" +version = "1.0.0" +description = "My package description" +tags = ["defi", "token"] +preset = "main" + +# Variables +[var.settings] +owner = "0x0000000000000000000000000000000000000000" +initialSupply = "1000000000000000000000000" + +# Actions execute in order based on dependencies +[deploy.MyContract] +artifact = "MyContract" +args = ["<%= settings.owner %>"] +``` + +## Variables (`var`) + +Define configurable settings. Cannon automatically provides `chainId` as a built-in variable. + +```toml +[var.settings] +# The label "settings" is just for organization - you can use any label +owner = "0x0000000000000000000000000000000000000000" +initialSupply = "1000000000000000000000000" +salt = "my-package" +``` + +Access with: `<%= settings.owner %>` or `<%= settings.initialSupply %>` + +Override at build time: +```bash +cannon build cannonfile.toml owner=0x1234... salt=custom-salt +``` + +## Deploy Action + +Deploy a contract from compiled artifacts. + +```toml +[deploy.Token] +artifact = "Token" +args = ["My Token", "TKN", "<%= settings.initialSupply %>", "<%= settings.owner %>"] +create2 = true +salt = "<%= settings.salt %>" +libraries = { Utils = "<%= contracts.Utils.address %>" } +from = "<%= settings.deployer %>" +value = "<%= parseEther('1.0') %>" +``` + +## Invoke Action + +Call a function on a deployed contract. + +```toml +[invoke.initialize] +target = ["Token"] +func = "initialize" +args = ["<%= settings.owner %>"] +from = "<%= settings.owner %>" +``` + +Note: `target` uses the contract label directly (e.g., `["Token"]`), not the full address path. + +## Clone Action + +Deploy another Cannon package as a "blueprint". Use when you want to deploy a fresh instance of an existing package. + +**Important:** Always set `target` appropriately: +- Same as `source` if you own the package +- New name if you don't own it + +```toml +[clone.safe] +source = "mycompany-safe:1.4.1@team" +target = "safe" +``` + +Access: `<%= safe.Safe.address %>` (shorthand) or `<%= imports.safe.contracts.Safe.address %>` (full) + +## Import Action + +Pull data from an already-deployed package without re-deploying. Use when you need to reference existing deployments. + +```toml +[import.usdc] +source = "usdc:1.0.0@main" +``` + +Access: `<%= usdc.USDC.address %>` (shorthand) or `<%= imports.usdc.contracts.USDC.address %>` (full) + +## Router Action + +Create a router contract that efficiently passes calls to downstream contracts. Powerful when combined with a UUPS proxy for upgradable contracts that exceed the contract size limit. + +```toml +[deploy.CoreImplementation] +artifact = "Core" + +[deploy.AnotherImplementation] +artifact = "Another" + +[router.CoreRouter] +dependencies = ["CoreImplementation", "AnotherImplementation"] +``` + +## Diamond Action (EIP-2535) + +Create a Diamond proxy with multiple facets. + +```toml +[deploy.FacetA] +artifact = "FacetA" + +[deploy.FacetB] +artifact = "FacetB" + +[diamond.MainDiamond] +facets = ["FacetA", "FacetB"] +init = "DiamondInit" +initArgs = ["<%= settings.owner %>"] +``` + +## Template Syntax + +Templates can be used anywhere a string is defined. They're JavaScript expressions. + +Cannon automatically topologically orders deployment steps based on dependencies in template syntax, so `depends =` is rarely needed. + +### Accessing Settings +```toml +<%= settings.varName %> +``` + +### Accessing Chain ID (Built-in) +```toml +<%= chainId %> # Cannon provides this automatically +``` + +### Accessing Contract Data +```toml +<%= contracts.ContractName.address %> +<%= contracts.ContractName.abi %> +``` + +### Accessing Imports (Shorthand) +```toml +<%= pkgName.ContractName.address %> # Preferred shorthand +<%= imports.pkgName.contracts.Contract.address %> # Full syntax +``` + +### Helpers +Available helpers include all functions from `ethers.utils` (ethers v5), plus: +- `encodeFunctionData` from viem +- Constants like `AddressZero` from `ethers.constants` + +```toml +<%= parseEther("1.0") %> # Convert to wei +<%= formatBytes32String("hello") %> # Convert to bytes32 +<%= AddressZero %> # 0x000...000 +<%= encodeFunctionData(abi, fn, args) %> +``` + +## Conditional Actions + +Use `only` to conditionally execute actions. + +```toml +[deploy.OnlyOnMainnet] +artifact = "MainnetOnly" +only = "<%= chainId == 1 %>" + +[deploy.OnlyOnL2] +artifact = "L2Only" +only = "<%= chainId != 1 %>" +``` + +## Action Dependencies + +Actions execute based on dependency order (resolved from template syntax), not file order. + +```toml +# These can be in any order - Cannon resolves dependencies from templates +[invoke.init] +target = ["<%= contracts.Token.address %>"] # Depends on deploy.Token + +[deploy.Token] +artifact = "Token" +``` + +## Overriding Settings at Build Time + +Pass settings directly to the build command: + +```bash +cannon build cannonfile.toml owner=0x1234123412341234123412341234123412341234 salt=foobar +``` + +Any `var` with matching keys will be overridden. + +## Best Practices + +1. **Use semantic versioning** for package versions +2. **Test locally** (chain 13370) before mainnet +3. **Use clone** to deploy fresh instances of existing packages +4. **Use import** to reference already-deployed packages +5. **Set target** appropriately when cloning (same as source if you own it) diff --git a/packages/skill/references/cli.md b/packages/skill/references/cli.md new file mode 100644 index 000000000..77145fc30 --- /dev/null +++ b/packages/skill/references/cli.md @@ -0,0 +1,212 @@ +# CLI Reference + +## Debugging + +If something is misbehaving, increase debugging verbosity: + +```bash +# Using DEBUG environment variable (NodeJS debug module) +DEBUG=cannon:* cannon build + +# Or using verbose flags (increasing verbosity) +cannon build -v # basic verbosity +cannon build -vv # more verbose +cannon build -vvv # most verbose +``` + +## Build Command + +```bash +cannon build [options] +``` + +Options: +- `--chain-id ` — Target chain ID (default: 13370, derived from `--rpc-url` if not specified) +- `--rpc-url ` — RPC endpoint URL +- `--private-key ` — Private key for deployment (or set `CANNON_PRIVATE_KEY` env var) +- `--impersonate ` — Impersonate specific addresses (comma-separated, recommended for dry-run) +- `--impersonate-all` — Impersonate all addresses (dry-run only) +- `--dry-run` — Simulate without sending transactions (always use before real deployments!) +- `--keep-alive` — Keep anvil running after build (useful with dry-run) +- `--port ` — Port for local anvil +- `--write-deployments ` — Output directory for deployment files +- `--upgrade-from ` — Upgrade from existing package (only if auto-detected package is wrong) + +Note: If `cannon ` is run and the command isn't recognized, Cannon automatically executes `cannon run `. + +## Run Command + +```bash +cannon run [options] +# Or simply: +cannon +``` + +Options: +- `--chain-id ` — Target chain ID (derived from `--rpc-url` if not specified) +- `--rpc-url ` — RPC endpoint URL +- `--private-key ` — Private key for transactions (or set `CANNON_PRIVATE_KEY` env var) +- `--impersonate ` — Impersonate specific addresses + +Package reference: `:@` (preset is optional) + +## Test Command + +```bash +cannon test [options] +``` + +Designed to work with Foundry projects. Runs forge tests with Cannon deployment context. + +Options: +- `--match-path ` — Match specific test files +- `--match-contract ` — Match specific contract tests +- `--chain-id ` — Chain ID for test context +- `--rpc-url ` — RPC endpoint for tests +- `--verbose` — Show detailed test output + +See cannon-std documentation for testing patterns. + +## Inspect Command + +```bash +cannon inspect [options] +``` + +Options: +- `--chain-id ` — Chain ID +- `--out ` — Output format (json, yaml, toml, etc.) +- `--write-deployments ` — Output directory for deployment files + +Package reference: `:@` + +## Publish Command + +```bash +cannon publish [options] +``` + +Options: +- `--chain-id ` — Target chain ID (default: mainnet or optimism) +- `--rpc-url ` — RPC endpoint (if not specified, will be requested via stdin) +- `--private-key ` — Private key with publish permissions (or set `CANNON_PRIVATE_KEY` env var) + +Note: There is a fee each time a package is published (currently 0.0025 ETH). Cannon provides an IPFS service included in the publishing fee. + +## Clean Command + +```bash +cannon clean [options] +``` + +Options: +- `--no-confirm` — Skip confirmation prompt +- `--ipfs` — Delete only unreferenced IPFS packages + +## Verify Command + +```bash +cannon verify [options] +``` + +Options: +- `--chain-id ` — Target chain ID +- `--rpc-url ` — RPC endpoint +- `--etherscan-api-key ` — Etherscan API key +- `--service ` — Verification service: `etherscan`, `sourcify`, or `all` (verifies to both) + +## Fetch Command + +```bash +cannon fetch [options] +``` + +Options: +- `--chain-id ` — Target chain ID +- `--output-dir ` — Output directory + +## Interact Command + +```bash +cannon interact [options] +``` + +Options: +- `--chain-id ` — Target chain ID +- `--rpc-url ` — RPC endpoint +- `--contract ` — Target contract name + +## Trace Command + +```bash +cannon trace [options] +``` + +Options: +- `--chain-id ` — Target chain ID +- `--rpc-url ` — RPC endpoint +- `--verbose` — Show detailed trace + +## Decode Command + +```bash +cannon decode [options] +``` + +Options: +- `--chain-id ` — Target chain ID + +Decodes function calls, events, and errors using package ABIs. + +## Alter Command + +Modify existing Cannon packages outside the regular build process. + +```bash +cannon alter [options] +``` + +Subcommands: +- `import ` — Import existing deployment/transaction +- `set-contract-address
` — Update contract address +- `mark-complete ` — Mark step as complete +- `mark-incomplete ` — Mark step as incomplete +- `set-url ` — Update deployment URL reference +- `set-misc ` — Update miscellaneous data URL +- `clean-unused` — Remove unused deployment states + +Options: +- `--chain-id ` — Target chain ID + +## Publishers Command + +Manage additional publishers for a package. + +```bash +cannon publishers [options] +``` + +Options: +- `--chain-id ` — Target chain ID (must be mainnet) +- `--rpc-url ` — RPC endpoint +- `--private-key ` — Owner's private key + +Note: Additional publishers must be set on mainnet when publishing to Optimism. + +## Register Command + +Register a new package name on the registry. + +```bash +cannon register [options] +``` + +Options: +- `--chain-id ` — Target chain ID (mainnet only) +- `--rpc-url ` — RPC endpoint +- `--private-key ` — Private key + +## Environment Variables + +- `CANNON_PRIVATE_KEY` — Private key for deployments/publishing +- `CANNON_DIRECTORY` — Override default storage directory (default: `~/.local/share/cannon/`) diff --git a/packages/skill/references/registry.md b/packages/skill/references/registry.md new file mode 100644 index 000000000..7016da69f --- /dev/null +++ b/packages/skill/references/registry.md @@ -0,0 +1,147 @@ +# Registry and Publishing + +## What is the Cannon Registry? + +The Cannon registry is an on-chain smart contract that stores package metadata and deployment data. It enables: +- Version management for packages +- Package discovery and sharing +- Integration with other projects +- **On-chain verification** of deployed packages (anyone can verify what was deployed) + +Registry address: `0x8E2c2E6A0c57dD0f58acE0ba4EBdD7807e0F8708` + +## Browsing Packages + +Deployed registry packages are visible on the Cannon website at: +``` +https://usecannon.com/packages///- +``` + +Example: https://usecannon.com/packages/safe/1.4.1/13370-main + +**Recommended:** Share this URL with users after successfully publishing a package! + +## Registry Networks + +### Mainnet (Chain ID: 1) +- Primary registry for package ownership +- Package names are registered here first + +### Optimism (Chain ID: 10) - Recommended +- **Recommended for publishing** (lower gas costs) +- Synced with mainnet registry via cross-chain bridge + +**Important:** Mainnet and Optimism registries are synced together through a cross-chain bridge. Package ownership is synchronized automatically within a couple of minutes. You can only register a new package name on mainnet. + +## Publishing + +Publishing makes your package available on the on-chain registry and IPFS. + +### Publishing Fee + +There is a fee each time a package is published: **0.0025 ETH** + +This fee covers: +- On-chain registry storage +- IPFS pinning service (Cannon provides IPFS hosting) + +### Publish Command + +```bash +cannon publish --chain-id 10 --rpc-url $RPC_URL +``` + +If `--private-key` is not specified, it will be requested via stdin. + +**Note:** You may want to use `--exclude-cloned` to prevent publishing subpackages if your setup clones other packages that should remain separate. + +### Package Ownership + +- First publisher of a package name becomes the owner +- Only the owner can publish new versions +- Ownership is transferable via registry contract + +### Additional Publishers + +Owners can authorize additional addresses to publish on their behalf: + +```bash +# On mainnet (required for Optimism publishing) +cannon publishers my-package --chain-id 1 --rpc-url $RPC_URL +``` + +Or call `setAdditionalPublishers` directly on the mainnet registry contract. + +**Note:** When publishing on Optimism, additional publishers must be set on mainnet first, as this is not done automatically. + +## Package Contents + +When you publish, Cannon uploads to IPFS: +- Package definition (cannonfile) +- Contract ABIs +- Deployed addresses +- Transaction data + +Cannon provides an IPFS service alongside package publishes (included in the publishing fee) which is used by default. + +**On-chain Verification:** The registry stores package metadata on-chain, allowing anyone to cryptographically verify what was deployed. This enables trustless verification of deployment integrity. + +## Cache Locations + +Default: `~/.local/share/cannon/` + +Override with `CANNON_DIRECTORY` environment variable. + +Directory structure: +``` +~/.local/share/cannon/ +├── tags/ # Package references (IPFS URLs) +└── ipfs_cache/ # Cached IPFS artifacts +``` + +## Clean Command + +```bash +# Delete all cache +cannon clean + +# Delete only unreferenced IPFS packages +cannon clean --ipfs +``` + +## Private Source Code + +By default, Cannon includes your project's source code in published packages. + +To prevent this, add to your `cannonfile.toml`: +```toml +privateSourceCode = true +``` + +## Troubleshooting + +### "deployment not found" +- Package not published for this chain ID +- Check `--chain-id` matches the deployment network + +### "Not authorized to publish" +- You don't own this package name +- Check if you're the owner or an additional publisher +- May need to set additional publishers on mainnet (especially for Optimism) + +### IPFS timeout +- Check network connection +- May need to configure a custom IPFS gateway + +### Registry publish fails +- Verify you have write permissions for the package name +- Ensure you have enough ETH for the publishing fee (0.0025 ETH) +- For Optimism, ensure additional publishers are set on mainnet + +## Best Practices + +1. **Publish on Optimism** - Lower gas costs +2. **Set additional publishers** - On mainnet before publishing to Optimism +3. **Use semantic versioning** - Clear version history +4. **Test before publishing** - Registry publishes are permanent +5. **Consider privateSourceCode** - If source should remain private diff --git a/packages/skill/references/testing.md b/packages/skill/references/testing.md new file mode 100644 index 000000000..eea96fc95 --- /dev/null +++ b/packages/skill/references/testing.md @@ -0,0 +1,135 @@ +# Testing Patterns + +## Setup + +Cannon integrates with Foundry for testing. Use `cannon-std` library to access deployed contracts in tests. + +**Important:** Foundry needs filesystem access to read Cannon state files. Add to your `foundry.toml`: + +```toml +[profile.default] +fs_permissions = [{ access = "read", path = "./"}] +``` + +## Basic Test Structure + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "cannon-std/Cannon.sol"; + +contract MyContractTest is Test { + using Cannon for Vm; + + address myContract; + + function setUp() public { + // Load deployed contract from cannon build + myContract = vm.getAddress("MyContract"); + } +} +``` + +## cannon-std Helpers + +All helpers are called on `vm`: + +```solidity +address contractAddr = vm.getAddress("ContractName"); +bytes memory abi = vm.getAbi("ContractName"); +bytes memory bytecode = vm.getBytecode("ContractName"); +``` + +## Running Tests + +```bash +# Run all tests +cannon test + +# Run specific test file +cannon test --match-path "test/MyContract.t.sol" + +# Run specific test function +cannon test --match-test "testTransfer" + +# Verbose output +cannon test -vvvv +``` + +## Test Patterns + +### Testing Deployed State + +```solidity +contract TokenTest is Test { + using Cannon for Vm; + + address token; + + function setUp() public { + token = vm.getAddress("Token"); + } + + function test_InitialState() public view { + assertEq(Token(token).name(), "My Token"); + assertEq(Token(token).symbol(), "MTK"); + assertEq(Token(token).totalSupply(), 1000000 * 10**18); + } +} +``` + +### Testing Cross-Contract Interactions + +```solidity +contract RouterTest is Test { + using Cannon for Vm; + + address router; + address token; + + function setUp() public { + router = vm.getAddress("Router"); + token = vm.getAddress("Token"); + } + + function test_Route() public { + vm.prank(owner); + Router(router).route(token, 1000); + } +} +``` + +### Testing with Impersonation + +```solidity +function test_OwnerAction() public { + address owner = vm.getAddress("Owner"); + address myContract = vm.getAddress("MyContract"); + + vm.prank(owner); + MyContract(myContract).ownerOnlyFunction(); +} +``` + +### Testing Upgrades + +```solidity +function test_Upgrade() public { + address proxy = vm.getAddress("Proxy"); + address newImpl = vm.getAddress("NewImplementation"); + + vm.prank(owner); + Proxy(proxy).upgradeTo(newImpl); +} +``` + +## Best Practices + +1. **Use `using Cannon for Vm`** — Enables `vm.getAddress()` and other helpers +2. **Configure fs_permissions** — Foundry needs read access to load Cannon state +3. **Use setUp()** — Load deployed contracts once at the start +4. **Test deployment state first** — Verify initial conditions before interactions +5. **Use vm.prank** — Test access control by impersonating different addresses +6. **Run cannon build before tests** — Ensure fresh deployment state From 876e58685cc6066ccf7880e9ba7e90a3bb88f868 Mon Sep 17 00:00:00 2001 From: saturn-dbeal Date: Tue, 17 Mar 2026 14:19:01 +0900 Subject: [PATCH 13/13] feat(cannon-3): draft var system changes for 3.0 This is a draft RFC for Cannon 3.0 breaking changes to the var system. ## Changes ### New var format Variables can now be defined with type information, descriptions, and namespacing: ```toml [var.main] foobar.value = "my super variable" foobar.type = "string" foobar.description = "Super important variable documentation" baz.type = "address" ``` Access via: `<%= var.main.foobar %>` ### Key features - **Type validation**: Required `type` field with validation for string, address, number, boolean, bytes - **Optional value**: If `value` is not defined, must be provided externally at build time - **Descriptions**: Optional `description` field for documentation - **Namespacing**: Vars are organized in namespaces (e.g., `var.main`, `var.deploy`) ### Breaking changes - `type` is now required for all vars - Vars output to `var.namespace.varname` in addition to `settings.varname` (backwards compat) - Missing values without override will error instead of silently failing ### Internal changes - Added `vars` to ChainBuilderContext type - Updated varSchema to support nested VarDefinition structure - Added type validation functions for address, number, boolean, bytes - Updated context initialization in builder.ts, cli/helpers.ts, website hooks - Added comprehensive tests for new format --- packages/builder/src/builder.ts | 2 + packages/builder/src/schemas.ts | 29 ++- packages/builder/src/steps/var.test.ts | 234 +++++++++++++++++- packages/builder/src/steps/var.ts | 172 ++++++++++++- packages/builder/src/types.ts | 9 +- packages/builder/test/fixtures.ts | 3 + packages/cli/src/helpers.ts | 1 + .../features/Deploy/hooks/useCannonPackage.ts | 1 + 8 files changed, 432 insertions(+), 19 deletions(-) diff --git a/packages/builder/src/builder.ts b/packages/builder/src/builder.ts index 14757d339..ede8b3aab 100644 --- a/packages/builder/src/builder.ts +++ b/packages/builder/src/builder.ts @@ -40,6 +40,8 @@ export async function createInitialContext( imports: {}, settings: _.clone(opts), + + vars: {}, }; } diff --git a/packages/builder/src/schemas.ts b/packages/builder/src/schemas.ts index bca04c1a7..a43e34416 100644 --- a/packages/builder/src/schemas.ts +++ b/packages/builder/src/schemas.ts @@ -858,6 +858,31 @@ export const diamondSchema = z }) .strict(); +/** + * Schema for individual var definitions within a var namespace. + * Each var has a required type, optional value, and optional description. + */ +const varDefinitionSchema = z.object({ + /** + * The value of the variable. If not provided, must be supplied externally at build time. + */ + value: z.string().optional().describe('The value of the variable. If not provided, must be supplied externally at build time.'), + /** + * The type of the variable. Required. Used for validation. + */ + type: z.enum(['string', 'address', 'number', 'boolean', 'bytes']).describe('The type of the variable. Used for validation.'), + /** + * Description of what this variable is used for. + */ + description: z.string().optional().describe('Description of what this variable is used for.'), +}); + +/** + * Schema for var namespace sections (e.g., [var.main]). + * Each namespace contains var definitions keyed by var name. + */ +export const varNamespaceSchema = z.record(z.string(), varDefinitionSchema); + export const varSchema = z .object({ /** @@ -878,7 +903,7 @@ export const varSchema = z 'List of operations that this operation depends on, which Cannon will execute first. If unspecified, Cannon automatically detects dependencies.' ), }) - .catchall(z.string()); + .catchall(z.union([z.string(), varDefinitionSchema])); /** * Shared schema for cannonfile actions (operations). @@ -973,7 +998,7 @@ const cannonfileActionsSchema = z.object({ /** * @internal */ - var: z.record(varSchema).describe('Apply a setting or intermediate value.'), + var: z.record(varNamespaceSchema).describe('Define namespaced variables with type information and descriptions.'), // ... there may be others that come from plugins }); diff --git a/packages/builder/src/steps/var.test.ts b/packages/builder/src/steps/var.test.ts index 7e50afd45..c2212a86f 100644 --- a/packages/builder/src/steps/var.test.ts +++ b/packages/builder/src/steps/var.test.ts @@ -2,10 +2,11 @@ import { fixtureCtx } from '../../test/fixtures'; import { fakeRuntime } from './utils.test.helper'; import { PackageReference } from '../package-reference'; import action from './var'; +import { VarDefinition } from './var'; describe('steps/var.ts', () => { describe('configInject()', () => { - it('injects all fields', async () => { + it('injects all fields (legacy format)', async () => { const result = action.configInject( fixtureCtx({ settings: { a: 'A', b: 'B', from: 'FROM', salt: 'SALT' }, @@ -26,10 +27,39 @@ describe('steps/var.ts', () => { depends: ['<%= settings.A %>'], }); }); + + it('injects values in new var namespace format', async () => { + const result = action.configInject( + fixtureCtx({ + settings: { owner: '0x1234567890123456789012345678901234567890' }, + }), + { + foobar: { + value: '<%= settings.owner %>', + type: 'address' as const, + description: 'Contract owner', + }, + baz: { + type: 'string' as const, + }, + } + ); + + expect(result).toStrictEqual({ + foobar: { + value: '0x1234567890123456789012345678901234567890', + type: 'address', + description: 'Contract owner', + }, + baz: { + type: 'string', + }, + }); + }); }); describe('getState()', () => { - it('resolves correct properties on state', async () => { + it('resolves correct properties on state (legacy format)', async () => { const runtime = fakeRuntime; const ctx = fixtureCtx({ settings: { woot: 'w' } }); @@ -50,7 +80,7 @@ describe('steps/var.ts', () => { }); describe('exec()', () => { - it('works forwards compatible', async () => { + it('works forwards compatible (legacy setting format)', async () => { const step = { ref: new PackageReference('var-test:0.0.0'), currentLabel: 'setting.something', @@ -63,7 +93,7 @@ describe('steps/var.ts', () => { expect(arts).toStrictEqual({ settings: { something: 'shoutout' } }); }); - it('works backwards compatible', async () => { + it('works backwards compatible (legacy var format)', async () => { const step = { ref: new PackageReference('var-test:0.0.0'), currentLabel: 'var.something', @@ -75,5 +105,201 @@ describe('steps/var.ts', () => { const arts = await action.exec(runtime, fixtureCtx(), config, step); expect(arts).toStrictEqual({ settings: { else: 'shoutout' } }); }); + + describe('new var namespace format', () => { + it('returns vars in namespaced format', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + foobar: { + value: 'my super variable', + type: 'string', + description: 'Super important variable documentation', + }, + }; + + const arts = await action.exec(runtime, fixtureCtx(), config as any, step); + expect(arts).toStrictEqual({ + settings: { foobar: 'my super variable' }, + vars: { main: { foobar: 'my super variable' } }, + }); + }); + + it('validates address type', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + owner: { + value: '0x1234567890123456789012345678901234567890', + type: 'address', + }, + }; + + const arts = await action.exec(runtime, fixtureCtx(), config as any, step); + expect(arts.settings.owner).toBe('0x1234567890123456789012345678901234567890'); + }); + + it('throws on invalid address type', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + owner: { + value: 'not-an-address', + type: 'address', + }, + }; + + await expect(action.exec(runtime, fixtureCtx(), config as any, step)).rejects.toThrow( + 'Variable "owner" in namespace "main" has invalid value "not-an-address" for type "address"' + ); + }); + + it('throws when value is missing and no override provided', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + requiredVar: { + type: 'string', + }, + }; + + await expect(action.exec(runtime, fixtureCtx(), config as any, step)).rejects.toThrow( + 'Variable "requiredVar" in namespace "main" has no value defined' + ); + }); + + it('uses override when value is missing', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + overrideableVar: { + type: 'string', + description: 'Can be overridden', + }, + }; + + const ctx = fixtureCtx({ + overrideSettings: { + 'main.overrideableVar': 'overridden-value', + }, + }); + + const arts = await action.exec(runtime, ctx, config as any, step); + expect(arts.settings.overrideableVar).toBe('overridden-value'); + expect(arts.vars!.main.overrideableVar).toBe('overridden-value'); + }); + + it('validates number type', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + amount: { + value: '12345', + type: 'number', + }, + }; + + const arts = await action.exec(runtime, fixtureCtx(), config as any, step); + expect(arts.settings.amount).toBe('12345'); + }); + + it('throws on invalid number type', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + amount: { + value: 'not-a-number', + type: 'number', + }, + }; + + await expect(action.exec(runtime, fixtureCtx(), config as any, step)).rejects.toThrow( + 'Variable "amount" in namespace "main" has invalid value "not-a-number" for type "number"' + ); + }); + + it('validates boolean type', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + enabled: { + value: 'true', + type: 'boolean', + }, + }; + + const arts = await action.exec(runtime, fixtureCtx(), config as any, step); + expect(arts.settings.enabled).toBe('true'); + }); + + it('validates bytes type', async () => { + const step = { + ref: new PackageReference('var-test:0.0.0'), + currentLabel: 'var.main', + }; + + const runtime = fakeRuntime; + const config: Record = { + data: { + value: '0x1234', + type: 'bytes', + }, + }; + + const arts = await action.exec(runtime, fixtureCtx(), config as any, step); + expect(arts.settings.data).toBe('0x1234'); + }); + }); + }); + + describe('getOutputs()', () => { + it('returns settings format for legacy var', () => { + const config = { foo: 'bar' }; + const outputs = action.getOutputs(config, { ref: null, currentLabel: 'var.something' }); + expect(outputs).toContain('settings.foo'); + }); + + it('returns namespaced var format for new format', () => { + const config: Record = { + foobar: { + value: 'test', + type: 'string', + }, + }; + const outputs = action.getOutputs(config as any, { ref: null, currentLabel: 'var.main' }); + expect(outputs).toContain('var.main.foobar'); + }); }); }); diff --git a/packages/builder/src/steps/var.ts b/packages/builder/src/steps/var.ts index 172a70b2a..efa9b0c91 100644 --- a/packages/builder/src/steps/var.ts +++ b/packages/builder/src/steps/var.ts @@ -1,6 +1,7 @@ import Debug from 'debug'; import _ from 'lodash'; import { z } from 'zod'; +import * as viem from 'viem'; import { mergeTemplateAccesses } from '../access-recorder'; import { varSchema } from '../schemas'; import { template } from '../utils/template'; @@ -9,16 +10,78 @@ import { CannonAction } from '../actions'; const debug = Debug('cannon:builder:var'); /** - * Available properties for var operation + * Available properties for var operation (legacy format) * @public * @group Var */ export type Config = z.infer; +/** + * New var definition format with type, value, description + * @public + * @group Var + */ +export type VarDefinition = { + value?: string; + type: 'string' | 'address' | 'number' | 'boolean' | 'bytes'; + description?: string; +}; + +/** + * Var namespace format (e.g., [var.main]) + * @public + * @group Var + */ +export type VarNamespaceConfig = Record; + export interface Outputs { [key: string]: string; } +/** + * Validate a value against its declared type + */ +function validateType(value: string, type: VarDefinition['type']): boolean { + switch (type) { + case 'address': + return viem.isAddress(value); + case 'number': + return !isNaN(Number(value)); + case 'boolean': + return value === 'true' || value === 'false'; + case 'bytes': + return viem.isHex(value); + case 'string': + default: + return true; + } +} + +/** + * Check if a value looks like a VarDefinition object + */ +function isVarDefinition(val: unknown): val is VarDefinition { + return ( + _.isPlainObject(val) && + typeof (val as any).type === 'string' && + ['string', 'address', 'number', 'boolean', 'bytes'].includes((val as any).type) + ); +} + +/** + * Check if config is in the new var namespace format + * Keys that are not 'depends' and have VarDefinition values indicate new format + */ +function isVarNamespaceConfig(config: Record): config is VarNamespaceConfig { + // Check if any key (except 'depends') has a VarDefinition object + for (const [key, val] of Object.entries(config)) { + if (key !== 'depends' && isVarDefinition(val)) { + return true; + } + } + return false; +} + // ensure the specified contract is already deployed // if not deployed, deploy the specified hardhat contract with specfied options, export address, abi, etc. // if already deployed, reexport deployment options for usage downstream and exit with no changes @@ -35,8 +98,23 @@ const varSpec = { configInject(ctx, config) { config = _.cloneDeep(config); - for (const c in _.omit(config, 'depends')) { - config[c] = template(config[c], ctx); + + // Check if this is the new var namespace format + if (isVarNamespaceConfig(config)) { + // New format: inject values in var definitions + for (const [varName, varDef] of Object.entries(config)) { + if (isVarDefinition(varDef) && varDef.value !== undefined) { + varDef.value = template(varDef.value, ctx); + } + // Type and description are not templated + } + } else { + // Legacy format: inject all string values (skip 'depends' array) + for (const c in _.omit(config, 'depends')) { + if (typeof config[c] === 'string') { + config[c] = template(config[c], ctx); + } + } } return config; @@ -45,19 +123,44 @@ const varSpec = { getInputs(config, engine) { let accesses = engine.computeTemplateAccesses(''); - for (const c in _.omit(config, 'depends')) { - const fields = engine.computeTemplateAccesses(config[c]); - accesses = mergeTemplateAccesses(accesses, fields); + // Check if this is the new var namespace format + if (isVarNamespaceConfig(config)) { + for (const [varName, varDef] of Object.entries(config)) { + if (isVarDefinition(varDef) && varDef.value !== undefined) { + const fields = engine.computeTemplateAccesses(varDef.value); + accesses = mergeTemplateAccesses(accesses, fields); + } + } + } else { + // Legacy format + for (const c in _.omit(config, 'depends')) { + if (typeof config[c] === 'string') { + const fields = engine.computeTemplateAccesses(config[c]); + accesses = mergeTemplateAccesses(accesses, fields); + } + } } return accesses; }, getOutputs(config, packageState) { + // Backwards compatibility for old setting format if (packageState.currentLabel.startsWith('setting.')) { return [`settings.${packageState.currentLabel.split('.')[1]}`]; } + const namespace = packageState.currentLabel.split('.')[1]; + + // Check if this is the new var namespace format + if (isVarNamespaceConfig(config)) { + // New format: outputs are var.namespace.varname + return Object.keys(config) + .filter((k) => k !== 'depends') + .map((k) => `var.${namespace}.${k}`); + } + + // Legacy format: outputs are settings.varname return Object.keys(config) .filter((k) => k !== 'depends') .map((k) => `settings.${k}`); @@ -67,10 +170,10 @@ const varSpec = { const varLabel = packageState.currentLabel?.split('.')[1] || ''; debug('exec', config, ctx); - // backwards compatibility + // Backwards compatibility for old setting format if (packageState.currentLabel.startsWith('setting.')) { const stepName = packageState.currentLabel.split('.')[1]; - let value = config.value || config.defaultValue || ctx.overrideSettings[stepName]; + let value = (config as any).value || (config as any).defaultValue || ctx.overrideSettings[stepName]; if (!value) { value = ''; @@ -81,15 +184,60 @@ const varSpec = { [varLabel]: value, }, }; - } else { + } + + const namespace = varLabel; + + // Check if this is the new var namespace format + if (isVarNamespaceConfig(config)) { const settings: { [k: string]: string } = {}; + const vars: { [namespace: string]: { [k: string]: string } } = {}; + + for (const [varName, varDef] of Object.entries(config)) { + if (!isVarDefinition(varDef)) continue; + + // Get value from config, override settings, or error + let value = varDef.value; + const overrideKey = `${namespace}.${varName}`; + + if (ctx.overrideSettings[overrideKey] !== undefined) { + value = ctx.overrideSettings[overrideKey]; + } + + if (value === undefined) { + throw new Error( + `Variable "${varName}" in namespace "${namespace}" has no value defined and no external override was provided. ` + + `Either set \`value\` in the cannonfile or provide --var ${overrideKey}=` + ); + } + + // Validate type + if (!validateType(value, varDef.type)) { + throw new Error( + `Variable "${varName}" in namespace "${namespace}" has invalid value "${value}" for type "${varDef.type}"` + ); + } + + settings[varName] = value; + } - for (const c in _.omit(config, 'depends')) { + // Return both settings (for backwards compat) and namespaced vars + return { + settings, + vars: { [namespace]: settings } + }; + } + + // Legacy format: flat key-value pairs + const settings: { [k: string]: string } = {}; + + for (const c in _.omit(config, 'depends')) { + if (typeof config[c] === 'string') { settings[c] = config[c]; } - - return { settings }; } + + return { settings }; }, } satisfies CannonAction; diff --git a/packages/builder/src/types.ts b/packages/builder/src/types.ts index 69fba8a6a..2784b7f90 100644 --- a/packages/builder/src/types.ts +++ b/packages/builder/src/types.ts @@ -90,6 +90,9 @@ export interface ChainBuilderContext extends PreChainBuilderContext { settings: { [label: string]: string }; + // Namespaced variables (Cannon 3.0+) + vars: { [namespace: string]: { [label: string]: string } }; + // Legacy extras?: { [label: string]: string }; @@ -98,7 +101,7 @@ export interface ChainBuilderContext extends PreChainBuilderContext { [shortContract: string]: any; } -export type CannonContextGlobals = 'imports' | 'contracts' | 'txns' | 'settings' | 'extras'; +export type CannonContextGlobals = 'imports' | 'contracts' | 'txns' | 'settings' | 'vars' | 'extras'; // We do a deepFreeze and deepClone to make sure to not any of the context objects, // and not let the user modify them also, @@ -266,6 +269,10 @@ export function combineCtx(ctxs: ChainBuilderContext[]): ChainBuilderContext { ctx.txns = { ...ctx.txns, ...additionalCtx.txns }; ctx.imports = { ...ctx.imports, ...additionalCtx.imports }; ctx.settings = { ...ctx.settings, ...additionalCtx.settings }; + // Merge vars namespaces + for (const [ns, vars] of Object.entries(additionalCtx.vars || {})) { + ctx.vars[ns] = { ...ctx.vars[ns], ...vars }; + } } return ctx; diff --git a/packages/builder/test/fixtures.ts b/packages/builder/test/fixtures.ts index a54c388b5..4a9cc462a 100644 --- a/packages/builder/test/fixtures.ts +++ b/packages/builder/test/fixtures.ts @@ -35,6 +35,7 @@ export const fixtureCtx = (overrides: Partial = {}) => _.merge( { settings: {}, + vars: {}, contracts: {}, txns: {}, extras: {}, @@ -42,6 +43,8 @@ export const fixtureCtx = (overrides: Partial = {}) => chainId: 1234, package: {}, timestamp: 1234123412, + overrideSettings: {}, + defaultSigner: '0x0000000000000000000000000000000000000000', }, overrides ) as ChainBuilderContext; diff --git a/packages/cli/src/helpers.ts b/packages/cli/src/helpers.ts index 04965aa49..20a84f46d 100644 --- a/packages/cli/src/helpers.ts +++ b/packages/cli/src/helpers.ts @@ -238,6 +238,7 @@ export async function loadCannonfile(filepath: string) { package: pkg, chainId: CANNON_CHAIN_ID, settings: {}, + vars: {}, timestamp: 0, defaultSigner: viem.zeroAddress, diff --git a/packages/website/src/features/Deploy/hooks/useCannonPackage.ts b/packages/website/src/features/Deploy/hooks/useCannonPackage.ts index 3105a2036..eb3702cf0 100644 --- a/packages/website/src/features/Deploy/hooks/useCannonPackage.ts +++ b/packages/website/src/features/Deploy/hooks/useCannonPackage.ts @@ -14,6 +14,7 @@ const ctx: ChainBuilderContext = { package: {}, timestamp: 0 as any, // TODO: fix this settings: {}, + vars: {}, contracts: {}, txns: {}, imports: {},