From 6c8beb87218a7a657c95ad540e071d3cd97c2733 Mon Sep 17 00:00:00 2001 From: jmc <33655003+jmcook1186@users.noreply.github.com> Date: Thu, 17 Oct 2024 14:57:55 +0100 Subject: [PATCH 1/2] feat(src): refactor into files, make level and unit CLI args --- src/if-attest/README.md | 8 + src/if-attest/config/config.ts | 74 ++++--- src/if-attest/index.ts | 192 ++---------------- src/if-attest/types/process-args.ts | 6 +- src/if-attest/util/args.ts | 4 +- src/if-attest/util/attestation-utils.ts | 122 +++++++++++ src/if-attest/util/ethereum-utils.ts | 14 ++ .../util/offchain-attestation-utils.ts | 49 +++++ ...ister-eas-schema.ts => register-schema.ts} | 2 +- 9 files changed, 256 insertions(+), 215 deletions(-) create mode 100644 src/if-attest/util/attestation-utils.ts create mode 100644 src/if-attest/util/ethereum-utils.ts create mode 100644 src/if-attest/util/offchain-attestation-utils.ts rename src/if-attest/util/{register-eas-schema.ts => register-schema.ts} (96%) diff --git a/src/if-attest/README.md b/src/if-attest/README.md index 14bb8420..a98f9ed0 100644 --- a/src/if-attest/README.md +++ b/src/if-attest/README.md @@ -99,6 +99,14 @@ Attestations are just snippets of data that conform to some predefined schema an We are using the [Ethereum Attestation Service](https://attest.org/) to bootstrap our attestations. They have deployed the attestation smart contracts on Ethereum and many other associated blockchains, such as layer 2's and testnets. Layer 2's are cheaper, faster blockchains that settle to the main Ethereum blockchain periodically. Testnets are blockchains that use tokens of no real world value and are typically used to test smart contracts befor they are deployed on a "real" network. +Here's an example of a raw attestation. If you run `if-attest` configured to create local attestations, you'll get a text file that looks like this: + +``` +{"sig":{"version":2,"uid":"0x047d38b6d175fe8a36a597863b7d8d94939aa2fd4b4f19831229c95f5eda5604","domain":{"name":"EAS Attestation","version":"0.26","chainId":"11155111","verifyingContract":"0xC2679fBD37d54388Ce493F1DB75320D236e1815e"},"primaryType":"Attest","message":{"version":2,"recipient":"0xc8317137B5c511ef9CE1762CE498FE16950EF42d","expirationTime":"0","time":"1729173300","revocable":true,"schema":"0x11fdca810433efc2d5b9fe8305b39669e8d0feb81f699a767fe48ce26fcf6a6c","refUID":"0x0000000000000000000000000000000000000000000000000000000000000000","data":"0x000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a020d034e94040bf5b40ff76f9568155cacbc7ed0d488a8fcea8dc37bd24b0d0dd00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000010323032332d30382d30365430303a3030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010323032332d30382d30365430303a3030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005302e372e30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b736974652d766973697473000000000000000000000000000000000000000000","salt":"0x0951f85ad71286a55562608cfba8cad023820a78cce8fd5df2a1498af0812505"},"types":{"Attest":[{"name":"version","type":"uint16"},{"name":"schema","type":"bytes32"},{"name":"recipient","type":"address"},{"name":"time","type":"uint64"},{"name":"expirationTime","type":"uint64"},{"name":"revocable","type":"bool"},{"name":"refUID","type":"bytes32"},{"name":"data","type":"bytes"},{"name":"salt","type":"bytes32"}]},"signature":{"v":27,"r":"0xea4ac79da011dd364b69cfb45cce6e9b5d71444861d0bb44456d7e50f433f981","s":"0x4106232e9af816c465657e10d39612c958f5b6f552d637c9cff5469ee7634333"}}, "signer":"0xc8317137B5c511ef9CE1762CE498FE16950EF42d"} +``` + +OK, it's not super human readable. This is because the manifest data is hex-encoded. Everything you need to verify the signatuire and recover the manifest summary data is here. + ## Onchain vs offchain attestations diff --git a/src/if-attest/config/config.ts b/src/if-attest/config/config.ts index e05f811f..9e62dbc9 100644 --- a/src/if-attest/config/config.ts +++ b/src/if-attest/config/config.ts @@ -1,37 +1,51 @@ -import {ArgumentConfig, ParseOptions} from 'ts-command-line-args'; -import {STRINGS as COMMON_STRINGS} from '../../common/config'; -import {IFAttestArgs} from '../types/process-args'; +import { ArgumentConfig, ParseOptions } from 'ts-command-line-args'; +import { STRINGS as COMMON_STRINGS } from '../../common/config'; +import { IFAttestArgs } from '../types/process-args'; -const {DISCLAIMER_MESSAGE} = COMMON_STRINGS; +const { DISCLAIMER_MESSAGE } = COMMON_STRINGS; export const CONFIG = { - ARGS: { - manifest: { - type: String, - optional: false, - alias: 'm', - description: '[path to the manifest file]', - }, - blockchain: { - type: Boolean, - optional: true, - alias: 'b', - description: - '[Boolean to toggle posting attestation to blockchain (true to post, false to save locally)]', - }, - } as ArgumentConfig, - HELP: { - helpArg: 'help', - headerContentSections: [ - {header: 'Impact Framework', content: 'IF-Attest Helpful keywords:'}, - ], - footerContentSections: [ - {header: 'Green Software Foundation', content: DISCLAIMER_MESSAGE}, - ], - } as ParseOptions, + ARGS: { + manifest: { + type: String, + optional: false, + alias: 'm', + description: '[path to the manifest file]', + }, + blockchain: { + type: Boolean, + optional: true, + alias: 'b', + description: + '[Boolean to toggle posting attestation to blockchain (true to post, false to save locally)]', + }, + level: { + type: Number, + optional: true, + alias: 'l', + description: + '[Audit level being attested to - integers from 1-5]', + }, + unit: { + type: String, + optional: true, + alias: 'u', + description: + '[The functional unit used to calculate SCI]', + }, + } as ArgumentConfig, + HELP: { + helpArg: 'help', + headerContentSections: [ + { header: 'Impact Framework', content: 'IF-Attest Helpful keywords:' }, + ], + footerContentSections: [ + { header: 'Green Software Foundation', content: DISCLAIMER_MESSAGE }, + ], + } as ParseOptions, }; export const STRINGS = { - MANIFEST_IS_NOT_YAML: (path: string) => - `The \`${path}\` is not in yaml format.`, + MANIFEST_IS_NOT_YAML: (path: string) => + `The \`${path}\` is not in yaml format.`, }; diff --git a/src/if-attest/index.ts b/src/if-attest/index.ts index 486638fb..c1962f53 100644 --- a/src/if-attest/index.ts +++ b/src/if-attest/index.ts @@ -1,53 +1,33 @@ #!/usr/bin/env node /* eslint-disable no-process-exit */ -import {ethers, Wallet} from 'ethers'; -import {ManifestInfo} from './types/types'; -import * as YAML from 'js-yaml'; import { EAS, - SchemaEncoder, - SignedOffchainAttestation, - // OffchainAttestationVersion, } from '@ethereum-attestation-service/eas-sdk'; -import {execPromise} from '../common/util/helpers'; -import {openYamlFileAsObject} from '../common/util/yaml'; -import {Manifest} from '../common/types/manifest'; -import {logger} from '../common/util/logger'; -import {parseIfAttestArgs} from './util/args'; -import * as dotenv from 'dotenv'; +import { logger } from '../common/util/logger'; +import { parseIfAttestArgs } from './util/args'; import * as fs from 'fs'; -import {SCHEMA} from './util/schema'; - -const packageJson = require('../../package.json'); -dotenv.config(); +import {createSigningWallet} from './util/ethereum-utils'; +import {addSignerInfoToAttestation, createOffchainAttestaton} from './util/offchain-attestation-utils'; +import {sendAttestationTx, encodeSchema, getManifestInfo } from './util/attestation-utils'; const EAS_CONTRACT_ADDRESS_SEPOLIA: string = process.env.EAS_CONTRACT_ADDRESS_SEPOLIA ?? ''; -const UID = process.env.SCHEMA_UID ?? ''; -const PRIVATE_KEY: string = process.env.ETH_PRIVATE_KEY ?? ''; -const INFURA_API_KEY: string = process.env.INFURA_API_KEY ?? ''; - -const createSigningWallet = (): Wallet => { - const provider = new ethers.JsonRpcProvider( - `https://sepolia.infura.io/v3/${INFURA_API_KEY}` - ); - const signer = new ethers.Wallet(PRIVATE_KEY, provider); - return signer; -}; const IfAttest = async () => { console.debug('starting attestation'); const commandArgs = await parseIfAttestArgs(); + + // initialize command args const manifestPath = commandArgs.manifest; + const level = commandArgs.level; + const functionalUnit = commandArgs.unit; - console.debug('creating Ethereum account'); + console.debug('initializing Ethereum account'); const signer = createSigningWallet(); const eas = new EAS(EAS_CONTRACT_ADDRESS_SEPOLIA); - eas.connect(signer); - //todo: make level and functional-unit CLI args - const level = 1; - const functionalUnit = 'site-visits'; + console.debug('creating signer object') + eas.connect(signer); const manifestInfo = await getManifestInfo( manifestPath, @@ -81,154 +61,6 @@ const IfAttest = async () => { } }; -const createOffchainAttestaton = async ( - eas: EAS, - signer: Wallet, - encodedData: string -): Promise => { - const offchain = await eas.getOffchain(); - - const attestation = await offchain.signOffchainAttestation( - { - recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address - expirationTime: BigInt(0), - time: BigInt(Math.floor(Date.now() / 1000)), - revocable: true, // Be aware that if your schema is not revocable, this MUST be false - schema: UID, - refUID: - '0x0000000000000000000000000000000000000000000000000000000000000000', - data: encodedData, - }, - signer, - { - verifyOnchain: false, - } - ); - return attestation; -}; - -const addSignerInfoToAttestation = ( - attestation: SignedOffchainAttestation, - signer: Wallet -): string => { - const prefix = '{"sig":'; - const suffix = `, "signer":${JSON.stringify(signer.address)}}`; - return ( - prefix + - JSON.stringify(attestation, (_, v) => - typeof v === 'bigint' ? v.toString() : v - ) + - suffix - ); -}; - -const sendAttestationTx = async ( - eas: EAS, - signer: Wallet, - encodedData: string -): Promise => { - const tx = await eas.attest({ - schema: UID, - data: { - recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address - expirationTime: BigInt(0), - revocable: true, // Be aware that if your schema is not revocable, this MUST be false - data: encodedData, - }, - }); - const attestationUID = await tx.wait(); - return attestationUID; -}; - -const encodeSchema = (manifestInfo: ManifestInfo) => { - const schemaEncoder = new SchemaEncoder(SCHEMA); - const encodedData = schemaEncoder.encodeData([ - {name: 'start', value: manifestInfo.start, type: 'string'}, - {name: 'end', value: manifestInfo.end, type: 'string'}, - {name: 'hash', value: manifestInfo.hash, type: 'bytes32'}, - {name: 'if', value: manifestInfo.if, type: 'string'}, - {name: 'verified', value: manifestInfo.verified, type: 'bool'}, - {name: 'sci', value: manifestInfo.sci, type: 'uint64'}, - {name: 'energy', value: manifestInfo.energy, type: 'uint64'}, - {name: 'carbon', value: manifestInfo.carbon, type: 'uint64'}, - {name: 'level', value: manifestInfo.level, type: 'uint8'}, - {name: 'quality', value: manifestInfo.quality, type: 'uint8'}, - { - name: 'functionalUnit', - value: manifestInfo.functionalUnit, - type: 'string', - }, - ]); - return encodedData; -}; - -const getManifestStart = (manifest: Manifest): string => { - const firstChildName = Object.keys(manifest.tree.children)[0] ?? 0; - const manifestStart = - manifest.tree.children[`${firstChildName}`].inputs[0].timestamp ?? 0; - return manifestStart; -}; - -const getManifestEnd = (manifest: Manifest): string => { - const firstChildName = Object.keys(manifest.tree.children)[0]; - const inputsLength = - manifest.tree.children[`${firstChildName}`].inputs.length ?? ''; - const manifestEnd = - manifest.tree.children[`${firstChildName}`].inputs[inputsLength - 1] - .timestamp ?? ''; - return manifestEnd; -}; - -const getManifestInfo = async ( - manifestPath: string, - level: number, - functionalUnit: string -): Promise => { - const manifest = await openYamlFileAsObject(manifestPath); - - // const functionalUnitStub = file.initialize.plugins.sci['global-config']['functional-unit'] ?? ''; - - const info: ManifestInfo = { - start: getManifestStart(manifest), - end: getManifestEnd(manifest), - hash: GetManifestHash(manifest), - if: GetIfVersion(), - verified: await runIfCheck(manifestPath), - sci: manifest.tree.aggregated.sci ?? 0, - energy: manifest.tree.aggregated.energy ?? 0, - carbon: manifest.tree.aggregated.carbon ?? 0, - level: level, - quality: 1, // quality score not yet functional in IF, - functionalUnit: functionalUnit, - }; - - return info; -}; - -const GetManifestHash = (manifest: Manifest): string => { - const manifestAsString = YAML.dump(manifest).toString(); - const manifestAsBytes: Uint8Array = ethers.toUtf8Bytes(manifestAsString); - const manifestHash = ethers.keccak256(manifestAsBytes); - return manifestHash; -}; - -const GetIfVersion = (): string => { - return packageJson.version; -}; - -const runIfCheck = async (manifestPath: string): Promise => { - const response = await execPromise(`npm run if-check -- -m ${manifestPath}`, { - cwd: process.env.CURRENT_DIR || process.cwd(), - }); - - if (response.stdout.includes('if-check could not verify the manifest')) { - console.log('IF-CHECK: verification was unsuccessful. Files do not match'); - return false; - } - console.log('IF-CHECK: verification was successful'); - - return true; -}; IfAttest().catch(error => { if (error instanceof Error) { diff --git a/src/if-attest/types/process-args.ts b/src/if-attest/types/process-args.ts index f337c48a..be915a97 100644 --- a/src/if-attest/types/process-args.ts +++ b/src/if-attest/types/process-args.ts @@ -1,4 +1,6 @@ export interface IFAttestArgs { - manifest: string; - blockchain?: boolean; + manifest: string; + blockchain?: boolean; + level: number; + unit: string; } diff --git a/src/if-attest/util/args.ts b/src/if-attest/util/args.ts index 0a3263de..a3e01dcf 100644 --- a/src/if-attest/util/args.ts +++ b/src/if-attest/util/args.ts @@ -35,7 +35,7 @@ const validateAndParseIfAttestArgs = () => { * Checks if the `manifests` command is provided and they are valid manifests files or a folder. */ export const parseIfAttestArgs = async () => { - const {manifest, blockchain} = validateAndParseIfAttestArgs(); + const {manifest, blockchain, level, unit} = validateAndParseIfAttestArgs(); const response = prependFullFilePath(manifest); const isManifestFileExists = await isFileExists(response); @@ -49,5 +49,5 @@ export const parseIfAttestArgs = async () => { throw new CliSourceFileError(MANIFEST_IS_NOT_YAML(manifest)); } - return {manifest, blockchain}; + return {manifest, blockchain, level, unit}; }; diff --git a/src/if-attest/util/attestation-utils.ts b/src/if-attest/util/attestation-utils.ts new file mode 100644 index 00000000..67932dfb --- /dev/null +++ b/src/if-attest/util/attestation-utils.ts @@ -0,0 +1,122 @@ +import { ManifestInfo } from '../types/types'; +import * as YAML from 'js-yaml'; +import { + EAS, + SchemaEncoder, +} from '@ethereum-attestation-service/eas-sdk'; +import { execPromise } from '../../common/util/helpers'; +import { openYamlFileAsObject } from '../../common/util/yaml'; +import { Manifest } from '../../common/types/manifest'; +import { SCHEMA } from '../util/schema'; +import { ethers, Wallet } from 'ethers'; + +const packageJson = require('../../../package.json'); +const UID = process.env.SCHEMA_UID ?? ''; + +export const sendAttestationTx = async ( + eas: EAS, + signer: Wallet, + encodedData: string +): Promise => { + const tx = await eas.attest({ + schema: UID, + data: { + recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address + expirationTime: BigInt(0), + revocable: true, // Be aware that if your schema is not revocable, this MUST be false + data: encodedData, + }, + }); + const attestationUID = await tx.wait(); + return attestationUID; +}; + +export const encodeSchema = (manifestInfo: ManifestInfo) => { + const schemaEncoder = new SchemaEncoder(SCHEMA); + const encodedData = schemaEncoder.encodeData([ + { name: 'start', value: manifestInfo.start, type: 'string' }, + { name: 'end', value: manifestInfo.end, type: 'string' }, + { name: 'hash', value: manifestInfo.hash, type: 'bytes32' }, + { name: 'if', value: manifestInfo.if, type: 'string' }, + { name: 'verified', value: manifestInfo.verified, type: 'bool' }, + { name: 'sci', value: manifestInfo.sci, type: 'uint64' }, + { name: 'energy', value: manifestInfo.energy, type: 'uint64' }, + { name: 'carbon', value: manifestInfo.carbon, type: 'uint64' }, + { name: 'level', value: manifestInfo.level, type: 'uint8' }, + { name: 'quality', value: manifestInfo.quality, type: 'uint8' }, + { + name: 'functionalUnit', + value: manifestInfo.functionalUnit, + type: 'string', + }, + ]); + return encodedData; +}; + +export const getManifestStart = (manifest: Manifest): string => { + const firstChildName = Object.keys(manifest.tree.children)[0] ?? 0; + const manifestStart = + manifest.tree.children[`${firstChildName}`].inputs[0].timestamp ?? 0; + return manifestStart; +}; + +export const getManifestEnd = (manifest: Manifest): string => { + const firstChildName = Object.keys(manifest.tree.children)[0]; + const inputsLength = + manifest.tree.children[`${firstChildName}`].inputs.length ?? ''; + const manifestEnd = + manifest.tree.children[`${firstChildName}`].inputs[inputsLength - 1] + .timestamp ?? ''; + return manifestEnd; +}; + +export const getManifestInfo = async ( + manifestPath: string, + level: number, + functionalUnit: string +): Promise => { + const manifest = await openYamlFileAsObject(manifestPath); + + // const functionalUnitStub = file.initialize.plugins.sci['global-config']['functional-unit'] ?? ''; + + const info: ManifestInfo = { + start: getManifestStart(manifest), + end: getManifestEnd(manifest), + hash: GetManifestHash(manifest), + if: GetIfVersion(), + verified: await runIfCheck(manifestPath), + sci: manifest.tree.aggregated.sci ?? 0, + energy: manifest.tree.aggregated.energy ?? 0, + carbon: manifest.tree.aggregated.carbon ?? 0, + level: level, + quality: 1, // quality score not yet functional in IF, + functionalUnit: functionalUnit, + }; + console.log(info) + return info; +}; + +export const GetManifestHash = (manifest: Manifest): string => { + const manifestAsString = YAML.dump(manifest).toString(); + const manifestAsBytes: Uint8Array = ethers.toUtf8Bytes(manifestAsString); + const manifestHash = ethers.keccak256(manifestAsBytes); + return manifestHash; +}; + +export const GetIfVersion = (): string => { + return packageJson.version; +}; + +export const runIfCheck = async (manifestPath: string): Promise => { + const response = await execPromise(`npm run if-check -- -m ${manifestPath}`, { + cwd: process.env.CURRENT_DIR || process.cwd(), + }); + + if (response.stdout.includes('if-check could not verify the manifest')) { + console.log('IF-CHECK: verification was unsuccessful. Files do not match'); + return false; + } + console.log('IF-CHECK: verification was successful'); + + return true; +}; diff --git a/src/if-attest/util/ethereum-utils.ts b/src/if-attest/util/ethereum-utils.ts new file mode 100644 index 00000000..bbc2afae --- /dev/null +++ b/src/if-attest/util/ethereum-utils.ts @@ -0,0 +1,14 @@ +import { ethers, Wallet } from 'ethers'; +import * as dotenv from 'dotenv'; + +dotenv.config(); +const PRIVATE_KEY: string = process.env.ETH_PRIVATE_KEY ?? ''; +const INFURA_API_KEY: string = process.env.INFURA_API_KEY ?? ''; + +export const createSigningWallet = (): Wallet => { + const provider = new ethers.JsonRpcProvider( + `https://sepolia.infura.io/v3/${INFURA_API_KEY}` + ); + const signer = new ethers.Wallet(PRIVATE_KEY, provider); + return signer; +}; diff --git a/src/if-attest/util/offchain-attestation-utils.ts b/src/if-attest/util/offchain-attestation-utils.ts new file mode 100644 index 00000000..bf72e131 --- /dev/null +++ b/src/if-attest/util/offchain-attestation-utils.ts @@ -0,0 +1,49 @@ +import { + EAS, + SignedOffchainAttestation, +} from '@ethereum-attestation-service/eas-sdk'; +import { Wallet } from 'ethers'; + + +const UID = process.env.SCHEMA_UID ?? ''; + +export const createOffchainAttestaton = async ( + eas: EAS, + signer: Wallet, + encodedData: string +): Promise => { + const offchain = await eas.getOffchain(); + + const attestation = await offchain.signOffchainAttestation( + { + recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address + expirationTime: BigInt(0), + time: BigInt(Math.floor(Date.now() / 1000)), + revocable: true, // Be aware that if your schema is not revocable, this MUST be false + schema: UID, + refUID: + '0x0000000000000000000000000000000000000000000000000000000000000000', + data: encodedData, + }, + signer, + { + verifyOnchain: false, + } + ); + return attestation; +}; + +export const addSignerInfoToAttestation = ( + attestation: SignedOffchainAttestation, + signer: Wallet +): string => { + const prefix = '{"sig":'; + const suffix = `, "signer":${JSON.stringify(signer.address)}}`; + return ( + prefix + + JSON.stringify(attestation, (_, v) => + typeof v === 'bigint' ? v.toString() : v + ) + + suffix + ); +}; diff --git a/src/if-attest/util/register-eas-schema.ts b/src/if-attest/util/register-schema.ts similarity index 96% rename from src/if-attest/util/register-eas-schema.ts rename to src/if-attest/util/register-schema.ts index e8fc8877..d31c9646 100644 --- a/src/if-attest/util/register-eas-schema.ts +++ b/src/if-attest/util/register-schema.ts @@ -1,7 +1,7 @@ import {SchemaRegistry} from '@ethereum-attestation-service/eas-sdk'; import {ethers} from 'ethers'; import * as dotenv from 'dotenv'; -import {SCHEMA} from '../util/schema'; +import {SCHEMA} from './schema'; dotenv.config(); From 0823ef09f46359ada95367e45d64d1dc62d3c98a Mon Sep 17 00:00:00 2001 From: jmc <33655003+jmcook1186@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:08:48 +0100 Subject: [PATCH 2/2] feat(package): update package json and lockfile, lint --- package-lock.json | 628 ++++++++++++------ package.json | 2 +- src/if-attest/README.md | 4 +- src/if-attest/config/config.ts | 86 ++- src/if-attest/index.ts | 22 +- src/if-attest/types/process-args.ts | 8 +- src/if-attest/util/attestation-utils.ts | 173 +++-- src/if-attest/util/ethereum-utils.ts | 12 +- .../util/offchain-attestation-utils.ts | 71 +- 9 files changed, 622 insertions(+), 384 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2956c962..b8c49f3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@commitlint/cli": "^18.6.0", "@commitlint/config-conventional": "^18.6.0", - "@ethereum-attestation-service/eas-sdk": "^2.3.0", + "@ethereum-attestation-service/eas-sdk": "^2.6.1", "@grnsft/if-core": "^0.0.25", "axios": "^1.7.2", "csv-parse": "^5.5.6", @@ -1194,32 +1194,33 @@ } }, "node_modules/@ethereum-attestation-service/eas-contracts": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@ethereum-attestation-service/eas-contracts/-/eas-contracts-1.4.1.tgz", - "integrity": "sha512-c+yaTMrEjOESG3yFztPQnNCGARZOBde6r7RnH4hK/T7BS84rC0Y0BbUv/4tOwGBAhN9ke8MJ7G/qySngVtJk3w==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@ethereum-attestation-service/eas-contracts/-/eas-contracts-1.7.1.tgz", + "integrity": "sha512-z2MeCrkp4JrtOMBHQt5fcdbxryC+xxofoPzzv3wcx5GbfG27PpkXRKxlSlb1l2jIT1YfDc701rixbP6vHaEN3Q==", "dependencies": { - "hardhat": "2.22.1" + "hardhat": "2.22.4" } }, "node_modules/@ethereum-attestation-service/eas-sdk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ethereum-attestation-service/eas-sdk/-/eas-sdk-2.3.0.tgz", - "integrity": "sha512-hZBkkOFKg71mNAI9ZVSTLjV29MRxFO+L/v/omYyOHXXY3U5GHdVnhOJNgkX16zlmpxxprYgesrDwQL/kXurP0g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@ethereum-attestation-service/eas-sdk/-/eas-sdk-2.7.0.tgz", + "integrity": "sha512-JpbUty2ab+FK5AZdoNhH/yCAUfruC2J6sxIhOaF923qip4ibs3M8XwFRr8R67xWEzcML7WKn8rFz0icJiJnxUA==", "dependencies": { - "@ethereum-attestation-service/eas-contracts": "1.4.1", - "@openzeppelin/merkle-tree": "^1.0.6", - "ethers": "^6.11.1", + "@ethereum-attestation-service/eas-contracts": "1.7.1", + "@openzeppelin/merkle-tree": "^1.0.7", + "ethers": "^6.13.2", "js-base64": "^3.7.7", "lodash": "^4.17.21", "multiformats": "9.9.0", "pako": "^2.1.0", - "semver": "^7.6.0" + "semver": "^7.6.3", + "viem": "^2.19.2" } }, "node_modules/@ethereum-attestation-service/eas-sdk/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -2706,12 +2707,14 @@ } }, "node_modules/@openzeppelin/merkle-tree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@openzeppelin/merkle-tree/-/merkle-tree-1.0.6.tgz", - "integrity": "sha512-cGWOb2WBWbJhqvupzxjnKAwGLxxAEYPg51sk76yZ5nVe5D03mw7Vx5yo8llaIEqYhP5O39M8QlrNWclgLfKVrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@openzeppelin/merkle-tree/-/merkle-tree-1.0.7.tgz", + "integrity": "sha512-i93t0YYv6ZxTCYU3CdO5Q+DXK0JH10A4dCBOMlzYbX+ujTXm+k1lXiEyVqmf94t3sqmv8sm/XT5zTa0+efnPgQ==", "dependencies": { "@ethersproject/abi": "^5.7.0", - "ethereum-cryptography": "^1.1.2" + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0" } }, "node_modules/@pkgjs/parseargs": { @@ -2790,9 +2793,9 @@ } }, "node_modules/@scure/base": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.7.tgz", - "integrity": "sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", "funding": { "url": "https://paulmillr.com/funding/" } @@ -3035,9 +3038,9 @@ } }, "node_modules/@types/bn.js": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", - "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", + "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", "dependencies": { "@types/node": "*" } @@ -3366,6 +3369,26 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/abitype": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.6.tgz", + "integrity": "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.22.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/acorn": { "version": "8.11.2", "dev": true, @@ -3668,9 +3691,9 @@ } }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -3776,9 +3799,9 @@ "license": "MIT" }, "node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", "dependencies": { "safe-buffer": "^5.0.1" } @@ -4424,9 +4447,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -4436,15 +4459,15 @@ } }, "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -4683,12 +4706,12 @@ } }, "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/compare-func": { @@ -5045,10 +5068,11 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "license": "MIT", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -5406,9 +5430,9 @@ } }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "engines": { "node": ">=0.3.1" } @@ -5535,6 +5559,18 @@ "node": ">=6" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.2", "license": "MIT", @@ -6131,9 +6167,9 @@ } }, "node_modules/ethers": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.1.tgz", - "integrity": "sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A==", + "version": "6.13.4", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.4.tgz", + "integrity": "sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA==", "funding": [ { "type": "individual", @@ -6148,9 +6184,9 @@ "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", - "@types/node": "18.15.13", + "@types/node": "22.7.5", "aes-js": "4.0.0-beta.5", - "tslib": "2.4.0", + "tslib": "2.7.0", "ws": "8.17.1" }, "engines": { @@ -6169,14 +6205,22 @@ } }, "node_modules/ethers/node_modules/@types/node": { - "version": "18.15.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", - "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "dependencies": { + "undici-types": "~6.19.2" + } }, "node_modules/ethers/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" + }, + "node_modules/ethers/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "node_modules/ethjs-util": { "version": "0.1.6", @@ -6663,9 +6707,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", - "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "dev": true, "engines": { "node": ">=18" @@ -7036,13 +7080,13 @@ } }, "node_modules/hardhat": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.1.tgz", - "integrity": "sha512-cTWYIJc5jQ132XUI8oRI/TO9L6oavPoJRCTRU9sIjkVxvkxz0Axz0K83Z3BEdJTqBQ2W84ZRoTekti84kBwCjg==", + "version": "2.22.4", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.4.tgz", + "integrity": "sha512-09qcXJFBHQUaraJkYNr7XlmwjOj27xBB0SL2rYS024hTj9tPMbp26AFjlf5quBMO9SR4AJFg+4qWahcYcvXBuQ==", "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.3.1", + "@nomicfoundation/edr": "^0.3.7", "@nomicfoundation/ethereumjs-common": "4.0.4", "@nomicfoundation/ethereumjs-tx": "5.0.4", "@nomicfoundation/ethereumjs-util": "9.0.4", @@ -7657,9 +7701,9 @@ } }, "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==" + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -8382,6 +8426,20 @@ "version": "2.0.0", "license": "ISC" }, + "node_modules/isows": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", + "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "peerDependencies": { + "ws": "*" + } + }, "node_modules/issue-parser": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", @@ -9686,12 +9744,15 @@ } }, "node_modules/lilconfig": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", - "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "dev": true, "engines": { "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { @@ -9699,21 +9760,21 @@ "license": "MIT" }, "node_modules/lint-staged": { - "version": "15.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", - "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", - "dev": true, - "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "3.0.0", - "listr2": "8.0.1", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.4" + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", + "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.6", + "execa": "~8.0.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", + "micromatch": "~4.0.8", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.5.0" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -9872,16 +9933,16 @@ } }, "node_modules/listr2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", - "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", - "rfdc": "^1.3.0", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, "engines": { @@ -9889,9 +9950,9 @@ } }, "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -9913,15 +9974,15 @@ } }, "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/listr2/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -10088,14 +10149,14 @@ } }, "node_modules/log-update": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", - "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "dependencies": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" }, @@ -10107,21 +10168,24 @@ } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, + "dependencies": { + "environment": "^1.0.0" + }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -10143,24 +10207,24 @@ } }, "node_modules/log-update/node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { @@ -10178,22 +10242,49 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/log-update/node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", @@ -10211,9 +10302,9 @@ } }, "node_modules/log-update/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -10431,11 +10522,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -10468,6 +10560,18 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", @@ -10544,30 +10648,30 @@ } }, "node_modules/mocha": { - "version": "10.5.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.5.2.tgz", - "integrity": "sha512-9btlN3JKCefPf+vKd/kcKz2SXxi12z6JswkGfaAF0saQvnsqLJk504ZmbxhSoENge08E9dsymozKgFMTl5PQsA==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", "chokidar": "^3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -10577,14 +10681,6 @@ "node": ">= 14.0.0" } }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "engines": { - "node": ">=6" - } - }, "node_modules/mocha/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -10689,9 +10785,9 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10699,11 +10795,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/mocha/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -10750,16 +10841,17 @@ } }, "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "engines": { "node": ">=10" } }, "node_modules/ms": { - "version": "2.1.2", - "license": "MIT" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/multiformats": { "version": "9.9.0", @@ -10868,9 +10960,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", - "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -12468,9 +12560,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, "node_modules/rimraf": { @@ -12726,9 +12818,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dependencies": { "randombytes": "^2.1.0" } @@ -13915,6 +14007,111 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/viem": { + "version": "2.21.27", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.21.27.tgz", + "integrity": "sha512-lBpldSmwmKZ8jIiVLqoplPnuMs2Cza8tK0/G9m+ZjqfbgEp4+BPviFBJWCDNFxSp8H3gPzAuqj8o1WKQyq3wlg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.11.0", + "@noble/curves": "1.6.0", + "@noble/hashes": "1.5.0", + "@scure/bip32": "1.5.0", + "@scure/bip39": "1.4.0", + "abitype": "1.0.6", + "isows": "1.0.6", + "webauthn-p256": "0.0.10", + "ws": "8.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/@adraffy/ens-normalize": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz", + "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==" + }, + "node_modules/viem/node_modules/@noble/curves": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", + "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "dependencies": { + "@noble/hashes": "1.5.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip32": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.5.0.tgz", + "integrity": "sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw==", + "dependencies": { + "@noble/curves": "~1.6.0", + "@noble/hashes": "~1.5.0", + "@scure/base": "~1.1.7" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip39": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.4.0.tgz", + "integrity": "sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==", + "dependencies": { + "@noble/hashes": "~1.5.0", + "@scure/base": "~1.1.8" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/walker": { "version": "1.0.8", "dev": true, @@ -13941,6 +14138,46 @@ "node": ">= 8" } }, + "node_modules/webauthn-p256": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/webauthn-p256/-/webauthn-p256-0.0.10.tgz", + "integrity": "sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "dependencies": { + "@noble/curves": "^1.4.0", + "@noble/hashes": "^1.4.0" + } + }, + "node_modules/webauthn-p256/node_modules/@noble/curves": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", + "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "dependencies": { + "@noble/hashes": "1.5.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/webauthn-p256/node_modules/@noble/hashes": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -14137,9 +14374,9 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==" }, "node_modules/wrap-ansi": { "version": "7.0.0", @@ -14234,10 +14471,13 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", "dev": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } diff --git a/package.json b/package.json index 1e726adc..9e276997 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "@commitlint/cli": "^18.6.0", "@commitlint/config-conventional": "^18.6.0", - "@ethereum-attestation-service/eas-sdk": "^2.3.0", + "@ethereum-attestation-service/eas-sdk": "^2.6.1", "@grnsft/if-core": "^0.0.25", "axios": "^1.7.2", "csv-parse": "^5.5.6", diff --git a/src/if-attest/README.md b/src/if-attest/README.md index a98f9ed0..3facf008 100644 --- a/src/if-attest/README.md +++ b/src/if-attest/README.md @@ -151,11 +151,11 @@ SCHEMA_UID: '0x9f074eced91e2c6952fdf5734ec1d8cc05e1e1d07eaa442f07746b7d8a422c0e' For an onchain attestation ``` -npm run if-attest -- -manifest ./manifests/outputs/example.yaml --blockchain true +npm run if-attest -- -manifest ./manifests/outputs/example.yaml --blockchain true --level 3 --unit site-visits ``` For an offchain attestation ``` -npm run if-attest -- --manifest ./manifests/outputs/example.yaml --blockchain false +npm run if-attest -- --manifest ./manifests/outputs/example.yaml --blockchain false --level 3 --unit site-visits ``` diff --git a/src/if-attest/config/config.ts b/src/if-attest/config/config.ts index 9e62dbc9..fd569586 100644 --- a/src/if-attest/config/config.ts +++ b/src/if-attest/config/config.ts @@ -1,51 +1,49 @@ -import { ArgumentConfig, ParseOptions } from 'ts-command-line-args'; -import { STRINGS as COMMON_STRINGS } from '../../common/config'; -import { IFAttestArgs } from '../types/process-args'; +import {ArgumentConfig, ParseOptions} from 'ts-command-line-args'; +import {STRINGS as COMMON_STRINGS} from '../../common/config'; +import {IFAttestArgs} from '../types/process-args'; -const { DISCLAIMER_MESSAGE } = COMMON_STRINGS; +const {DISCLAIMER_MESSAGE} = COMMON_STRINGS; export const CONFIG = { - ARGS: { - manifest: { - type: String, - optional: false, - alias: 'm', - description: '[path to the manifest file]', - }, - blockchain: { - type: Boolean, - optional: true, - alias: 'b', - description: - '[Boolean to toggle posting attestation to blockchain (true to post, false to save locally)]', - }, - level: { - type: Number, - optional: true, - alias: 'l', - description: - '[Audit level being attested to - integers from 1-5]', - }, - unit: { - type: String, - optional: true, - alias: 'u', - description: - '[The functional unit used to calculate SCI]', - }, - } as ArgumentConfig, - HELP: { - helpArg: 'help', - headerContentSections: [ - { header: 'Impact Framework', content: 'IF-Attest Helpful keywords:' }, - ], - footerContentSections: [ - { header: 'Green Software Foundation', content: DISCLAIMER_MESSAGE }, - ], - } as ParseOptions, + ARGS: { + manifest: { + type: String, + optional: false, + alias: 'm', + description: '[path to the manifest file]', + }, + blockchain: { + type: Boolean, + optional: true, + alias: 'b', + description: + '[Boolean to toggle posting attestation to blockchain (true to post, false to save locally)]', + }, + level: { + type: Number, + optional: true, + alias: 'l', + description: '[Audit level being attested to - integers from 1-5]', + }, + unit: { + type: String, + optional: true, + alias: 'u', + description: '[The functional unit used to calculate SCI]', + }, + } as ArgumentConfig, + HELP: { + helpArg: 'help', + headerContentSections: [ + {header: 'Impact Framework', content: 'IF-Attest Helpful keywords:'}, + ], + footerContentSections: [ + {header: 'Green Software Foundation', content: DISCLAIMER_MESSAGE}, + ], + } as ParseOptions, }; export const STRINGS = { - MANIFEST_IS_NOT_YAML: (path: string) => - `The \`${path}\` is not in yaml format.`, + MANIFEST_IS_NOT_YAML: (path: string) => + `The \`${path}\` is not in yaml format.`, }; diff --git a/src/if-attest/index.ts b/src/if-attest/index.ts index c1962f53..2cfb1b06 100644 --- a/src/if-attest/index.ts +++ b/src/if-attest/index.ts @@ -1,14 +1,19 @@ #!/usr/bin/env node /* eslint-disable no-process-exit */ -import { - EAS, -} from '@ethereum-attestation-service/eas-sdk'; -import { logger } from '../common/util/logger'; -import { parseIfAttestArgs } from './util/args'; +import {EAS} from '@ethereum-attestation-service/eas-sdk'; +import {logger} from '../common/util/logger'; +import {parseIfAttestArgs} from './util/args'; import * as fs from 'fs'; import {createSigningWallet} from './util/ethereum-utils'; -import {addSignerInfoToAttestation, createOffchainAttestaton} from './util/offchain-attestation-utils'; -import {sendAttestationTx, encodeSchema, getManifestInfo } from './util/attestation-utils'; +import { + addSignerInfoToAttestation, + createOffchainAttestaton, +} from './util/offchain-attestation-utils'; +import { + sendAttestationTx, + encodeSchema, + getManifestInfo, +} from './util/attestation-utils'; const EAS_CONTRACT_ADDRESS_SEPOLIA: string = process.env.EAS_CONTRACT_ADDRESS_SEPOLIA ?? ''; @@ -26,7 +31,7 @@ const IfAttest = async () => { const signer = createSigningWallet(); const eas = new EAS(EAS_CONTRACT_ADDRESS_SEPOLIA); - console.debug('creating signer object') + console.debug('creating signer object'); eas.connect(signer); const manifestInfo = await getManifestInfo( @@ -61,7 +66,6 @@ const IfAttest = async () => { } }; - IfAttest().catch(error => { if (error instanceof Error) { logger.error(error); diff --git a/src/if-attest/types/process-args.ts b/src/if-attest/types/process-args.ts index be915a97..f12d0989 100644 --- a/src/if-attest/types/process-args.ts +++ b/src/if-attest/types/process-args.ts @@ -1,6 +1,6 @@ export interface IFAttestArgs { - manifest: string; - blockchain?: boolean; - level: number; - unit: string; + manifest: string; + blockchain?: boolean; + level: number; + unit: string; } diff --git a/src/if-attest/util/attestation-utils.ts b/src/if-attest/util/attestation-utils.ts index 67932dfb..bc52ebac 100644 --- a/src/if-attest/util/attestation-utils.ts +++ b/src/if-attest/util/attestation-utils.ts @@ -1,122 +1,119 @@ -import { ManifestInfo } from '../types/types'; +import {ManifestInfo} from '../types/types'; import * as YAML from 'js-yaml'; -import { - EAS, - SchemaEncoder, -} from '@ethereum-attestation-service/eas-sdk'; -import { execPromise } from '../../common/util/helpers'; -import { openYamlFileAsObject } from '../../common/util/yaml'; -import { Manifest } from '../../common/types/manifest'; -import { SCHEMA } from '../util/schema'; -import { ethers, Wallet } from 'ethers'; +import {EAS, SchemaEncoder} from '@ethereum-attestation-service/eas-sdk'; +import {execPromise} from '../../common/util/helpers'; +import {openYamlFileAsObject} from '../../common/util/yaml'; +import {Manifest} from '../../common/types/manifest'; +import {SCHEMA} from '../util/schema'; +import {ethers, Wallet} from 'ethers'; const packageJson = require('../../../package.json'); const UID = process.env.SCHEMA_UID ?? ''; export const sendAttestationTx = async ( - eas: EAS, - signer: Wallet, - encodedData: string + eas: EAS, + signer: Wallet, + encodedData: string ): Promise => { - const tx = await eas.attest({ - schema: UID, - data: { - recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address - expirationTime: BigInt(0), - revocable: true, // Be aware that if your schema is not revocable, this MUST be false - data: encodedData, - }, - }); - const attestationUID = await tx.wait(); - return attestationUID; + const tx = await eas.attest({ + schema: UID, + data: { + recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address + expirationTime: BigInt(0), + revocable: true, // Be aware that if your schema is not revocable, this MUST be false + data: encodedData, + }, + }); + const attestationUID = await tx.wait(); + return attestationUID; }; export const encodeSchema = (manifestInfo: ManifestInfo) => { - const schemaEncoder = new SchemaEncoder(SCHEMA); - const encodedData = schemaEncoder.encodeData([ - { name: 'start', value: manifestInfo.start, type: 'string' }, - { name: 'end', value: manifestInfo.end, type: 'string' }, - { name: 'hash', value: manifestInfo.hash, type: 'bytes32' }, - { name: 'if', value: manifestInfo.if, type: 'string' }, - { name: 'verified', value: manifestInfo.verified, type: 'bool' }, - { name: 'sci', value: manifestInfo.sci, type: 'uint64' }, - { name: 'energy', value: manifestInfo.energy, type: 'uint64' }, - { name: 'carbon', value: manifestInfo.carbon, type: 'uint64' }, - { name: 'level', value: manifestInfo.level, type: 'uint8' }, - { name: 'quality', value: manifestInfo.quality, type: 'uint8' }, - { - name: 'functionalUnit', - value: manifestInfo.functionalUnit, - type: 'string', - }, - ]); - return encodedData; + const schemaEncoder = new SchemaEncoder(SCHEMA); + const encodedData = schemaEncoder.encodeData([ + {name: 'start', value: manifestInfo.start, type: 'string'}, + {name: 'end', value: manifestInfo.end, type: 'string'}, + {name: 'hash', value: manifestInfo.hash, type: 'bytes32'}, + {name: 'if', value: manifestInfo.if, type: 'string'}, + {name: 'verified', value: manifestInfo.verified, type: 'bool'}, + {name: 'sci', value: manifestInfo.sci, type: 'uint64'}, + {name: 'energy', value: manifestInfo.energy, type: 'uint64'}, + {name: 'carbon', value: manifestInfo.carbon, type: 'uint64'}, + {name: 'level', value: manifestInfo.level, type: 'uint8'}, + {name: 'quality', value: manifestInfo.quality, type: 'uint8'}, + { + name: 'functionalUnit', + value: manifestInfo.functionalUnit, + type: 'string', + }, + ]); + return encodedData; }; export const getManifestStart = (manifest: Manifest): string => { - const firstChildName = Object.keys(manifest.tree.children)[0] ?? 0; - const manifestStart = - manifest.tree.children[`${firstChildName}`].inputs[0].timestamp ?? 0; - return manifestStart; + const firstChildName = Object.keys(manifest.tree.children)[0] ?? 0; + const manifestStart = + manifest.tree.children[`${firstChildName}`].inputs[0].timestamp ?? 0; + return manifestStart; }; export const getManifestEnd = (manifest: Manifest): string => { - const firstChildName = Object.keys(manifest.tree.children)[0]; - const inputsLength = - manifest.tree.children[`${firstChildName}`].inputs.length ?? ''; - const manifestEnd = - manifest.tree.children[`${firstChildName}`].inputs[inputsLength - 1] - .timestamp ?? ''; - return manifestEnd; + const firstChildName = Object.keys(manifest.tree.children)[0]; + const inputsLength = + manifest.tree.children[`${firstChildName}`].inputs.length ?? ''; + const manifestEnd = + manifest.tree.children[`${firstChildName}`].inputs[inputsLength - 1] + .timestamp ?? ''; + return manifestEnd; }; export const getManifestInfo = async ( - manifestPath: string, - level: number, - functionalUnit: string + manifestPath: string, + level: number, + functionalUnit: string ): Promise => { - const manifest = await openYamlFileAsObject(manifestPath); + const manifest = await openYamlFileAsObject(manifestPath); - // const functionalUnitStub = file.initialize.plugins.sci['global-config']['functional-unit'] ?? ''; + // const functionalUnitStub = file.initialize.plugins.sci['global-config']['functional-unit'] ?? ''; - const info: ManifestInfo = { - start: getManifestStart(manifest), - end: getManifestEnd(manifest), - hash: GetManifestHash(manifest), - if: GetIfVersion(), - verified: await runIfCheck(manifestPath), - sci: manifest.tree.aggregated.sci ?? 0, - energy: manifest.tree.aggregated.energy ?? 0, - carbon: manifest.tree.aggregated.carbon ?? 0, - level: level, - quality: 1, // quality score not yet functional in IF, - functionalUnit: functionalUnit, - }; - console.log(info) - return info; + const info: ManifestInfo = { + start: getManifestStart(manifest), + end: getManifestEnd(manifest), + hash: GetManifestHash(manifest), + if: GetIfVersion(), + verified: await runIfCheck(manifestPath), + sci: manifest.tree.aggregated.sci ?? 0, + energy: manifest.tree.aggregated.energy ?? 0, + carbon: manifest.tree.aggregated.carbon ?? 0, + level: level, + quality: 1, // quality score not yet functional in IF, + functionalUnit: functionalUnit, + }; + console.log(info); + return info; }; export const GetManifestHash = (manifest: Manifest): string => { - const manifestAsString = YAML.dump(manifest).toString(); - const manifestAsBytes: Uint8Array = ethers.toUtf8Bytes(manifestAsString); - const manifestHash = ethers.keccak256(manifestAsBytes); - return manifestHash; + const manifestAsString = YAML.dump(manifest).toString(); + const manifestAsBytes: Uint8Array = ethers.toUtf8Bytes(manifestAsString); + const manifestHash = ethers.keccak256(manifestAsBytes); + return manifestHash; }; export const GetIfVersion = (): string => { - return packageJson.version; + return packageJson.version; }; export const runIfCheck = async (manifestPath: string): Promise => { - const response = await execPromise(`npm run if-check -- -m ${manifestPath}`, { - cwd: process.env.CURRENT_DIR || process.cwd(), - }); + const response = await execPromise(`npm run if-check -- -m ${manifestPath}`, { + cwd: process.env.CURRENT_DIR || process.cwd(), + }); - if (response.stdout.includes('if-check could not verify the manifest')) { - console.log('IF-CHECK: verification was unsuccessful. Files do not match'); - return false; - } - console.log('IF-CHECK: verification was successful'); + if (response.stdout.includes('if-check could not verify the manifest')) { + console.log('IF-CHECK: verification was unsuccessful. Files do not match'); + return false; + } + console.log('IF-CHECK: verification was successful'); - return true; + return true; }; diff --git a/src/if-attest/util/ethereum-utils.ts b/src/if-attest/util/ethereum-utils.ts index bbc2afae..f17a74d9 100644 --- a/src/if-attest/util/ethereum-utils.ts +++ b/src/if-attest/util/ethereum-utils.ts @@ -1,4 +1,4 @@ -import { ethers, Wallet } from 'ethers'; +import {ethers, Wallet} from 'ethers'; import * as dotenv from 'dotenv'; dotenv.config(); @@ -6,9 +6,9 @@ const PRIVATE_KEY: string = process.env.ETH_PRIVATE_KEY ?? ''; const INFURA_API_KEY: string = process.env.INFURA_API_KEY ?? ''; export const createSigningWallet = (): Wallet => { - const provider = new ethers.JsonRpcProvider( - `https://sepolia.infura.io/v3/${INFURA_API_KEY}` - ); - const signer = new ethers.Wallet(PRIVATE_KEY, provider); - return signer; + const provider = new ethers.JsonRpcProvider( + `https://sepolia.infura.io/v3/${INFURA_API_KEY}` + ); + const signer = new ethers.Wallet(PRIVATE_KEY, provider); + return signer; }; diff --git a/src/if-attest/util/offchain-attestation-utils.ts b/src/if-attest/util/offchain-attestation-utils.ts index bf72e131..4ac9e89a 100644 --- a/src/if-attest/util/offchain-attestation-utils.ts +++ b/src/if-attest/util/offchain-attestation-utils.ts @@ -1,49 +1,48 @@ import { - EAS, - SignedOffchainAttestation, + EAS, + SignedOffchainAttestation, } from '@ethereum-attestation-service/eas-sdk'; -import { Wallet } from 'ethers'; - +import {Wallet} from 'ethers'; const UID = process.env.SCHEMA_UID ?? ''; export const createOffchainAttestaton = async ( - eas: EAS, - signer: Wallet, - encodedData: string + eas: EAS, + signer: Wallet, + encodedData: string ): Promise => { - const offchain = await eas.getOffchain(); + const offchain = await eas.getOffchain(); - const attestation = await offchain.signOffchainAttestation( - { - recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address - expirationTime: BigInt(0), - time: BigInt(Math.floor(Date.now() / 1000)), - revocable: true, // Be aware that if your schema is not revocable, this MUST be false - schema: UID, - refUID: - '0x0000000000000000000000000000000000000000000000000000000000000000', - data: encodedData, - }, - signer, - { - verifyOnchain: false, - } - ); - return attestation; + const attestation = await offchain.signOffchainAttestation( + { + recipient: signer.address, //can provide an ethereum address for the attested org if needed- here it's the signer address + expirationTime: BigInt(0), + time: BigInt(Math.floor(Date.now() / 1000)), + revocable: true, // Be aware that if your schema is not revocable, this MUST be false + schema: UID, + refUID: + '0x0000000000000000000000000000000000000000000000000000000000000000', + data: encodedData, + }, + signer, + { + verifyOnchain: false, + } + ); + return attestation; }; export const addSignerInfoToAttestation = ( - attestation: SignedOffchainAttestation, - signer: Wallet + attestation: SignedOffchainAttestation, + signer: Wallet ): string => { - const prefix = '{"sig":'; - const suffix = `, "signer":${JSON.stringify(signer.address)}}`; - return ( - prefix + - JSON.stringify(attestation, (_, v) => - typeof v === 'bigint' ? v.toString() : v - ) + - suffix - ); + const prefix = '{"sig":'; + const suffix = `, "signer":${JSON.stringify(signer.address)}}`; + return ( + prefix + + JSON.stringify(attestation, (_, v) => + typeof v === 'bigint' ? v.toString() : v + ) + + suffix + ); };