diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 38a4d36e6..23daf960d 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -41,6 +41,7 @@ "type": "module", "types": "dist/index.d.ts", "dependencies": { + "@farcaster/hub-nodejs": "^0.11.16", "@snickerdoodlelabs/common-utils": "workspace:^", "@snickerdoodlelabs/node-utils": "workspace:^", "@snickerdoodlelabs/objects": "workspace:^", diff --git a/packages/contracts-sdk/src/debug/constants.ts b/packages/contracts-sdk/src/debug/constants.ts index 0991fb6bc..5f31f7204 100644 --- a/packages/contracts-sdk/src/debug/constants.ts +++ b/packages/contracts-sdk/src/debug/constants.ts @@ -7,8 +7,10 @@ import { import { ethers } from "ethers"; // #region export constants -export const chainId = ChainId(31337); -export const providerUrl = URLString("http://localhost:8545"); +export const chainId = ChainId(10); +export const providerUrl = URLString( + "https://optimism-mainnet.infura.io/v3/a6271a49218848a7ad939ee62d225914", +); // This is the private key of the account that A. deployed the contracts and B. has all the token // #0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 diff --git a/packages/contracts-sdk/src/debug/debugger.ts b/packages/contracts-sdk/src/debug/debugger.ts index ef7944bff..7e3f4df00 100644 --- a/packages/contracts-sdk/src/debug/debugger.ts +++ b/packages/contracts-sdk/src/debug/debugger.ts @@ -1,4 +1,19 @@ import "reflect-metadata"; +import { + ID_GATEWAY_ADDRESS, + ID_REGISTRY_ADDRESS, + ViemLocalEip712Signer, + idGatewayABI, + idRegistryABI, + NobleEd25519Signer, + KEY_GATEWAY_ADDRESS, + keyGatewayABI, + ID_GATEWAY_EIP_712_TYPES, + BUNDLER_ADDRESS, + bundlerABI, + SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_TYPES, + KEY_GATEWAY_EIP_712_TYPES, +} from "@farcaster/hub-nodejs"; import { CryptoUtils } from "@snickerdoodlelabs/node-utils"; import { BaseURI, @@ -9,9 +24,12 @@ import { EVMAccountAddress, EVMContractAddress, MarketplaceTag, + UnknownBlockchainError, } from "@snickerdoodlelabs/objects"; -import { ethers } from "ethers"; +import { ethers, ParamType, TypedDataField } from "ethers"; +import { okAsync, ResultAsync } from "neverthrow"; import { ResultUtils } from "neverthrow-result-utils"; +import { fromString, toString } from "uint8arrays"; import { consentAddress, @@ -441,16 +459,516 @@ const getAccountBalanceForErc20 = async ( } }; +const getNativeBalance = async ( + account: EVMAccountAddress, +): Promise => { + try { + const balance = await provider.getBalance(account); + console.log("Native balance: ", balance); + return balance; + } catch (e) { + console.log("getNativeBalance e: ", e); + throw e; // Optionally rethrow the error to handle it elsewhere + } +}; + +const getIdRegistrationPrice = async (): Promise => { + try { + const contract = new ethers.Contract( + ID_GATEWAY_ADDRESS, + idGatewayABI, + provider, + ); + const args = [0n]; + const price: bigint = await contract["price(uint256)"].staticCall(...args); + console.log("Id Registration Price: ", price); + return price; + } catch (e) { + console.log("getIdRegistrationPrice e: ", e); + throw e; + } +}; + +const getBundlerRegistrationPrice = async (): Promise => { + try { + const contract = new ethers.Contract(BUNDLER_ADDRESS, bundlerABI, provider); + const args = [0n]; + const price: bigint = await contract["price(uint256)"].staticCall(...args); + console.log("Bundler Registration Price: ", price); + return price; + } catch (e) { + console.log("getBundlerRegistrationPrice e: ", e); + throw e; + } +}; + +// make sure to check if appSigner: +// - has enough balance +// - doesn't already have fid +const registerApp = async ( + appSigner: ethers.Wallet, + recoveryAddress: EVMAccountAddress, +) => { + try { + const contract = new ethers.Contract( + ID_GATEWAY_ADDRESS, + idGatewayABI, + appSigner, + ); + const args = [recoveryAddress, 0n]; + // can do more to customize fees and other if you want + const idRegistrationPrice = await getIdRegistrationPrice(); + const tx = await contract["register(address,uint256)"](...args, { + value: idRegistrationPrice, + }); + console.log("tx: ", tx); + const receipt = await tx.wait(); + console.log("receipt: ", receipt); + return receipt; + } catch (e) { + console.log("getAppFid e: ", e); + throw e; + } +}; + +const addKey = async ( + newKeySigner: ethers.Wallet, + newKey: EVMAccountAddress, + deadline: bigint, +) => { + try { + const contract = new ethers.Contract( + KEY_GATEWAY_ADDRESS, + keyGatewayABI, + newKeySigner, + ); + const encodedMetadataStruct = await signKeyRegisterEncodedMetadataCall( + newKeySigner, + newKey, + deadline, + ); + const args = [1, newKey, 1, encodedMetadataStruct]; + // can do more to customize fees and other if you want + const tx = await contract["add"].staticCall(...args); + console.log("tx: ", tx); + const receipt = await tx.wait(); + console.log("receipt: ", receipt); + return receipt; + } catch (e) { + console.log("addKey e: ", e); + throw e; + } +}; + +// getting 0n means the app is not registered +const getAppFid = async ( + appAddress: EVMAccountAddress | EVMContractAddress, +): Promise => { + try { + const contract = new ethers.Contract( + ID_REGISTRY_ADDRESS, + idRegistryABI, + provider, + ); + const args = [appAddress]; + const fid: bigint = await contract["idOf"].staticCall(...args); + console.log("app fid: ", fid); + return fid; + } catch (e) { + console.log("getAppFid e: ", e); + throw e; + } +}; + +const getKeyGatewayNonce = async ( + address: EVMAccountAddress | EVMContractAddress, +): Promise => { + try { + const contract = new ethers.Contract( + KEY_GATEWAY_ADDRESS, + keyGatewayABI, + provider, + ); + const args = [address]; + const keyGatewayNonce: bigint = await contract["nonces"].staticCall( + ...args, + ); + console.log("keyGateway nonce: ", keyGatewayNonce); + return keyGatewayNonce; + } catch (e) { + console.log("getKeyGatewayNonce e: ", e); + throw e; + } +}; + +const HOUR_DEADLINE = BigInt(Math.floor(Date.now() / 1000) + 3600); // set the signatures' deadline to 1 hour from now + +function removeReadonlyFromReadonlyTypes( + obj: T, +): Record { + return obj as Record; +} + +// allows Alice to delegate the creation of her id registration +const signIdRegisterCall = async ( + signer: ethers.Wallet, // the user wallet signer + recoveryAddress: EVMAccountAddress | EVMContractAddress, + deadline: bigint, +): Promise => { + try { + const nonce = await getKeyGatewayNonce(EVMAccountAddress(signer.address)); + // message should be RegistrationParams struct + // https://docs.farcaster.xyz/reference/contracts/reference/id-gateway#register-signature + // Needs to be a EIP712 signature + const message = { + to: signer.address, + recovery: recoveryAddress, + nonce: nonce, + deadline: deadline, + }; + // const bytesMessage: Uint8Array = new TextEncoder().encode( + // JSON.stringify(message), + // ); + const signedMessage = await signer.signTypedData( + ID_GATEWAY_EIP_712_TYPES.domain, + removeReadonlyFromReadonlyTypes(ID_GATEWAY_EIP_712_TYPES.types), + message, + ); + console.log("signedIdRegistrationMessage: ", signedMessage); + return signedMessage; + } catch (e) { + console.log("signIdRegisterCall e: ", e); + throw e; + } +}; + +// creates metadata for alice to delegate the creation of her key registration +const signKeyRegisterEncodedMetadataCall = async ( + appSigner: ethers.Wallet, // the app that will register a key on behalf of the user + keyToAdd: EVMAccountAddress, // key to be tied to account + deadline: bigint, +): Promise => { + // TODO HexString with prefix + try { + const appFid = await getAppFid(EVMAccountAddress(appSigner.address)); + if (appFid === 0n) { + throw new UnknownBlockchainError("App is not registered"); + } + // https://docs.farcaster.xyz/reference/contracts/reference/signed-key-request-validator#signedkeyrequestmetadata-struct + // Needs to be a EIP712 signature + const metadataMessage = { + requestFid: appFid, + key: keyToAdd, + deadline, + }; + const metadataSignature = await appSigner.signTypedData( + SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_TYPES.domain, + removeReadonlyFromReadonlyTypes( + SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_TYPES.types, + ), + metadataMessage, + ); + const metadataStruct = { + requestFid: appFid, + requestSigner: keyToAdd, + signature: metadataSignature, + deadline: deadline, + }; + // function similar to https://github.com/farcasterxyz/hub-monorepo/blob/27a1cfc84a19bf20120567abc806d158374cea15/packages/core/src/signers/viemLocalEip712Signer.ts#L134 + const metadataStructType = ParamType.from({ + components: [ + { + name: "requestFid", + type: "uint256", + }, + { + name: "requestSigner", + type: "address", + }, + { + name: "signature", + type: "bytes", + }, + { + name: "deadline", + type: "uint256", + }, + ], + name: "SignedKeyRequestMetadata", + type: "tuple", + }); + console.log("metadataStruct: ", metadataStruct); + + const encodedMetadataStruct = ethers.AbiCoder.defaultAbiCoder().encode( + [metadataStructType], + [metadataStruct], + ); + console.log("signKeyRegisterEncodedMetadataCall: ", encodedMetadataStruct); + return encodedMetadataStruct; + } catch (e) { + console.log("signKeyRegisterEncodedMetadataCall e: ", e); + throw e; + } +}; + +interface AddKeySingedMetadata { + encodedMetadataStruct: string; + signature: string; +} +// allows Alice to delegate the creation of her key registration +const signKeyRegisterCall = async ( + accountSigner: ethers.Wallet, // the user wallet signer / owner + keyToAdd: EVMAccountAddress, + appSigner: ethers.Wallet, // the app that will register a key on behalf of the user + deadline: bigint, +): Promise => { + try { + const appFid = await getAppFid(EVMAccountAddress(appSigner.address)); + if (appFid === 0n) { + throw new UnknownBlockchainError("App is not registered"); + } + // message should be Add Signature struct + // https://docs.farcaster.xyz/reference/contracts/reference/key-gateway#add-signature + // Signature needs to include metadata + // https://docs.farcaster.xyz/reference/contracts/reference/signed-key-request-validator#signedkeyrequestmetadata-struct + // Needs to be a EIP712 signature + const encodedMetadataStruct = await signKeyRegisterEncodedMetadataCall( + appSigner, + keyToAdd, + deadline, + ); + const nonce = await getKeyGatewayNonce(EVMAccountAddress(signer.address)); + const addKeyMessage = { + owner: accountSigner.address, + keyType: 1, + key: keyToAdd, + metadataType: 1, + metadata: encodedMetadataStruct, + nonce: nonce, + deadline: deadline, + }; + const addKeySignature = await accountSigner.signTypedData( + KEY_GATEWAY_EIP_712_TYPES.domain, + removeReadonlyFromReadonlyTypes(KEY_GATEWAY_EIP_712_TYPES.types), + addKeyMessage, + ); + console.log("signKeyRegisterCall: ", addKeySignature); + return { + encodedMetadataStruct: encodedMetadataStruct, + signature: addKeySignature, + }; + } catch (e) { + console.log("signKeyRegisterCall e: ", e); + throw e; + } +}; + +const idGatewayRegisterFor = async ( + appSigner: ethers.Wallet, // needs to have existing fid + mainUserSigner: ethers.Wallet, + recoveryAddress: EVMAccountAddress, + deadline: bigint, +): Promise => { + try { + const contract = new ethers.Contract( + ID_GATEWAY_ADDRESS, + idGatewayABI, + appSigner, + ); + const registerIdSig = await signIdRegisterCall( + mainUserSigner, + recoveryAddress, + deadline, + ); + const idGatewayRegisterForParams = { + to: mainUserSigner.address, + recovery: recoveryAddress, + sig: registerIdSig, + deadline: deadline, + }; + const idRegistrationPrice = await getIdRegistrationPrice(); + console.log("idRegistrationPrice: ", idRegistrationPrice); + const args = [ + idGatewayRegisterForParams.to, + idGatewayRegisterForParams.recovery, + idGatewayRegisterForParams.deadline, + idGatewayRegisterForParams.sig, + 0n, + ]; + //"register((address,address,uint256,bytes),(uint32,bytes,uint8,bytes,uint256,bytes)[],uint256)" + const registerCall = await contract["registerFor"].staticCall(...args, { + value: idRegistrationPrice, + }); + console.log("idGatewayRegisterFor: ", registerCall); + return registerCall; + } catch (e) { + console.log("idGatewayRegisterFor e: ", e); + throw e; + } +}; + +const keyGatewayAddFor = async ( + appSigner: ethers.Wallet, // needs to have existing fid + mainUserSigner: ethers.Wallet, + keyToAdd: EVMAccountAddress, + deadline: bigint, +): Promise => { + try { + const contract = new ethers.Contract( + KEY_GATEWAY_ADDRESS, + keyGatewayABI, + appSigner, + ); + const { encodedMetadataStruct, signature } = await signKeyRegisterCall( + mainUserSigner, + keyToAdd, + appSigner, + deadline, + ); + const keyGatewayRegisterForParams = { + keyType: 1, // 1 is the only key type for now + key: mainUserSigner.address, // the key to be registered - doesn't have to be same key as mainUser, could be a newly generated key + metadataType: 1, + metadata: encodedMetadataStruct, + sig: signature, + deadline: deadline, + }; + const args = [ + appSigner.address, + keyGatewayRegisterForParams.keyType, + keyGatewayRegisterForParams.key, + keyGatewayRegisterForParams.metadataType, + keyGatewayRegisterForParams.metadata, + keyGatewayRegisterForParams.deadline, + keyGatewayRegisterForParams.sig, + ]; + //"register((address,address,uint256,bytes),(uint32,bytes,uint8,bytes,uint256,bytes)[],uint256)" + const addForCall = await contract["addFor"].staticCall(...args); + console.log("keyGatewayAddFor: ", addForCall); + return addForCall; + } catch (e) { + console.log("keyGatewayAddFor e: ", e); + throw e; + } +}; + +const haveAppCallBundlerToCreateNewAccounts = async ( + appSigner: ethers.Wallet, // needs to have existing fid + mainUserSigner: ethers.Wallet, + keyToAdd: EVMAccountAddress, + recoveryAddress: EVMAccountAddress, + deadline: bigint, +): Promise => { + try { + const contract = new ethers.Contract( + BUNDLER_ADDRESS, + bundlerABI, + appSigner, + ); + const registerIdSig = await signIdRegisterCall( + mainUserSigner, + recoveryAddress, + deadline, + ); + const idGatewayRegisterForParams = { + to: mainUserSigner.address, + recovery: recoveryAddress, + sig: registerIdSig, + deadline: deadline, + }; + const { encodedMetadataStruct, signature } = await signKeyRegisterCall( + mainUserSigner, + keyToAdd, + appSigner, + deadline, + ); + const keyGatewayRegisterForParams = { + keyType: 1, // 1 is the only key type for now + key: mainUserSigner.address, // the key to be registered - doesn't have to be same key as mainUser, could be a newly generated key + metadataType: 1, + metadata: encodedMetadataStruct, + sig: signature, + deadline: deadline, + }; + const bundlerRegistrationPrice = await getBundlerRegistrationPrice(); + console.log("bundlerRegistrationPrice: ", bundlerRegistrationPrice); + const args = [ + idGatewayRegisterForParams, + [keyGatewayRegisterForParams], + 0n, + ]; + //"register((address,address,uint256,bytes),(uint32,bytes,uint8,bytes,uint256,bytes)[],uint256)" + const registerCall = await contract["register"].staticCall(...args, { + value: bundlerRegistrationPrice, + }); + console.log("haveAppCallBundlerToCreateNewAccounts: ", registerCall); + return registerCall; + } catch (e) { + console.log("haveAppCallBundlerToCreateNewAccounts e: ", e); + throw e; + } +}; + const init = async () => { console.log("Initializing..."); await getLatestBlock(); // await createConsent(); // await sendFunds(); // await renounceRole(); - await getAccountBalanceForErc20( - EVMContractAddress("0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"), - EVMAccountAddress("0x0F9Deb936F279625C13b1d3E3ef8c94734cEd12c"), + // await getAccountBalanceForErc20( + // EVMContractAddress("0x94b008aA00579c1307B0EF2c499aD98a8ce58e58"), + // EVMAccountAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), + // ); + const testAccount = EVMAccountAddress( + "0x0F9Deb936F279625C13b1d3E3ef8c94734cEd12c", + ); + const testAccountSigner = new ethers.Wallet( + "46cb718f767d331ac76f04dc8771adf96f9ab21132545dd0c7797524684d0d63", + provider, + ); + await getNativeBalance(testAccount); + await getIdRegistrationPrice(); + await getBundlerRegistrationPrice(); + await getAppFid(testAccount); + await getKeyGatewayNonce(EVMAccountAddress(signer.address)); + await signIdRegisterCall(signer, testAccount, HOUR_DEADLINE); + await signKeyRegisterEncodedMetadataCall( + testAccountSigner, + EVMAccountAddress(signer.address), + HOUR_DEADLINE, + ); + await signKeyRegisterCall( + signer, + EVMAccountAddress(signer.address), + testAccountSigner, + HOUR_DEADLINE, + ); + await idGatewayRegisterFor( + testAccountSigner, + signer, + EVMAccountAddress(signer.address), + HOUR_DEADLINE, + ); + await addKey( + testAccountSigner, + EVMAccountAddress("0x36F452f0253d0E878BC8a114FF3fA8664EEcbA95"), + HOUR_DEADLINE, ); + // await keyGatewayAddFor( + // testAccountSigner, + // testAccountSigner, + // EVMAccountAddress(signer.address), + // HOUR_DEADLINE, + // ); + // await haveAppCallBundlerToCreateNewAccounts( + // testAccountSigner, + // signer, + // EVMAccountAddress(signer.address), + // testAccount, + // HOUR_DEADLINE, + // ); + // await registerApp(testAccountSigner, testAccount); + // await registerApp(); // await grantRole(); // await getBaseUri(); // await setBaseUri(); diff --git a/yarn.lock b/yarn.lock index 94987ca91..409f75cb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3572,6 +3572,31 @@ __metadata: languageName: node linkType: hard +"@farcaster/core@npm:0.14.15": + version: 0.14.15 + resolution: "@farcaster/core@npm:0.14.15" + dependencies: + "@noble/curves": ^1.0.0 + "@noble/hashes": ^1.3.0 + bs58: ^5.0.0 + neverthrow: ^6.0.0 + viem: ^1.12.2 + checksum: 5319da7e71f86802c3043e114f691b432bd061f02d2c6b4b6537cc248bc4da26b29ad6d71dccd4f37e94b98b66de2173a901d711b2843c5f514c5015b9d2c76f + languageName: node + linkType: hard + +"@farcaster/hub-nodejs@npm:^0.11.16": + version: 0.11.16 + resolution: "@farcaster/hub-nodejs@npm:0.11.16" + dependencies: + "@farcaster/core": 0.14.15 + "@grpc/grpc-js": ~1.8.21 + "@noble/hashes": ^1.3.0 + neverthrow: ^6.0.0 + checksum: 542e36a37747e6b624a556416aa4804a4b8a4522cfce12eda17786dd3809f336701ff4ce8506adc73873ac677e83b382f23a72c9835d6a27076d4f92e3fd9c83 + languageName: node + linkType: hard + "@fastify/busboy@npm:^2.0.0": version: 2.0.0 resolution: "@fastify/busboy@npm:2.0.0" @@ -3805,6 +3830,30 @@ __metadata: languageName: node linkType: hard +"@grpc/grpc-js@npm:~1.8.21": + version: 1.8.22 + resolution: "@grpc/grpc-js@npm:1.8.22" + dependencies: + "@grpc/proto-loader": ^0.7.0 + "@types/node": ">=12.12.47" + checksum: 4e7be493f568ce7f6d196b28d1177cab2714261c2df61a5900b5cc93e2f61362c780e57d0dae556972375006b72d39a9e0860d5c78bbe5e354a0bddf0d3da121 + languageName: node + linkType: hard + +"@grpc/proto-loader@npm:^0.7.0": + version: 0.7.13 + resolution: "@grpc/proto-loader@npm:0.7.13" + dependencies: + lodash.camelcase: ^4.3.0 + long: ^5.0.0 + protobufjs: ^7.2.5 + yargs: ^17.7.2 + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 399c1b8a4627f93dc31660d9636ea6bf58be5675cc7581e3df56a249369e5be02c6cd0d642c5332b0d5673bc8621619bc06fb045aa3e8f57383737b5d35930dc + languageName: node + linkType: hard + "@hapi/address@npm:2.x.x": version: 2.1.4 resolution: "@hapi/address@npm:2.1.4" @@ -9084,6 +9133,7 @@ __metadata: version: 0.0.0-use.local resolution: "@snickerdoodlelabs/contracts-sdk@workspace:packages/contracts-sdk" dependencies: + "@farcaster/hub-nodejs": ^0.11.16 "@snickerdoodlelabs/common-utils": "workspace:^" "@snickerdoodlelabs/node-utils": "workspace:^" "@snickerdoodlelabs/objects": "workspace:^" @@ -11276,6 +11326,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:>=12.12.47": + version: 20.14.2 + resolution: "@types/node@npm:20.14.2" + dependencies: + undici-types: ~5.26.4 + checksum: 265362479b8f3b50fcd1e3f9e9af6121feb01a478dff0335ae67cccc3babfe45d0f12209d3d350595eebd7e67471762697b877c380513f8e5d27a238fa50c805 + languageName: node + linkType: hard + "@types/node@npm:^10.0.3": version: 10.17.60 resolution: "@types/node@npm:10.17.60" @@ -31486,6 +31545,13 @@ __metadata: languageName: node linkType: hard +"long@npm:^5.0.0": + version: 5.2.3 + resolution: "long@npm:5.2.3" + checksum: 885ede7c3de4facccbd2cacc6168bae3a02c3e836159ea4252c87b6e34d40af819824b2d4edce330bfb5c4d6e8ce3ec5864bdcf9473fa1f53a4f8225860e5897 + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -33658,6 +33724,13 @@ __metadata: languageName: node linkType: hard +"neverthrow@npm:^6.0.0": + version: 6.2.2 + resolution: "neverthrow@npm:6.2.2" + checksum: 6b9dd701419c4e475c6dd11dde32be6e1af9c549c29ae18f776b123ef09b6a4235e877b319115597e29fb95aed7ee3b9bb554e4332cba74656a06f3feac9215d + languageName: node + linkType: hard + "next-tick@npm:^1.1.0": version: 1.1.0 resolution: "next-tick@npm:1.1.0" @@ -37409,6 +37482,26 @@ __metadata: languageName: node linkType: hard +"protobufjs@npm:^7.2.5": + version: 7.3.2 + resolution: "protobufjs@npm:7.3.2" + dependencies: + "@protobufjs/aspromise": ^1.1.2 + "@protobufjs/base64": ^1.1.2 + "@protobufjs/codegen": ^2.0.4 + "@protobufjs/eventemitter": ^1.1.0 + "@protobufjs/fetch": ^1.1.0 + "@protobufjs/float": ^1.0.2 + "@protobufjs/inquire": ^1.1.0 + "@protobufjs/path": ^1.1.2 + "@protobufjs/pool": ^1.1.0 + "@protobufjs/utf8": ^1.1.0 + "@types/node": ">=13.7.0" + long: ^5.0.0 + checksum: cfb2a744787f26ee7c82f3e7c4b72cfc000e9bb4c07828ed78eb414db0ea97a340c0cc3264d0e88606592f847b12c0351411f10e9af255b7ba864eec44d7705f + languageName: node + linkType: hard + "protochain@npm:^1.0.5": version: 1.0.5 resolution: "protochain@npm:1.0.5" @@ -44853,6 +44946,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 3192ef6f3fd5df652f2dc1cd782b49d6ff14dc98e5dced492aa8a8c65425227da5da6aafe22523c67f035a272c599bb89cfe803c1db6311e44bed3042fc25487 + languageName: node + linkType: hard + "undici@npm:^5.14.0": version: 5.26.3 resolution: "undici@npm:5.26.3" @@ -45695,6 +45795,27 @@ __metadata: languageName: node linkType: hard +"viem@npm:^1.12.2": + version: 1.21.4 + resolution: "viem@npm:1.21.4" + dependencies: + "@adraffy/ens-normalize": 1.10.0 + "@noble/curves": 1.2.0 + "@noble/hashes": 1.3.2 + "@scure/bip32": 1.3.2 + "@scure/bip39": 1.2.1 + abitype: 0.9.8 + isows: 1.0.3 + ws: 8.13.0 + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: c351fdea2d53d2d781ac73c964348b3b9fc5dd46f9eb53903e867705fc9e30a893cb9f2c8d7a00acdcdeca27d14eeebf976eed9f948c28c47018dc9211369117 + languageName: node + linkType: hard + "vinyl-sourcemaps-apply@npm:^0.2.1": version: 0.2.1 resolution: "vinyl-sourcemaps-apply@npm:0.2.1" @@ -48257,7 +48378,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.0": +"yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.0, yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: