diff --git a/.gitignore b/.gitignore index a66b74a8e..9531f70f8 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,7 @@ tx-builder-*.json **/horizon-localNetwork/ **/subgraph-service-localNetwork/ !**/ignition/**/artifacts/ + +# Tenderly +.tenderly-artifacts/ + diff --git a/packages/horizon/package.json b/packages/horizon/package.json index 35499f5e1..ed6552b22 100644 --- a/packages/horizon/package.json +++ b/packages/horizon/package.json @@ -53,6 +53,7 @@ "@openzeppelin/contracts": "^5.0.2", "@openzeppelin/contracts-upgradeable": "^5.0.2", "@openzeppelin/foundry-upgrades": "0.4.0", + "@tenderly/hardhat-tenderly": "^1.11.0", "@typechain/ethers-v6": "^0.5.0", "@typechain/hardhat": "^9.0.0", "@types/chai": "^4.2.0", diff --git a/packages/horizon/tasks/tenderly.ts b/packages/horizon/tasks/tenderly.ts new file mode 100644 index 000000000..0f7ef858a --- /dev/null +++ b/packages/horizon/tasks/tenderly.ts @@ -0,0 +1,35 @@ +import { task } from 'hardhat/config' +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { runTenderlyUpload } from '@graphprotocol/toolshed/hardhat' +import addresses from '../addresses.json' +import path from 'path' + +task('tenderly:upload', 'Upload and verify contracts on Tenderly') + .addFlag('noVerify', 'Skip contract verification') + .addFlag('skipAdd', 'Skip adding contracts (only verify)') + .setAction(async (taskArgs: { noVerify: boolean; skipAdd: boolean }, hre: HardhatRuntimeEnvironment) => { + // Dynamically import tenderly plugin only when this task runs + // This avoids triggering provider initialization for other hardhat commands + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { Tenderly } = require('@tenderly/hardhat-integration') + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { lazyObject } = require('hardhat/plugins') + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { configExists, getAccessToken } = require('@tenderly/api-client/utils/config') + + // Manually attach tenderly to hre since extendEnvironment already ran + if (!(hre as any).tenderly) { + ;(hre as any).tenderly = lazyObject(() => new Tenderly(hre)) + } + + if (!configExists()) { + throw new Error( + 'Tenderly config not found. Run `tenderly login` to authenticate, or create ~/.tenderly/config.yaml manually.', + ) + } + + const accessToken = getAccessToken() + const packageDir = path.join(__dirname, '..') + + await runTenderlyUpload(hre, packageDir, addresses, accessToken, taskArgs) + }) diff --git a/packages/horizon/tenderly.config.json b/packages/horizon/tenderly.config.json new file mode 100644 index 000000000..725ce035e --- /dev/null +++ b/packages/horizon/tenderly.config.json @@ -0,0 +1,24 @@ +{ + "username": "graphprotocol", + "networks": { + "421614": { + "project": "horizon-arbitrum-sepolia" + }, + "42161": { + "project": "horizon-arbitrum-one" + } + }, + "externalArtifacts": { + "source": "../contracts/artifacts", + "buildInfo": "../contracts/artifacts/build-info" + }, + "verifyList": [ + "HorizonStaking", + "GraphPayments", + "PaymentsEscrow", + "GraphTallyCollector", + "L2Curation", + "RewardsManager" + ], + "tag": "Horizon" +} diff --git a/packages/subgraph-service/package.json b/packages/subgraph-service/package.json index 1062b429d..a3db13843 100644 --- a/packages/subgraph-service/package.json +++ b/packages/subgraph-service/package.json @@ -52,6 +52,7 @@ "@openzeppelin/contracts": "^5.0.2", "@openzeppelin/contracts-upgradeable": "^5.0.2", "@openzeppelin/foundry-upgrades": "0.4.0", + "@tenderly/hardhat-tenderly": "^1.11.0", "@typechain/ethers-v6": "^0.5.0", "@typechain/hardhat": "^9.0.0", "@types/chai": "^4.2.0", diff --git a/packages/subgraph-service/tasks/tenderly.ts b/packages/subgraph-service/tasks/tenderly.ts new file mode 100644 index 000000000..0f7ef858a --- /dev/null +++ b/packages/subgraph-service/tasks/tenderly.ts @@ -0,0 +1,35 @@ +import { task } from 'hardhat/config' +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import { runTenderlyUpload } from '@graphprotocol/toolshed/hardhat' +import addresses from '../addresses.json' +import path from 'path' + +task('tenderly:upload', 'Upload and verify contracts on Tenderly') + .addFlag('noVerify', 'Skip contract verification') + .addFlag('skipAdd', 'Skip adding contracts (only verify)') + .setAction(async (taskArgs: { noVerify: boolean; skipAdd: boolean }, hre: HardhatRuntimeEnvironment) => { + // Dynamically import tenderly plugin only when this task runs + // This avoids triggering provider initialization for other hardhat commands + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { Tenderly } = require('@tenderly/hardhat-integration') + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { lazyObject } = require('hardhat/plugins') + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { configExists, getAccessToken } = require('@tenderly/api-client/utils/config') + + // Manually attach tenderly to hre since extendEnvironment already ran + if (!(hre as any).tenderly) { + ;(hre as any).tenderly = lazyObject(() => new Tenderly(hre)) + } + + if (!configExists()) { + throw new Error( + 'Tenderly config not found. Run `tenderly login` to authenticate, or create ~/.tenderly/config.yaml manually.', + ) + } + + const accessToken = getAccessToken() + const packageDir = path.join(__dirname, '..') + + await runTenderlyUpload(hre, packageDir, addresses, accessToken, taskArgs) + }) diff --git a/packages/subgraph-service/tenderly.config.json b/packages/subgraph-service/tenderly.config.json new file mode 100644 index 000000000..88680b34a --- /dev/null +++ b/packages/subgraph-service/tenderly.config.json @@ -0,0 +1,21 @@ +{ + "username": "graphprotocol", + "networks": { + "421614": { + "project": "horizon-arbitrum-sepolia" + }, + "42161": { + "project": "horizon-arbitrum-one" + } + }, + "verifyList": [ + "SubgraphService", + "DisputeManager" + ], + "excludeList": [ + "L2Curation", + "L2GNS", + "SubgraphNFT" + ], + "tag": "Subgraph Service" +} diff --git a/packages/toolshed/src/hardhat/index.ts b/packages/toolshed/src/hardhat/index.ts index d0b1183e6..0f289d0ca 100644 --- a/packages/toolshed/src/hardhat/index.ts +++ b/packages/toolshed/src/hardhat/index.ts @@ -4,3 +4,16 @@ export { getEventData } from './event' export { hardhatBaseConfig } from './hardhat.base.config' export { loadConfig, patchConfig, saveToAddressBook } from './ignition' export { requireLocalNetwork } from './local' +export { + loadTenderlyConfig, + copyExternalArtifacts, + classifyContracts, + addContractToTenderly, + tagContractsOnTenderly, + verifyLocalContract, + verifyExternalContract, + runTenderlyUpload, + type TenderlyConfig, + type ContractInfo, + type BuildInfo, +} from './tenderly' diff --git a/packages/toolshed/src/hardhat/tenderly.ts b/packages/toolshed/src/hardhat/tenderly.ts new file mode 100644 index 000000000..57b356430 --- /dev/null +++ b/packages/toolshed/src/hardhat/tenderly.ts @@ -0,0 +1,591 @@ +import { HardhatRuntimeEnvironment } from 'hardhat/types' +import fs from 'fs' +import path from 'path' +import https from 'https' +import { execSync } from 'child_process' + +export interface TenderlyConfig { + username: string + networks: { + [chainId: string]: { + project: string + } + } + externalArtifacts?: { + source: string + buildInfo: string + } + verifyList?: string[] + excludeList?: string[] + tag?: string +} + +export interface ContractInfo { + name: string + address: string + verifyAddress: string + isLocal: boolean + shouldVerify: boolean + artifactPath?: string + sourcePath?: string +} + +export interface BuildInfo { + solcVersion: string + input: { + settings: { + optimizer: { + enabled: boolean + runs: number + } + evmVersion?: string + } + sources: { + [sourceName: string]: { + content: string + } + } + } +} + +export function loadTenderlyConfig(packageDir: string): TenderlyConfig { + const configPath = path.join(packageDir, 'tenderly.config.json') + + if (!fs.existsSync(configPath)) { + throw new Error(`Tenderly config not found at ${configPath}`) + } + + return JSON.parse(fs.readFileSync(configPath, 'utf8')) +} + +export function copyExternalArtifacts(packageDir: string, config: TenderlyConfig): void { + if (!config.externalArtifacts) { + return + } + + const destDir = path.join(packageDir, '.tenderly-artifacts') + const sourceDir = path.resolve(packageDir, config.externalArtifacts.source) + + console.log(`Copying external artifacts from ${sourceDir}...`) + + if (!fs.existsSync(destDir)) { + fs.mkdirSync(destDir, { recursive: true }) + } + + const sourcePath = path.join(sourceDir, 'contracts') + const destPath = path.join(destDir, 'contracts') + + if (fs.existsSync(sourcePath)) { + execSync(`rsync -a "${sourcePath}/" "${destPath}/"`, { stdio: 'inherit' }) + } + + const buildInfoSource = path.resolve(packageDir, config.externalArtifacts.buildInfo) + const buildInfoDest = path.join(destDir, 'build-info') + + if (fs.existsSync(buildInfoSource)) { + execSync(`rsync -a "${buildInfoSource}/" "${buildInfoDest}/"`, { stdio: 'inherit' }) + } + + console.log(`āœ“ External artifacts copied to ${destDir}`) +} + +export function findArtifact(contractName: string, searchDirs: string[]): string | null { + for (const searchDir of searchDirs) { + if (!fs.existsSync(searchDir)) { + continue + } + + const found = findFileRecursive(searchDir, contractName) + + if (found) { + return found + } + } + + return null +} + +function findFileRecursive(dir: string, contractName: string): string | null { + const entries = fs.readdirSync(dir, { withFileTypes: true }) + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name) + + if (entry.isDirectory()) { + if (entry.name === `${contractName}.sol`) { + const jsonPath = path.join(fullPath, `${contractName}.json`) + if (fs.existsSync(jsonPath)) { + return jsonPath + } + } + + const found = findFileRecursive(fullPath, contractName) + if (found) { + return found + } + } + } + + return null +} + +function isLocalContract(artifactPath: string, packageDir: string): boolean { + try { + const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8')) + + if (!artifact.deployedBytecode || artifact.deployedBytecode === '0x') { + return false + } + + const sourceName = artifact.sourceName || '' + if (sourceName.includes('/interfaces/') || sourceName.startsWith('I')) { + return false + } + + if (sourceName.startsWith('@graphprotocol/')) { + return false + } + + if (sourceName.startsWith('contracts/')) { + const sourceFile = path.join(packageDir, sourceName) + if (fs.existsSync(sourceFile)) { + return true + } + } + + return false + } catch { + return false + } +} + +export function classifyContracts( + packageDir: string, + deployments: Record, + verifyList?: string[], + excludeList?: string[], +): ContractInfo[] { + const contracts: ContractInfo[] = [] + const localArtifactsDir = path.join(packageDir, 'build', 'contracts', 'contracts') + const externalArtifactsDir = path.join(packageDir, '.tenderly-artifacts', 'contracts') + + for (const [contractName, contractData] of Object.entries(deployments)) { + if (typeof contractData !== 'object' || !contractData) { + continue + } + + if (excludeList?.includes(contractName)) { + continue + } + + const address = contractData.address + const verifyAddress = contractData.implementation || contractData.address + + if (!address) { + console.warn(`⚠ Skipping ${contractName}: no address found`) + continue + } + + const shouldVerify = verifyList ? verifyList.includes(contractName) : false + + const localArtifact = findArtifact(contractName, [localArtifactsDir]) + + if (localArtifact && isLocalContract(localArtifact, packageDir)) { + contracts.push({ + name: contractName, + address, + verifyAddress, + isLocal: true, + shouldVerify, + artifactPath: localArtifact, + }) + } else { + const externalArtifact = findArtifact(contractName, [externalArtifactsDir]) + + if (externalArtifact) { + const artifact = JSON.parse(fs.readFileSync(externalArtifact, 'utf8')) + contracts.push({ + name: contractName, + address, + verifyAddress, + isLocal: false, + shouldVerify, + artifactPath: externalArtifact, + sourcePath: artifact.sourceName, + }) + } else if (shouldVerify) { + console.warn(`⚠ Skipping ${contractName}: artifact not found (required for verification)`) + } else { + contracts.push({ + name: contractName, + address, + verifyAddress, + isLocal: false, + shouldVerify: false, + }) + } + } + } + + return contracts +} + +export async function addContractToTenderly( + address: string, + networkId: string, + displayName: string, + config: TenderlyConfig, + accessToken: string, +): Promise { + return new Promise((resolve, reject) => { + const networkConfig = config.networks[networkId] + if (!networkConfig) { + reject(new Error(`No Tenderly project configured for network ${networkId}`)) + return + } + + const data = JSON.stringify({ + address: address, + network_id: networkId, + display_name: displayName, + }) + + const options = { + hostname: 'api.tenderly.co', + port: 443, + path: `/api/v1/account/${config.username}/project/${networkConfig.project}/address`, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': data.length, + 'X-Access-Key': accessToken, + }, + } + + const req = https.request(options, (res) => { + let responseData = '' + + res.on('data', (chunk) => { + responseData += chunk + }) + + res.on('end', () => { + if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { + resolve() + } else if (res.statusCode === 409) { + resolve() + } else { + reject(new Error(`HTTP ${res.statusCode}: ${responseData}`)) + } + }) + }) + + req.on('error', reject) + req.write(data) + req.end() + }) +} + +export async function tagContractsOnTenderly( + addresses: string[], + networkId: string, + tag: string, + config: TenderlyConfig, + accessToken: string, +): Promise { + return new Promise((resolve, reject) => { + const networkConfig = config.networks[networkId] + if (!networkConfig) { + reject(new Error(`No Tenderly project configured for network ${networkId}`)) + return + } + + const data = JSON.stringify({ + contract_ids: addresses.map((addr) => `eth:${networkId}:${addr.toLowerCase()}`), + tag: tag, + }) + + const options = { + hostname: 'api.tenderly.co', + port: 443, + path: `/api/v1/account/${config.username}/project/${networkConfig.project}/tag`, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': data.length, + 'X-Access-Key': accessToken, + }, + } + + const req = https.request(options, (res) => { + let responseData = '' + + res.on('data', (chunk) => { + responseData += chunk + }) + + res.on('end', () => { + if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { + resolve() + } else { + reject(new Error(`HTTP ${res.statusCode}: ${responseData}`)) + } + }) + }) + + req.on('error', reject) + req.write(data) + req.end() + }) +} + +export async function verifyLocalContract( + hre: HardhatRuntimeEnvironment, + contractName: string, + verifyAddress: string, +): Promise { + const { tenderly } = hre as any + + if (!tenderly) { + throw new Error('Tenderly plugin not available') + } + + await tenderly.verify({ + name: contractName, + address: verifyAddress, + }) +} + +export async function verifyExternalContract( + hre: HardhatRuntimeEnvironment, + contract: ContractInfo, + networkId: string, + packageDir: string, +): Promise { + const { tenderly } = hre as any + + if (!tenderly) { + throw new Error('Tenderly plugin not available') + } + + if (!contract.artifactPath || !contract.sourcePath) { + throw new Error(`Missing artifact or source path for ${contract.name}`) + } + + const buildInfoFile = findBuildInfoForContract(contract.sourcePath, packageDir) + if (!buildInfoFile) { + throw new Error(`Build info not found for ${contract.name}`) + } + + const buildInfo: BuildInfo = JSON.parse(fs.readFileSync(buildInfoFile, 'utf8')) + + const sources: any = {} + for (const [sourceName, sourceData] of Object.entries(buildInfo.input.sources)) { + sources[sourceName] = { + name: path.basename(sourceName, '.sol'), + code: sourceData.content, + } + } + + const compilerSettings = { + ...buildInfo.input.settings, + evmVersion: buildInfo.input.settings.evmVersion || 'istanbul', + } + + await tenderly.verifyMultiCompilerAPI({ + contracts: [ + { + contractToVerify: `${contract.sourcePath}:${contract.name}`, + sources: sources, + compiler: { + version: buildInfo.solcVersion, + settings: compilerSettings, + }, + networks: { + [networkId]: { + address: contract.verifyAddress, + }, + }, + }, + ], + }) +} + +function findBuildInfoForContract(sourcePath: string, packageDir: string): string | null { + const buildInfoDir = path.join(packageDir, '.tenderly-artifacts', 'build-info') + + if (!fs.existsSync(buildInfoDir)) { + return null + } + + const buildInfoFiles = fs.readdirSync(buildInfoDir).filter((f) => f.endsWith('.json')) + + for (const file of buildInfoFiles) { + try { + const buildInfoPath = path.join(buildInfoDir, file) + const buildInfo = JSON.parse(fs.readFileSync(buildInfoPath, 'utf8')) + + if (buildInfo.input?.sources && sourcePath in buildInfo.input.sources) { + return buildInfoPath + } + } catch (e) { + continue + } + } + + return null +} + +export async function runTenderlyUpload( + hre: HardhatRuntimeEnvironment, + packageDir: string, + addresses: Record, + accessToken: string, + taskArgs: { noVerify: boolean; skipAdd: boolean }, +): Promise { + const { network } = hre + + const chainId = network.config.chainId?.toString() + if (!chainId) { + throw new Error('Network chain ID not found') + } + + console.log(`\nšŸ“¤ Uploading contracts to Tenderly`) + console.log(`Network: ${network.name} (${chainId})`) + + const tenderlyConfig = loadTenderlyConfig(packageDir) + const networkConfig = tenderlyConfig.networks[chainId] + + if (!networkConfig) { + throw new Error(`No Tenderly project configured for network ${chainId}`) + } + + console.log(`Tenderly project: ${tenderlyConfig.username}/${networkConfig.project}\n`) + + // Copy external artifacts if configured + if (tenderlyConfig.externalArtifacts) { + copyExternalArtifacts(packageDir, tenderlyConfig) + console.log() + } + + const deployments = addresses[chainId] + if (!deployments) { + throw new Error(`No deployments found for network ${chainId}`) + } + + const contracts = classifyContracts( + packageDir, + deployments, + tenderlyConfig.verifyList, + tenderlyConfig.excludeList, + ) + + console.log(`\nFound ${contracts.length} contracts:`) + const localCount = contracts.filter((c) => c.isLocal).length + const externalCount = contracts.filter((c) => !c.isLocal).length + const verifyCount = contracts.filter((c) => c.shouldVerify).length + console.log(` ${localCount} local contracts`) + console.log(` ${externalCount} external contracts`) + console.log(` ${verifyCount} to verify (in verifyList)\n`) + + // Step 1: Add all contracts to Tenderly project + if (!taskArgs.skipAdd) { + console.log(`\n${'='.repeat(60)}`) + console.log(`Step 1: Adding contracts to Tenderly project`) + console.log(`${'='.repeat(60)}\n`) + + let addedCount = 0 + let addFailedCount = 0 + + for (const contract of contracts) { + try { + console.log(`Adding ${contract.name} (${contract.address})...`) + await addContractToTenderly( + contract.address, + chainId, + contract.name, + tenderlyConfig, + accessToken, + ) + console.log(` āœ“ Added\n`) + addedCount++ + + await new Promise((resolve) => setTimeout(resolve, 500)) + } catch (error: any) { + console.error(` āœ— Failed: ${error.message}\n`) + addFailedCount++ + } + } + + console.log(`Summary: ${addedCount} added, ${addFailedCount} failed\n`) + + // Tag contracts if configured + if (tenderlyConfig.tag) { + console.log(`Tagging contracts with "${tenderlyConfig.tag}"...`) + try { + await tagContractsOnTenderly( + contracts.map((c) => c.address), + chainId, + tenderlyConfig.tag, + tenderlyConfig, + accessToken, + ) + console.log(` āœ“ Tagged ${contracts.length} contracts\n`) + } catch (error: any) { + console.error(` āœ— Failed to tag: ${error.message}\n`) + } + } + } else { + console.log(`\nā© Skipping add step (--skip-add flag set)\n`) + } + + // Step 2: Verify contracts (if not skipped) + if (!taskArgs.noVerify) { + console.log(`\n${'='.repeat(60)}`) + console.log(`Step 2: Verifying contracts`) + console.log(`${'='.repeat(60)}\n`) + + const contractsToVerify = contracts.filter((c) => c.shouldVerify) + const contractsToSkip = contracts.filter((c) => !c.shouldVerify) + + console.log(`Verifying ${contractsToVerify.length} of ${contracts.length} contracts (allowlist)`) + if (contractsToSkip.length > 0) { + console.log(`Skipping verification for: ${contractsToSkip.map((c) => c.name).join(', ')}\n`) + } + + let verifiedCount = 0 + let verifyFailedCount = 0 + + for (const contract of contractsToVerify) { + try { + console.log(`Verifying ${contract.name}...`) + console.log(` Type: ${contract.isLocal ? 'local' : 'external'}`) + + if (contract.isLocal) { + await verifyLocalContract(hre, contract.name, contract.verifyAddress) + } else { + await verifyExternalContract(hre, contract, chainId, packageDir) + } + + console.log(` āœ“ Verified\n`) + verifiedCount++ + + await new Promise((resolve) => setTimeout(resolve, 1000)) + } catch (error: any) { + console.error(` āœ— Failed: ${error.message}\n`) + verifyFailedCount++ + } + } + + console.log(`Summary: ${verifiedCount} verified, ${verifyFailedCount} failed\n`) + } else { + console.log(`\nā© Skipping verification (--no-verify flag set)\n`) + } + + console.log(`\n${'='.repeat(60)}`) + console.log(`āœ… Upload complete!`) + console.log(`${'='.repeat(60)}`) + console.log( + `\nView contracts: https://dashboard.tenderly.co/${tenderlyConfig.username}/${networkConfig.project}/contracts\n`, + ) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99a5dc71c..62b9127a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -829,6 +829,9 @@ importers: '@openzeppelin/foundry-upgrades': specifier: 0.4.0 version: 0.4.0(@openzeppelin/defender-deploy-client-cli@0.0.1-alpha.10(encoding@0.1.13))(@openzeppelin/upgrades-core@1.44.1) + '@tenderly/hardhat-tenderly': + specifier: ^1.11.0 + version: 1.11.0(@types/node@20.19.14)(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.26.3(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@20.19.14)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@typechain/ethers-v6': specifier: ^0.5.0 version: 0.5.1(ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(patch_hash=b34ed6afcf99760666fdc85ecb2094fdd20ce509f947eb09cef21665a2a6a1d6)(typescript@5.9.3))(typescript@5.9.3) @@ -1006,6 +1009,9 @@ importers: '@openzeppelin/foundry-upgrades': specifier: 0.4.0 version: 0.4.0(@openzeppelin/defender-deploy-client-cli@0.0.1-alpha.10(encoding@0.1.13))(@openzeppelin/upgrades-core@1.44.1) + '@tenderly/hardhat-tenderly': + specifier: ^1.11.0 + version: 1.11.0(@types/node@20.19.14)(bufferutil@4.0.9)(encoding@0.1.13)(hardhat@2.26.3(bufferutil@4.0.9)(ts-node@10.9.2(@types/node@20.19.14)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@typechain/ethers-v6': specifier: ^0.5.0 version: 0.5.1(ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typechain@8.3.2(patch_hash=b34ed6afcf99760666fdc85ecb2094fdd20ce509f947eb09cef21665a2a6a1d6)(typescript@5.9.3))(typescript@5.9.3) @@ -13284,7 +13290,7 @@ snapshots: '@ethereumjs/common@2.6.0': dependencies: crc-32: 1.2.2 - ethereumjs-util: 7.1.3 + ethereumjs-util: 7.1.5 '@ethereumjs/common@2.6.5': dependencies: @@ -13306,7 +13312,7 @@ snapshots: '@ethereumjs/tx@3.4.0': dependencies: '@ethereumjs/common': 2.6.0 - ethereumjs-util: 7.1.3 + ethereumjs-util: 7.1.5 '@ethereumjs/tx@3.5.2': dependencies: @@ -13333,7 +13339,7 @@ snapshots: async-eventemitter: 0.2.4 core-js-pure: 3.45.1 debug: 2.6.9 - ethereumjs-util: 7.1.3 + ethereumjs-util: 7.1.5 functional-red-black-tree: 1.0.1 mcl-wasm: 0.7.9 merkle-patricia-tree: 4.2.4 @@ -13357,12 +13363,12 @@ snapshots: '@ethersproject/abi@5.6.0': dependencies: '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.6.0 '@ethersproject/hash': 5.6.0 '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/strings': 5.6.0 @@ -13392,9 +13398,9 @@ snapshots: '@ethersproject/abstract-provider@5.6.0': dependencies: - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/networks': 5.6.1 '@ethersproject/properties': 5.6.0 '@ethersproject/transactions': 5.6.0 @@ -13402,7 +13408,7 @@ snapshots: '@ethersproject/abstract-provider@5.7.0': dependencies: - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.7.0 '@ethersproject/networks': 5.7.1 @@ -13423,15 +13429,15 @@ snapshots: '@ethersproject/abstract-signer@5.6.0': dependencies: '@ethersproject/abstract-provider': 5.8.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/abstract-signer@5.7.0': dependencies: '@ethersproject/abstract-provider': 5.8.0 - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 @@ -13446,10 +13452,10 @@ snapshots: '@ethersproject/address@5.6.0': dependencies: - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/rlp': 5.6.0 '@ethersproject/address@5.6.1': @@ -13462,7 +13468,7 @@ snapshots: '@ethersproject/address@5.7.0': dependencies: - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/keccak256': 5.7.0 '@ethersproject/logger': 5.7.0 @@ -13506,7 +13512,7 @@ snapshots: '@ethersproject/bignumber@5.6.0': dependencies: '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 bn.js: 4.12.2 '@ethersproject/bignumber@5.7.0': @@ -13523,7 +13529,7 @@ snapshots: '@ethersproject/bytes@5.6.1': dependencies: - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/bytes@5.7.0': dependencies: @@ -13535,11 +13541,11 @@ snapshots: '@ethersproject/constants@5.6.0': dependencies: - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/constants@5.7.0': dependencies: - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/constants@5.8.0': dependencies: @@ -13551,10 +13557,10 @@ snapshots: '@ethersproject/abstract-provider': 5.8.0 '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/transactions': 5.6.0 @@ -13564,7 +13570,7 @@ snapshots: '@ethersproject/abstract-provider': 5.8.0 '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.7.0 '@ethersproject/logger': 5.7.0 @@ -13609,10 +13615,10 @@ snapshots: dependencies: '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/strings': 5.6.0 @@ -13621,7 +13627,7 @@ snapshots: '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/address': 5.8.0 '@ethersproject/base64': 5.7.0 - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/keccak256': 5.7.0 '@ethersproject/logger': 5.7.0 @@ -13644,9 +13650,9 @@ snapshots: dependencies: '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/basex': 5.6.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/pbkdf2': 5.6.0 '@ethersproject/properties': 5.6.0 '@ethersproject/sha2': 5.6.0 @@ -13659,7 +13665,7 @@ snapshots: dependencies: '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.7.0 '@ethersproject/pbkdf2': 5.7.0 @@ -13692,7 +13698,7 @@ snapshots: '@ethersproject/bytes': 5.8.0 '@ethersproject/hdnode': 5.6.0 '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/pbkdf2': 5.6.0 '@ethersproject/properties': 5.6.0 '@ethersproject/random': 5.6.0 @@ -13756,11 +13762,11 @@ snapshots: '@ethersproject/networks@5.6.1': dependencies: - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/networks@5.7.0': dependencies: - '@ethersproject/logger': 5.7.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/networks@5.7.1': dependencies: @@ -13787,7 +13793,7 @@ snapshots: '@ethersproject/properties@5.6.0': dependencies: - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties@5.7.0': dependencies: @@ -13803,11 +13809,11 @@ snapshots: '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/address': 5.8.0 '@ethersproject/basex': 5.6.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.6.0 '@ethersproject/hash': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/networks': 5.6.1 '@ethersproject/properties': 5.6.0 '@ethersproject/random': 5.6.0 @@ -13829,18 +13835,18 @@ snapshots: '@ethersproject/address': 5.8.0 '@ethersproject/base64': 5.7.0 '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 - '@ethersproject/constants': 5.7.0 + '@ethersproject/constants': 5.8.0 '@ethersproject/hash': 5.7.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/networks': 5.7.0 '@ethersproject/properties': 5.7.0 '@ethersproject/random': 5.7.0 '@ethersproject/rlp': 5.7.0 '@ethersproject/sha2': 5.7.0 '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 + '@ethersproject/transactions': 5.8.0 '@ethersproject/web': 5.7.0 bech32: 1.1.4 ws: 7.4.6(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -13903,7 +13909,7 @@ snapshots: '@ethersproject/random@5.6.0': dependencies: '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/random@5.7.0': dependencies: @@ -13918,7 +13924,7 @@ snapshots: '@ethersproject/rlp@5.6.0': dependencies: '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/rlp@5.7.0': dependencies: @@ -13933,7 +13939,7 @@ snapshots: '@ethersproject/sha2@5.6.0': dependencies: '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 hash.js: 1.1.7 '@ethersproject/sha2@5.7.0': @@ -13951,7 +13957,7 @@ snapshots: '@ethersproject/signing-key@5.6.0': dependencies: '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 bn.js: 4.12.2 elliptic: 6.5.4 @@ -13977,16 +13983,16 @@ snapshots: '@ethersproject/solidity@5.6.0': dependencies: - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/sha2': 5.6.0 '@ethersproject/strings': 5.6.0 '@ethersproject/solidity@5.7.0': dependencies: - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/keccak256': 5.7.0 '@ethersproject/logger': 5.7.0 @@ -14006,7 +14012,7 @@ snapshots: dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/strings@5.7.0': dependencies: @@ -14023,11 +14029,11 @@ snapshots: '@ethersproject/transactions@5.6.0': dependencies: '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.6.0 '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/rlp': 5.6.0 '@ethersproject/signing-key': 5.6.0 @@ -14035,7 +14041,7 @@ snapshots: '@ethersproject/transactions@5.7.0': dependencies: '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/constants': 5.7.0 '@ethersproject/keccak256': 5.7.0 @@ -14058,13 +14064,13 @@ snapshots: '@ethersproject/units@5.6.0': dependencies: - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/constants': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/units@5.7.0': dependencies: - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/constants': 5.7.0 '@ethersproject/logger': 5.7.0 @@ -14079,13 +14085,13 @@ snapshots: '@ethersproject/abstract-provider': 5.8.0 '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.6.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/hash': 5.6.0 '@ethersproject/hdnode': 5.6.0 '@ethersproject/json-wallets': 5.6.0 '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/random': 5.6.0 '@ethersproject/signing-key': 5.6.0 @@ -14097,7 +14103,7 @@ snapshots: '@ethersproject/abstract-provider': 5.8.0 '@ethersproject/abstract-signer': 5.8.0 '@ethersproject/address': 5.8.0 - '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bignumber': 5.8.0 '@ethersproject/bytes': 5.8.0 '@ethersproject/hash': 5.7.0 '@ethersproject/hdnode': 5.7.0 @@ -14132,7 +14138,7 @@ snapshots: dependencies: '@ethersproject/base64': 5.6.0 '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/strings': 5.6.0 @@ -14140,7 +14146,7 @@ snapshots: dependencies: '@ethersproject/base64': 5.7.0 '@ethersproject/bytes': 5.8.0 - '@ethersproject/logger': 5.7.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 @@ -14164,7 +14170,7 @@ snapshots: dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/hash': 5.6.0 - '@ethersproject/logger': 5.6.0 + '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.6.0 '@ethersproject/strings': 5.6.0