From 9905321686453cbfa1944062eddbd30038a19355 Mon Sep 17 00:00:00 2001 From: HananINouman <110400366+HananINouman@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:50:09 +0300 Subject: [PATCH] support v1.8.0 (#31) * support v1.8.0 * remove not needed function * add tests for v1.8.0 * test to validate v1.7.0 lock * add tests for deposit_amounts * deposit amounts validation * clean the code * fix lint errors * use v1.7.0 for creation * add v1.6.0 data * fix lint errors * format cleaning --- package.json | 3 +- src/constants.ts | 2 + src/hash.ts | 256 ------------- src/index.ts | 2 +- src/services.ts | 2 +- src/types.ts | 19 +- src/utils.ts | 49 +++ src/verification/common.ts | 420 ++++++++++++++++++++++ src/verification/sszTypes.ts | 79 ++++ src/verification/v1.6.0.ts | 226 ++++++++++++ src/verification/v1.7.0.ts | 274 ++++++++++++++ src/verification/v1.8.0.ts | 281 +++++++++++++++ src/verify.ts | 494 ------------------------- test/fixtures.ts | 245 ++++++++++++- test/methods.test.ts | 21 +- test/sdk-package-test/cluster.test.ts | 24 +- test/sdk-package-test/fixtures.ts | 124 ------- test/sdk-package-test/utils.ts | 2 +- test/sdk-package-test/yarn.lock | 495 ++++++++++++++++---------- yarn.lock | 2 +- 20 files changed, 1916 insertions(+), 1104 deletions(-) delete mode 100644 src/hash.ts create mode 100644 src/verification/common.ts create mode 100644 src/verification/sszTypes.ts create mode 100644 src/verification/v1.6.0.ts create mode 100644 src/verification/v1.7.0.ts create mode 100644 src/verification/v1.8.0.ts delete mode 100644 src/verify.ts delete mode 100644 test/sdk-package-test/fixtures.ts diff --git a/package.json b/package.json index bcb3bb3..60e6243 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@obolnetwork/obol-sdk", - "version": "1.0.12", + "version": "1.0.13", "description": "A package for creating Distributed Validators using the Obol API.", "bugs": { "url": "https://github.com/obolnetwork/obol-sdk/issues" @@ -51,6 +51,7 @@ "ethers": "^6.4.0", "nock": "^13.5.3", "release-it": "^17.1.1", + "semver": "^7.6.0", "typescript-eslint": "^7.1.0", "uuid": "^9.0.0" }, diff --git a/src/constants.ts b/src/constants.ts index 572cf0b..0a8d0f8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -116,3 +116,5 @@ export enum DefinitionFlow { export const DEFAULT_BASE_URL = 'https://api.obol.tech' export const DEFAULT_CHAIN_ID = 1 + +export const ETHER_TO_GWEI = 10 ** 9 diff --git a/src/hash.ts b/src/hash.ts deleted file mode 100644 index 489466d..0000000 --- a/src/hash.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { - ContainerType, - ByteVectorType, - UintNumberType, - ListCompositeType, - ByteListType, - fromHexString, -} from '@chainsafe/ssz' -import { type UintNumberByteLen } from '@chainsafe/ssz/lib/type/uint.js' -import { type ValueOfFields } from '@chainsafe/ssz/lib/view/container.js' -import { type ClusterDefintion, type ClusterLock } from './types.js' -import { strToUint8Array } from './utils.js' - -// cluster-definition - -/** - * @param cluster The cluster configuration or the cluster definition - * @param configOnly a boolean to indicate config hash or definition hash - * @returns The config hash or the definition hash in of the corresponding cluster - */ -export const clusterConfigOrDefinitionHash = ( - cluster: ClusterDefintion, - configOnly: boolean, -): string => { - const definitionType = clusterDefinitionContainerType(configOnly) - const val = hashClusterDefinition(cluster, configOnly) - return ( - '0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex') - ) -} - -export const hashClusterDefinition = ( - cluster: ClusterDefintion, - configOnly: boolean, -): ValueOfFields => { - const definitionType = clusterDefinitionContainerType(configOnly) - - const val = definitionType.defaultValue() - - // order should be same as charon https://github.com/ObolNetwork/charon/blob/d00b31e6465a260a43ce40f15c47fb5a5b009042/cluster/ssz.go#L285 - val.uuid = strToUint8Array(cluster.uuid) - val.name = strToUint8Array(cluster.name) - val.version = strToUint8Array(cluster.version) - val.timestamp = strToUint8Array(cluster.timestamp) - val.num_validators = cluster.num_validators - val.threshold = cluster.threshold - val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm) - val.fork_version = fromHexString(cluster.fork_version) - val.operators = cluster.operators.map((operator) => { - return configOnly - ? { address: fromHexString(operator.address) } - : { - address: fromHexString(operator.address), - enr: strToUint8Array(operator.enr as string), - config_signature: fromHexString(operator.config_signature as string), - enr_signature: fromHexString(operator.enr_signature as string), - } - }) - val.creator = configOnly - ? { address: fromHexString(cluster.creator.address) } - : { - address: fromHexString(cluster.creator.address), - config_signature: fromHexString(cluster.creator.config_signature as string), - } - val.validators = cluster.validators.map( - (validator: { - fee_recipient_address: string - withdrawal_address: string - }) => { - return { - fee_recipient_address: fromHexString(validator.fee_recipient_address), - withdrawal_address: fromHexString(validator.withdrawal_address), - } - }, - ) - - if (!configOnly) { - val.config_hash = fromHexString(cluster.config_hash) - } - return val -} - -const operatorAddressWrapperType = new ContainerType({ - address: new ByteVectorType(20), -}) - -const creatorAddressWrapperType = new ContainerType({ - address: new ByteVectorType(20), -}) - -export const operatorContainerType = new ContainerType({ - address: new ByteVectorType(20), - enr: new ByteListType(1024), // This needs to be dynamic, since ENRs do not have a fixed length. - config_signature: new ByteVectorType(65), - enr_signature: new ByteVectorType(65), -}) - -export const creatorContainerType = new ContainerType({ - address: new ByteVectorType(20), - config_signature: new ByteVectorType(65), -}) - -export const validatorsContainerType = new ContainerType({ - fee_recipient_address: new ByteVectorType(20), - withdrawal_address: new ByteVectorType(20), -}) - -const newCreatorContainerType = (configOnly: boolean): ContainerType => { - return configOnly ? creatorAddressWrapperType : creatorContainerType -} - -const newOperatorContainerType = (configOnly: boolean): ContainerType => { - return configOnly ? operatorAddressWrapperType : operatorContainerType -} - -type DefinitionFields = { - uuid: ByteListType - name: ByteListType - version: ByteListType - timestamp: ByteListType - num_validators: UintNumberType - threshold: UintNumberType - dkg_algorithm: ByteListType - fork_version: ByteVectorType - operators: ListCompositeType< - typeof operatorContainerType | typeof operatorAddressWrapperType - > - creator: typeof creatorContainerType | typeof creatorAddressWrapperType - validators: ListCompositeType - config_hash?: ByteVectorType -} - -export type DefinitionContainerType = ContainerType - -/** - * @param configOnly a boolean to indicate config hash or definition hash - * @returns SSZ Containerized type of cluster definition - */ -export const clusterDefinitionContainerType = ( - configOnly: boolean, -): DefinitionContainerType => { - let returnedContainerType: DefinitionFields = { - uuid: new ByteListType(64), - name: new ByteListType(256), - version: new ByteListType(16), - timestamp: new ByteListType(32), - num_validators: new UintNumberType(8 as UintNumberByteLen), - threshold: new UintNumberType(8 as UintNumberByteLen), - dkg_algorithm: new ByteListType(32), - fork_version: new ByteVectorType(4), - operators: new ListCompositeType(newOperatorContainerType(configOnly), 256), - creator: newCreatorContainerType(configOnly), - validators: new ListCompositeType(validatorsContainerType, 65536), - } - - if (!configOnly) { - returnedContainerType = { - ...returnedContainerType, - config_hash: new ByteVectorType(32), - } - } - - return new ContainerType(returnedContainerType) -} - -// cluster-lock - -/** - * @param cluster The published cluster lock - * @returns The lock hash in of the corresponding cluster - */ -export const clusterLockHash = (cluster: ClusterLock): string => { - const lockType = clusterLockContainerType() - - const val = lockType.defaultValue() - - // Check if we can replace with definition_hash - val.cluster_definition = hashClusterDefinition( - cluster.cluster_definition, - false, - ) - val.distributed_validators = cluster.distributed_validators.map( - (dVaidator) => { - return { - distributed_public_key: fromHexString(dVaidator.distributed_public_key), - public_shares: dVaidator.public_shares.map((publicShare) => - fromHexString(publicShare), - ), - deposit_data: { - pubkey: fromHexString(dVaidator.deposit_data.pubkey as string), - withdrawal_credentials: fromHexString( - dVaidator.deposit_data.withdrawal_credentials as string, - ), - amount: parseInt(dVaidator.deposit_data.amount as string), - signature: fromHexString(dVaidator.deposit_data.signature as string), - }, - builder_registration: { - message: { - fee_recipient: fromHexString( - dVaidator.builder_registration.message.fee_recipient, - ), - gas_limit: dVaidator.builder_registration.message.gas_limit, - timestamp: dVaidator.builder_registration.message.timestamp, - pubkey: fromHexString( - dVaidator.builder_registration.message.pubkey, - ), - }, - signature: fromHexString(dVaidator.builder_registration.signature), - }, - } - }, - ) - - return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex') -} - -const depositDataContainer = new ContainerType({ - pubkey: new ByteVectorType(48), - withdrawal_credentials: new ByteVectorType(32), - amount: new UintNumberType(8 as UintNumberByteLen), - signature: new ByteVectorType(96), -}) - -const builderRegistrationMessageContainer = new ContainerType({ - fee_recipient: new ByteVectorType(20), - gas_limit: new UintNumberType(8 as UintNumberByteLen), - timestamp: new UintNumberType(8 as UintNumberByteLen), - pubkey: new ByteVectorType(48), -}) - -const builderRegistrationContainer = new ContainerType({ - message: builderRegistrationMessageContainer, - signature: new ByteVectorType(96), -}) - -const dvContainerType = new ContainerType({ - distributed_public_key: new ByteVectorType(48), - public_shares: new ListCompositeType(new ByteVectorType(48), 256), - deposit_data: depositDataContainer, - builder_registration: builderRegistrationContainer, -}) - -type LockContainerType = ContainerType<{ - cluster_definition: DefinitionContainerType - distributed_validators: ListCompositeType -}> - -/** - * @returns SSZ Containerized type of cluster lock - */ -const clusterLockContainerType = (): LockContainerType => { - return new ContainerType({ - cluster_definition: clusterDefinitionContainerType(false), - distributed_validators: new ListCompositeType(dvContainerType, 65536), - }) -} diff --git a/src/index.ts b/src/index.ts index 63d3a63..f3ca275 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,7 +17,7 @@ import { type ClusterPayload, type OperatorPayload, } from './types.js' -import { clusterConfigOrDefinitionHash } from './hash.js' +import { clusterConfigOrDefinitionHash } from './verification/common.js' import { validatePayload } from './ajv.js' import { definitionSchema, operatorPayloadSchema } from './schema.js' export * from './types.js' diff --git a/src/services.ts b/src/services.ts index 83834a6..7a47626 100644 --- a/src/services.ts +++ b/src/services.ts @@ -1,5 +1,5 @@ import { type ClusterLock } from './types.js' -import { isValidClusterLock } from './verify.js' +import { isValidClusterLock } from './verification/common.js' /** * Verifies Cluster Lock's validity. diff --git a/src/types.ts b/src/types.ts index 119c02c..d3334cf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,8 +75,11 @@ export interface ClusterPayload { /** The cluster nodes operators addresses. */ operators: ClusterOperator[] - /** The clusters validators information. */ + /** The cluster validators information. */ validators: ClusterValidator[] + + /** The cluster partial deposits in gwei or 32000000000. */ + deposit_amounts?: string[] } /** @@ -110,6 +113,9 @@ export interface ClusterDefintion extends ClusterPayload { /** The number of distributed validators in the cluster. */ num_validators: number + /** The cluster partial deposits in gwei or 32000000000. */ + deposit_amounts?: string[] + /** The hash of the cluster definition. */ definition_hash?: string } @@ -172,11 +178,14 @@ export interface DistributedValidator { /** The public key of the node distributed validator share. */ public_shares: string[] - /** The required deposit data for activating the DV. */ - deposit_data: Partial + /** The deposit data for activating the DV. */ + deposit_data?: Partial + + /** The deposit data with partial amounts or full amount for activating the DV. */ + partial_deposit_data?: Array> /** pre-generated signed validator builder registration to be sent to builder network. */ - builder_registration: BuilderRegistration + builder_registration?: BuilderRegistration } /** @@ -196,5 +205,5 @@ export interface ClusterLock { lock_hash: string /** Node Signature for the lock hash by the node secp256k1 key. */ - node_signatures: string[] + node_signatures?: string[] } diff --git a/src/utils.ts b/src/utils.ts index cf7e05d..38025e5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,6 @@ +import { DefinitionFlow } from './constants' +import { type ClusterDefintion } from './types' + export const hexWithout0x = (hex: string): string => { return hex.slice(2, hex.length) } @@ -5,3 +8,49 @@ export const hexWithout0x = (hex: string): string => { export const strToUint8Array = (str: string): Uint8Array => { return new TextEncoder().encode(str) } + +export const definitionFlow = ( + clusterDefinition: ClusterDefintion, +): DefinitionFlow | null => { + if ( + clusterDefinition.creator.address && + clusterDefinition.creator.config_signature && + clusterDefinition.operators.every((operator) => { + return ( + operator.address && + operator.config_signature && + operator.enr && + operator.enr_signature + ) + }) + ) { + return DefinitionFlow.Group + } else if ( + clusterDefinition.creator.address && + clusterDefinition.creator.config_signature && + clusterDefinition.operators.every((operator) => { + return ( + !operator.address && + !operator.config_signature && + operator.enr && + !operator.enr_signature + ) + }) + ) { + return DefinitionFlow.Solo + } else if ( + !clusterDefinition.creator.address && + !clusterDefinition.creator.config_signature && + clusterDefinition.operators.every((operator) => { + return ( + !operator.address && + !operator.config_signature && + operator.enr && + !operator.enr_signature + ) + }) + ) { + return DefinitionFlow.Charon + } + return null +} diff --git a/src/verification/common.ts b/src/verification/common.ts new file mode 100644 index 0000000..7e452cb --- /dev/null +++ b/src/verification/common.ts @@ -0,0 +1,420 @@ +import { + fromHexString, +} from '@chainsafe/ssz' +import elliptic from 'elliptic' +import { + init, +} from '@chainsafe/bls' + +import { FORK_MAPPING, type ClusterDefintion, type ClusterLock, type DepositData, type BuilderRegistrationMessage, type DistributedValidator } from '../types.js' +import * as semver from 'semver' +import { clusterDefinitionContainerTypeV1X6, hashClusterDefinitionV1X6, hashClusterLockV1X6, verifyDVV1X6 } from './v1.6.0.js' +import { clusterDefinitionContainerTypeV1X7, hashClusterDefinitionV1X7, hashClusterLockV1X7, verifyDVV1X7 } from './v1.7.0.js' +import { ethers } from 'ethers' +import { DOMAIN_APPLICATION_BUILDER, DOMAIN_DEPOSIT, DefinitionFlow, GENESIS_VALIDATOR_ROOT, signCreatorConfigHashPayload, signEnrPayload, signOperatorConfigHashPayload } from '../constants.js' +import { SignTypedDataVersion, TypedDataUtils } from '@metamask/eth-sig-util' +import { builderRegistrationMessageType, depositMessageType, forkDataType, signingRootType } from './sszTypes.js' +import { definitionFlow, hexWithout0x } from '../utils.js' +import { ENR } from '@chainsafe/discv5' +import { clusterDefinitionContainerTypeV1X8, hashClusterDefinitionV1X8, hashClusterLockV1X8, verifyDVV1X8 } from './v1.8.0.js' + +// cluster-definition hash + +/** + * @param cluster The cluster configuration or the cluster definition + * @param configOnly a boolean to indicate config hash or definition hash + * @returns The config hash or the definition hash in of the corresponding cluster + */ +export const clusterConfigOrDefinitionHash = ( + cluster: ClusterDefintion, + configOnly: boolean, +): string => { + let definitionType, val + + if (semver.eq(cluster.version, 'v1.6.0')) { + definitionType = clusterDefinitionContainerTypeV1X6(configOnly) + val = hashClusterDefinitionV1X6(cluster, configOnly) + return ( + '0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex') + ) + } + + if (semver.eq(cluster.version, 'v1.7.0')) { + definitionType = clusterDefinitionContainerTypeV1X7(configOnly) + val = hashClusterDefinitionV1X7(cluster, configOnly) + return ( + '0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex') + ) + } + + if (semver.eq(cluster.version, 'v1.8.0')) { + definitionType = clusterDefinitionContainerTypeV1X8(configOnly) + val = hashClusterDefinitionV1X8(cluster, configOnly) + return ( + '0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex') + ) + } + + throw new Error('unsupported version') +} + +// cluster-lock hash + +/** + * Returns the SSZ cluster lock hash of the given cluster lock object + * @param cluster The cluster lock whose lock hash needs to be calculated + * @returns The cluster lock hash in of the corresponding cluster lock + */ +export const clusterLockHash = (clusterLock: ClusterLock): string => { + if (semver.eq(clusterLock.cluster_definition.version, 'v1.6.0')) { + return hashClusterLockV1X6(clusterLock) + } + + if (semver.eq(clusterLock.cluster_definition.version, 'v1.7.0')) { + return hashClusterLockV1X7(clusterLock) + } + + if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) { + return hashClusterLockV1X8(clusterLock) + } + + // other versions + throw new Error('unsupported version') +} + +// Lock verification + +// cluster-definition signatures verification + +const getPOSTConfigHashSigner = ( + signature: string, + configHash: string, + chainId: FORK_MAPPING, +): string => { + try { + const sig = ethers.Signature.from(signature) + const data = signCreatorConfigHashPayload( + { creator_config_hash: configHash }, + chainId, + ) + const digest = TypedDataUtils.eip712Hash(data, SignTypedDataVersion.V4) + + return ethers.recoverAddress(digest, sig).toLowerCase() + } catch (err) { + throw err + } +} + +const getPUTConfigHashSigner = ( + signature: string, + configHash: string, + chainId: number, +): string => { + try { + const sig = ethers.Signature.from(signature) + const data = signOperatorConfigHashPayload( + { operator_config_hash: configHash }, + chainId, + ) + const digest = TypedDataUtils.eip712Hash(data, SignTypedDataVersion.V4) + + return ethers.recoverAddress(digest, sig).toLowerCase() + } catch (err) { + throw err + } +} + +const getEnrSigner = ( + signature: string, + payload: string, + chainId: number, +): string => { + try { + const sig = ethers.Signature.from(signature) + + const data = signEnrPayload({ enr: payload }, chainId) + const digest = TypedDataUtils.eip712Hash(data, SignTypedDataVersion.V4) + + return ethers.recoverAddress(digest, sig).toLowerCase() + } catch (err) { + throw err + } +} + +const verifyDefinitionSignatures = ( + clusterDefinition: ClusterDefintion, + definitionType: DefinitionFlow, +): boolean => { + if (definitionType === DefinitionFlow.Charon) { + return true + } else { + const configSigner = getPOSTConfigHashSigner( + clusterDefinition.creator.config_signature as string, + clusterDefinition.config_hash, + FORK_MAPPING[clusterDefinition.fork_version as keyof typeof FORK_MAPPING], + ) + + if (configSigner !== clusterDefinition.creator.address.toLowerCase()) { + return false + } + if (definitionType === DefinitionFlow.Solo) { + return true + } + return clusterDefinition.operators.every((operator) => { + const configSigner = getPUTConfigHashSigner( + operator.config_signature as string, + clusterDefinition.config_hash, + FORK_MAPPING[ + clusterDefinition.fork_version as keyof typeof FORK_MAPPING + ], + ) + + const enrSigner = getEnrSigner( + operator.enr_signature as string, + operator.enr as string, + FORK_MAPPING[ + clusterDefinition.fork_version as keyof typeof FORK_MAPPING + ], + ) + + if ( + configSigner !== operator.address.toLowerCase() || + enrSigner !== operator.address.toLowerCase() + ) { + return false + } + return true + }) + } +} + +// cluster-lock data verification +const computeSigningRoot = ( + sszObjectRoot: Uint8Array, + domain: Uint8Array, +): Uint8Array => { + const signingRootDefaultValue = signingRootType.defaultValue() + signingRootDefaultValue.objectRoot = sszObjectRoot + signingRootDefaultValue.domain = domain + return Buffer.from(signingRootType.hashTreeRoot(signingRootDefaultValue).buffer) +} + +const computeDepositMsgRoot = (msg: Partial): Buffer => { + const depositMsgVal = depositMessageType.defaultValue() + + depositMsgVal.pubkey = fromHexString(msg.pubkey as string) + depositMsgVal.withdrawal_credentials = fromHexString( + msg.withdrawal_credentials as string, + ) + depositMsgVal.amount = parseInt(msg.amount as string) + return Buffer.from(depositMessageType.hashTreeRoot(depositMsgVal).buffer) +} + +const computeForkDataRoot = ( + currentVersion: Uint8Array, + genesisValidatorsRoot: Uint8Array, +): Uint8Array => { + const forkDataVal = forkDataType.defaultValue() + forkDataVal.currentVersion = currentVersion + forkDataVal.genesisValidatorsRoot = genesisValidatorsRoot + return Buffer.from(forkDataType.hashTreeRoot(forkDataVal).buffer) +} + +const computebuilderRegistrationMsgRoot = ( + msg: BuilderRegistrationMessage, +): Buffer => { + const builderRegistrationMsgVal = + builderRegistrationMessageType.defaultValue() + + builderRegistrationMsgVal.fee_recipient = fromHexString(msg.fee_recipient) + builderRegistrationMsgVal.gas_limit = msg.gas_limit + builderRegistrationMsgVal.timestamp = msg.timestamp + builderRegistrationMsgVal.pubkey = fromHexString(msg.pubkey) + return Buffer.from( + builderRegistrationMessageType.hashTreeRoot(builderRegistrationMsgVal) + .buffer, + ) +} + +const computeDomain = ( + domainType: Uint8Array, + lockForkVersion: string, + genesisValidatorsRoot: Uint8Array = fromHexString(GENESIS_VALIDATOR_ROOT), +): Uint8Array => { + const forkVersion = fromHexString( + lockForkVersion.substring(2, lockForkVersion.length), + ) + + const forkDataRoot = computeForkDataRoot(forkVersion, genesisValidatorsRoot) + const domain = new Uint8Array(32) + domain.set(domainType) + domain.set(forkDataRoot.subarray(0, 28), 4) + return domain +} + +/** + * Verify deposit data withdrawal credintials and signature + * @param {string} forkVersion - fork version in definition file. + * @param {DistributedValidatorDto} validator - distributed validator. + * @param {string} withdrawalAddress - withdrawal address in definition file. + * @returns {boolean} - return if deposit data is valid. + */ +export const verifyDepositData = ( + distributedPublicKey: string, + depositData: Partial, + withdrawalAddress: string, + forkVersion: string, +): { isValidDepositData: boolean, depositDataMsg: Uint8Array } => { + const depositDomain = computeDomain( + fromHexString(DOMAIN_DEPOSIT), + forkVersion, + ) + const eth1AddressWithdrawalPrefix = '0x01' + if ( + eth1AddressWithdrawalPrefix + + '0'.repeat(22) + + withdrawalAddress.toLowerCase().slice(2) !== + depositData.withdrawal_credentials + ) { + return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) } + } + + if (distributedPublicKey !== depositData.pubkey) { + return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) } + } + + const depositMessageBuffer = computeDepositMsgRoot( + depositData + ) + const depositDataMessage = signingRoot( + depositDomain, + depositMessageBuffer, + ) + + return { isValidDepositData: true, depositDataMsg: depositDataMessage } +} + +export const verifyBuilderRegistration = ( + validator: DistributedValidator, + feeRecipientAddress: string, + forkVersion: string, +): { isValidBuilderRegistration: boolean, builderRegistrationMsg: Uint8Array } => { + const builderDomain = computeDomain( + fromHexString(DOMAIN_APPLICATION_BUILDER), + forkVersion) + + if ( + validator.distributed_public_key !== + validator.builder_registration?.message.pubkey + ) { + return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) } + } + if ( + feeRecipientAddress.toLowerCase() !== + validator.builder_registration.message.fee_recipient.toLowerCase() + ) { + return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) } + } + + const builderRegistrationMessageBuffer = + computebuilderRegistrationMsgRoot( + validator.builder_registration.message, + ) + + const builderRegistrationMessage = signingRoot( + builderDomain, + builderRegistrationMessageBuffer, + ) + + return { isValidBuilderRegistration: true, builderRegistrationMsg: builderRegistrationMessage } +} + +export const verifyNodeSignatures = (clusterLock: ClusterLock): boolean => { + const ec = new elliptic.ec('secp256k1') + const nodeSignatures = clusterLock.node_signatures + + const lockHashWithout0x = hexWithout0x(clusterLock.lock_hash) + // node(ENR) signatures + for (let i = 0; i < (nodeSignatures as string[]).length; i++) { + const pubkey = ENR.decodeTxt( + clusterLock.cluster_definition.operators[i].enr as string, + ).publicKey.toString('hex') + + const ENRsignature = { + r: (nodeSignatures as string[])[i].slice(2, 66), + s: (nodeSignatures as string[])[i].slice(66, 130), + } + + const nodeSignatureVerification = ec + .keyFromPublic(pubkey, 'hex') + .verify(lockHashWithout0x, ENRsignature) + + if (!nodeSignatureVerification) { + return false + } + } + + return true +} + +export const signingRoot = ( + domain: Uint8Array, + messageBuffer: Buffer, +): Uint8Array => { + return computeSigningRoot(messageBuffer, domain) +} + +const verifyLockData = async (clusterLock: ClusterLock): Promise => { + await init('herumi') + + if (semver.eq(clusterLock.cluster_definition.version, 'v1.6.0')) { + return verifyDVV1X6(clusterLock) + } + + if (semver.eq(clusterLock.cluster_definition.version, 'v1.7.0')) { + return verifyDVV1X7(clusterLock) + } + + if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) { + return verifyDVV1X8(clusterLock) + } + return false +} + +export const isValidClusterLock = async ( + clusterLock: ClusterLock, +): Promise => { + try { + const definitionType = definitionFlow(clusterLock.cluster_definition) + if (definitionType == null) { + return false + } + + const isValidDefinitionData = verifyDefinitionSignatures( + clusterLock.cluster_definition, + definitionType, + ) + if (!isValidDefinitionData) { + return false + } + + if ( + clusterConfigOrDefinitionHash(clusterLock.cluster_definition, false) !== + clusterLock.cluster_definition.definition_hash + ) { + return false + } + + if (clusterLockHash(clusterLock) !== clusterLock.lock_hash) { + return false + } + + const isValidLockData = await verifyLockData(clusterLock) + if (!isValidLockData) { + return false + } + return true + } catch (err) { + return false + } +} diff --git a/src/verification/sszTypes.ts b/src/verification/sszTypes.ts new file mode 100644 index 0000000..05c9302 --- /dev/null +++ b/src/verification/sszTypes.ts @@ -0,0 +1,79 @@ +import { ByteListType, ByteVectorType, ContainerType, UintNumberType } from '@chainsafe/ssz' +import { type UintNumberByteLen } from '@chainsafe/ssz/lib/type/uint' + +export const operatorAddressWrapperType = new ContainerType({ + address: new ByteVectorType(20), +}) + +export const creatorAddressWrapperType = new ContainerType({ + address: new ByteVectorType(20), +}) + +export const operatorContainerType = new ContainerType({ + address: new ByteVectorType(20), + enr: new ByteListType(1024), // This needs to be dynamic, since ENRs do not have a fixed length. + config_signature: new ByteVectorType(65), + enr_signature: new ByteVectorType(65), +}) + +export const creatorContainerType = new ContainerType({ + address: new ByteVectorType(20), + config_signature: new ByteVectorType(65), +}) + +export const validatorsContainerType = new ContainerType({ + fee_recipient_address: new ByteVectorType(20), + withdrawal_address: new ByteVectorType(20), +}) + +export const newCreatorContainerType = (configOnly: boolean): ContainerType => { + return configOnly ? creatorAddressWrapperType : creatorContainerType +} + +export const newOperatorContainerType = (configOnly: boolean): ContainerType => { + return configOnly ? operatorAddressWrapperType : operatorContainerType +} + +// Lock +export const depositDataContainer = new ContainerType({ + pubkey: new ByteVectorType(48), + withdrawal_credentials: new ByteVectorType(32), + amount: new UintNumberType(8 as UintNumberByteLen), + signature: new ByteVectorType(96), +}) + +export const builderRegistrationMessageContainer = new ContainerType({ + fee_recipient: new ByteVectorType(20), + gas_limit: new UintNumberType(8 as UintNumberByteLen), + timestamp: new UintNumberType(8 as UintNumberByteLen), + pubkey: new ByteVectorType(48), +}) + +export const builderRegistrationContainer = new ContainerType({ + message: builderRegistrationMessageContainer, + signature: new ByteVectorType(96), +}) + +export const builderRegistrationMessageType = new ContainerType({ + fee_recipient: new ByteVectorType(20), + gas_limit: new UintNumberType(8 as UintNumberByteLen), + timestamp: new UintNumberType(8 as UintNumberByteLen), + pubkey: new ByteVectorType(48), +}) + +// For domain computation that is used in deposit data and builder registration verification for dv +export const forkDataType = new ContainerType({ + currentVersion: new ByteVectorType(4), + genesisValidatorsRoot: new ByteVectorType(32), +}) + +export const depositMessageType = new ContainerType({ + pubkey: new ByteVectorType(48), + withdrawal_credentials: new ByteVectorType(32), + amount: new UintNumberType(8), +}) + +export const signingRootType = new ContainerType({ + objectRoot: new ByteVectorType(32), + domain: new ByteVectorType(32), +}) diff --git a/src/verification/v1.6.0.ts b/src/verification/v1.6.0.ts new file mode 100644 index 0000000..5400b14 --- /dev/null +++ b/src/verification/v1.6.0.ts @@ -0,0 +1,226 @@ +import { type UintNumberByteLen, UintNumberType } from '@chainsafe/ssz/lib/type/uint' +import { strToUint8Array } from '../utils' +import { type creatorAddressWrapperType, type creatorContainerType, newCreatorContainerType, newOperatorContainerType, type operatorAddressWrapperType, type operatorContainerType, validatorsContainerType } from './sszTypes' +import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from '@chainsafe/ssz' +import { type ValueOfFields } from '@chainsafe/ssz/lib/view/container' +import { type ClusterDefintion, type ClusterLock, type DepositData } from '../types' +import { verifyDepositData } from './common' +import { aggregateSignatures, verifyAggregate, verifyMultiple } from '@chainsafe/bls' + +// cluster defintion +type DefinitionFieldsV1X6 = { + uuid: ByteListType + name: ByteListType + version: ByteListType + timestamp: ByteListType + num_validators: UintNumberType + threshold: UintNumberType + dkg_algorithm: ByteListType + fork_version: ByteVectorType + operators: ListCompositeType< + typeof operatorContainerType | typeof operatorAddressWrapperType + > + creator: typeof creatorContainerType | typeof creatorAddressWrapperType + validators: ListCompositeType + config_hash?: ByteVectorType +} + +type DefinitionContainerTypeV1X6 = + ContainerType + +/** + * Returns the containerized cluster definition + * @param cluster ClusterDefinition to calculate the type from + * @returns SSZ Containerized type of cluster input + */ +export const clusterDefinitionContainerTypeV1X6 = ( + configOnly: boolean, +): DefinitionContainerTypeV1X6 => { + let returnedContainerType: any = { + uuid: new ByteListType(64), + name: new ByteListType(256), + version: new ByteListType(16), + timestamp: new ByteListType(32), + num_validators: new UintNumberType(8 as UintNumberByteLen), + threshold: new UintNumberType(8 as UintNumberByteLen), + dkg_algorithm: new ByteListType(32), + fork_version: new ByteVectorType(4), + operators: new ListCompositeType(newOperatorContainerType(configOnly), 256), + creator: newCreatorContainerType(configOnly), + validators: new ListCompositeType(validatorsContainerType, 65536), + } + + if (!configOnly) { + returnedContainerType = { + ...returnedContainerType, + config_hash: new ByteVectorType(32), + } + } + + return new ContainerType(returnedContainerType) +} + +export const hashClusterDefinitionV1X6 = ( + cluster: ClusterDefintion, + configOnly: boolean, +): ValueOfFields => { + const definitionType = clusterDefinitionContainerTypeV1X6(configOnly) + + const val = definitionType.defaultValue() + + // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276 + val.uuid = strToUint8Array(cluster.uuid) + val.name = strToUint8Array(cluster.name) + val.version = strToUint8Array(cluster.version) + val.timestamp = strToUint8Array(cluster.timestamp) + val.num_validators = cluster.num_validators + val.threshold = cluster.threshold + val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm) + val.fork_version = fromHexString(cluster.fork_version) + val.operators = cluster.operators.map(operator => { + return configOnly + ? { address: fromHexString(operator.address) } + : { + address: fromHexString(operator.address), + enr: strToUint8Array(operator.enr as string), + config_signature: fromHexString(operator.config_signature as string), + enr_signature: fromHexString(operator.enr_signature as string), + } + }) + val.creator = configOnly + ? { address: fromHexString(cluster.creator.address) } + : { + address: fromHexString(cluster.creator.address), + config_signature: fromHexString(cluster.creator.config_signature as string), + } + val.validators = cluster.validators.map((validator) => { + return { + fee_recipient_address: fromHexString(validator.fee_recipient_address), + withdrawal_address: fromHexString(validator.withdrawal_address), + } + }) + + if (!configOnly) { + val.config_hash = fromHexString(cluster.config_hash) + } + return val +} + +// cluster lock + +const dvContainerTypeV1X6 = new ContainerType({ + distributed_public_key: new ByteVectorType(48), + public_shares: new ListCompositeType(new ByteVectorType(48), 256), + pubkey: new ByteVectorType(48), + withdrawal_credentials: new ByteVectorType(32), + amount: new UintNumberType(8 as UintNumberByteLen), + signature: new ByteVectorType(96), +}) + +type LockContainerTypeV1X6 = ContainerType<{ + cluster_definition: DefinitionContainerTypeV1X6 + distributed_validators: ListCompositeType +}> + +/** + * @returns SSZ Containerized type of cluster lock + */ +const clusterLockContainerTypeV1X6 = (): LockContainerTypeV1X6 => { + return new ContainerType({ + cluster_definition: clusterDefinitionContainerTypeV1X6(false), + distributed_validators: new ListCompositeType(dvContainerTypeV1X6, 65536), + }) +} + +/** + * @param cluster The published cluster lock + * @returns The lock hash in of the corresponding cluster + */ +export const hashClusterLockV1X6 = (cluster: ClusterLock): string => { + const lockType = clusterLockContainerTypeV1X6() + + const val = lockType.defaultValue() + + // Check if we can replace with definition_hash + val.cluster_definition = hashClusterDefinitionV1X6( + cluster.cluster_definition, + false, + ) + val.distributed_validators = cluster.distributed_validators.map(dValidator => { + return { + distributed_public_key: fromHexString(dValidator.distributed_public_key), + public_shares: dValidator.public_shares.map(publicShare => + fromHexString(publicShare), + ), + pubkey: fromHexString(dValidator.deposit_data?.pubkey as string), + withdrawal_credentials: fromHexString( + dValidator.deposit_data?.withdrawal_credentials as string, + ), + amount: parseInt(dValidator.deposit_data?.amount as string), + signature: fromHexString(dValidator.deposit_data?.signature as string), + } + }) + + return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex') +} + +// DV verification +export const verifyDVV1X6 = (clusterLock: ClusterLock): boolean => { + const validators = clusterLock.distributed_validators + const pubShares = [] + const pubKeys = [] + const builderRegistrationAndDepositDataMessages = [] + const blsSignatures = [] + + for (let i = 0; i < validators.length; i++) { + const validator = validators[i] + const validatorPublicShares = validator.public_shares + const distributedPublicKey = validator.distributed_public_key + + // Needed in signature_aggregate verification + for (const element of validatorPublicShares) { + pubShares.push(fromHexString(element)) + } + + const { isValidDepositData, depositDataMsg } = verifyDepositData( + distributedPublicKey, + validator.deposit_data as Partial, + clusterLock.cluster_definition.validators[i].withdrawal_address, + clusterLock.cluster_definition.fork_version + ) + + if ( + !isValidDepositData + ) { + return false + } + + pubKeys.push(fromHexString(validator.distributed_public_key)) + builderRegistrationAndDepositDataMessages.push(depositDataMsg) + blsSignatures.push(fromHexString(validator.deposit_data?.signature as string)) + } + + const aggregateBLSSignature = aggregateSignatures(blsSignatures) + + if ( + !verifyMultiple( + pubKeys, + builderRegistrationAndDepositDataMessages, + aggregateBLSSignature, + ) + ) { + return false + } + + if ( + !verifyAggregate( + pubShares, + fromHexString(clusterLock.lock_hash), + fromHexString(clusterLock.signature_aggregate), + ) + ) { + return false + } + + return true +} diff --git a/src/verification/v1.7.0.ts b/src/verification/v1.7.0.ts new file mode 100644 index 0000000..8e87a4f --- /dev/null +++ b/src/verification/v1.7.0.ts @@ -0,0 +1,274 @@ +import { type UintNumberByteLen, UintNumberType } from '@chainsafe/ssz/lib/type/uint' +import { strToUint8Array } from '../utils' +import { builderRegistrationContainer, type creatorAddressWrapperType, type creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, type operatorAddressWrapperType, type operatorContainerType, validatorsContainerType } from './sszTypes' +import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from '@chainsafe/ssz' +import { type ValueOfFields } from '@chainsafe/ssz/lib/view/container' +import { type ClusterDefintion, type ClusterLock, type DepositData } from '../types' +import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from './common' +import { aggregateSignatures, verifyAggregate, verifyMultiple } from '@chainsafe/bls' + +// cluster defintion +type DefinitionFieldsV1X7 = { + uuid: ByteListType + name: ByteListType + version: ByteListType + timestamp: ByteListType + num_validators: UintNumberType + threshold: UintNumberType + dkg_algorithm: ByteListType + fork_version: ByteVectorType + operators: ListCompositeType< + typeof operatorContainerType | typeof operatorAddressWrapperType + > + creator: typeof creatorContainerType | typeof creatorAddressWrapperType + validators: ListCompositeType + config_hash?: ByteVectorType +} + +type DefinitionContainerTypeV1X7 = + ContainerType + +/** + * Returns the containerized cluster definition + * @param cluster ClusterDefinition to calculate the type from + * @returns SSZ Containerized type of cluster input + */ +export const clusterDefinitionContainerTypeV1X7 = ( + configOnly: boolean, +): DefinitionContainerTypeV1X7 => { + let returnedContainerType: any = { + uuid: new ByteListType(64), + name: new ByteListType(256), + version: new ByteListType(16), + timestamp: new ByteListType(32), + num_validators: new UintNumberType(8 as UintNumberByteLen), + threshold: new UintNumberType(8 as UintNumberByteLen), + dkg_algorithm: new ByteListType(32), + fork_version: new ByteVectorType(4), + operators: new ListCompositeType(newOperatorContainerType(configOnly), 256), + creator: newCreatorContainerType(configOnly), + validators: new ListCompositeType(validatorsContainerType, 65536), + } + + if (!configOnly) { + returnedContainerType = { + ...returnedContainerType, + config_hash: new ByteVectorType(32), + } + } + + return new ContainerType(returnedContainerType) +} + +export const hashClusterDefinitionV1X7 = ( + cluster: ClusterDefintion, + configOnly: boolean, +): ValueOfFields => { + const definitionType = clusterDefinitionContainerTypeV1X7(configOnly) + + const val = definitionType.defaultValue() + + // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276 + val.uuid = strToUint8Array(cluster.uuid) + val.name = strToUint8Array(cluster.name) + val.version = strToUint8Array(cluster.version) + val.timestamp = strToUint8Array(cluster.timestamp) + val.num_validators = cluster.num_validators + val.threshold = cluster.threshold + val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm) + val.fork_version = fromHexString(cluster.fork_version) + val.operators = cluster.operators.map(operator => { + return configOnly + ? { address: fromHexString(operator.address) } + : { + address: fromHexString(operator.address), + enr: strToUint8Array(operator.enr as string), + config_signature: fromHexString(operator.config_signature as string), + enr_signature: fromHexString(operator.enr_signature as string), + } + }) + val.creator = configOnly + ? { address: fromHexString(cluster.creator.address) } + : { + address: fromHexString(cluster.creator.address), + config_signature: fromHexString(cluster.creator.config_signature as string), + } + val.validators = cluster.validators.map((validator) => { + return { + fee_recipient_address: fromHexString(validator.fee_recipient_address), + withdrawal_address: fromHexString(validator.withdrawal_address), + } + }) + + if (!configOnly) { + val.config_hash = fromHexString(cluster.config_hash) + } + return val +} + +// cluster lock + +const dvContainerTypeV1X7 = new ContainerType({ + distributed_public_key: new ByteVectorType(48), + public_shares: new ListCompositeType(new ByteVectorType(48), 256), + deposit_data: depositDataContainer, + builder_registration: builderRegistrationContainer, +}) + +type LockContainerTypeV1X7 = ContainerType<{ + cluster_definition: DefinitionContainerTypeV1X7 + distributed_validators: ListCompositeType +}> + +/** + * @returns SSZ Containerized type of cluster lock + */ +const clusterLockContainerTypeV1X7 = (): LockContainerTypeV1X7 => { + return new ContainerType({ + cluster_definition: clusterDefinitionContainerTypeV1X7(false), + distributed_validators: new ListCompositeType(dvContainerTypeV1X7, 65536), + }) +} + +/** + * @param cluster The published cluster lock + * @returns The lock hash in of the corresponding cluster + */ +export const hashClusterLockV1X7 = (cluster: ClusterLock): string => { + const lockType = clusterLockContainerTypeV1X7() + + const val = lockType.defaultValue() + + // Check if we can replace with definition_hash + val.cluster_definition = hashClusterDefinitionV1X7( + cluster.cluster_definition, + false, + ) + val.distributed_validators = cluster.distributed_validators.map( + (dValidator) => { + return { + distributed_public_key: fromHexString(dValidator.distributed_public_key), + public_shares: dValidator.public_shares.map((publicShare) => + fromHexString(publicShare), + ), + deposit_data: { + pubkey: fromHexString(dValidator.deposit_data?.pubkey as string), + withdrawal_credentials: fromHexString( + dValidator.deposit_data?.withdrawal_credentials as string, + ), + amount: parseInt(dValidator.deposit_data?.amount as string), + signature: fromHexString(dValidator.deposit_data?.signature as string), + }, + builder_registration: { + message: { + fee_recipient: fromHexString( + dValidator.builder_registration?.message.fee_recipient as string, + ), + gas_limit: dValidator.builder_registration?.message.gas_limit as number, + timestamp: dValidator.builder_registration?.message.timestamp as number, + pubkey: fromHexString( + dValidator.builder_registration?.message.pubkey as string, + ), + }, + signature: fromHexString(dValidator.builder_registration?.signature as string), + }, + } + }, + ) + + return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex') +} + +// DV verification +export const verifyDVV1X7 = (clusterLock: ClusterLock): boolean => { + const validators = clusterLock.distributed_validators + + const pubShares = [] + + const pubKeys = [] + const builderRegistrationAndDepositDataMessages = [] + const blsSignatures = [] + + for (let i = 0; i < validators.length; i++) { + const validator = validators[i] + const validatorPublicShares = validator.public_shares + const distributedPublicKey = validator.distributed_public_key + + // Needed in signature_aggregate verification + for (const element of validatorPublicShares) { + pubShares.push(fromHexString(element)) + } + + // Deposit Data Verification + const { isValidDepositData, depositDataMsg } = verifyDepositData( + distributedPublicKey, + validator.deposit_data as Partial, + clusterLock.cluster_definition.validators[i].withdrawal_address, + clusterLock.cluster_definition.fork_version + ) + + if ( + !isValidDepositData + ) { + return false + } + + pubKeys.push(fromHexString(distributedPublicKey)) + builderRegistrationAndDepositDataMessages.push(depositDataMsg) + blsSignatures.push(fromHexString(validator.deposit_data?.signature as string)) + + // Builder Registration Verification + const { isValidBuilderRegistration, builderRegistrationMsg } = verifyBuilderRegistration( + validator, + clusterLock.cluster_definition.validators[i].fee_recipient_address, + clusterLock.cluster_definition.fork_version + ) + + if ( + !isValidBuilderRegistration + ) { + return false + } + + pubKeys.push(fromHexString(distributedPublicKey)) + builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg) + blsSignatures.push( + fromHexString(validator.builder_registration?.signature as string), + ) + } + + // BLS signatures verification + const aggregateBLSSignature = aggregateSignatures(blsSignatures) + + if ( + !verifyMultiple( + pubKeys, + builderRegistrationAndDepositDataMessages, + aggregateBLSSignature, + ) + ) { + return false + } + + // Node Signatures verification + if ( + !verifyNodeSignatures( + clusterLock + ) + ) { + return false + } + + // signature_aggregate verification + if ( + !verifyAggregate( + pubShares, + fromHexString(clusterLock.lock_hash), + fromHexString(clusterLock.signature_aggregate), + ) + ) { + return false + } + + return true +} diff --git a/src/verification/v1.8.0.ts b/src/verification/v1.8.0.ts new file mode 100644 index 0000000..75b5a75 --- /dev/null +++ b/src/verification/v1.8.0.ts @@ -0,0 +1,281 @@ +import { type UintNumberByteLen, UintNumberType } from '@chainsafe/ssz/lib/type/uint' +import { strToUint8Array } from '../utils' +import { builderRegistrationContainer, type creatorAddressWrapperType, type creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, type operatorAddressWrapperType, type operatorContainerType, validatorsContainerType } from './sszTypes' +import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString } from '@chainsafe/ssz' +import { type ValueOfFields } from '@chainsafe/ssz/lib/view/container' +import { type ClusterDefintion, type ClusterLock, type DepositData } from '../types' +import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from './common' +import { aggregateSignatures, verifyAggregate, verifyMultiple } from '@chainsafe/bls' + +// cluster defintion +type DefinitionFieldsV1X8 = { + uuid: ByteListType + name: ByteListType + version: ByteListType + timestamp: ByteListType + num_validators: UintNumberType + threshold: UintNumberType + dkg_algorithm: ByteListType + fork_version: ByteVectorType + operators: ListCompositeType< + typeof operatorContainerType | typeof operatorAddressWrapperType + > + creator: typeof creatorContainerType | typeof creatorAddressWrapperType + validators: ListCompositeType + deposit_amounts: ListBasicType + config_hash?: ByteVectorType +} + +type DefinitionContainerTypeV1X8 = ContainerType + +/** + * Returns the containerized cluster definition + * @param cluster ClusterDefinition to calculate the type from + * @returns SSZ Containerized type of cluster input + */ +export const clusterDefinitionContainerTypeV1X8 = ( + configOnly: boolean, +): DefinitionContainerTypeV1X8 => { + let returnedContainerType: any = { + uuid: new ByteListType(64), + name: new ByteListType(256), + version: new ByteListType(16), + timestamp: new ByteListType(32), + num_validators: new UintNumberType(8 as UintNumberByteLen), + threshold: new UintNumberType(8 as UintNumberByteLen), + dkg_algorithm: new ByteListType(32), + fork_version: new ByteVectorType(4), + operators: new ListCompositeType(newOperatorContainerType(configOnly), 256), + creator: newCreatorContainerType(configOnly), + validators: new ListCompositeType(validatorsContainerType, 65536), + deposit_amounts: new ListBasicType( + new UintNumberType(8 as UintNumberByteLen), + 256, + ), + } + + if (!configOnly) { + returnedContainerType = { + ...returnedContainerType, + config_hash: new ByteVectorType(32), + } + } + + return new ContainerType(returnedContainerType) +} + +export const hashClusterDefinitionV1X8 = ( + cluster: ClusterDefintion, + configOnly: boolean, +): ValueOfFields => { + const definitionType = clusterDefinitionContainerTypeV1X8(configOnly) + + const val = definitionType.defaultValue() + + // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276 + val.uuid = strToUint8Array(cluster.uuid) + val.name = strToUint8Array(cluster.name) + val.version = strToUint8Array(cluster.version) + val.timestamp = strToUint8Array(cluster.timestamp) + val.num_validators = cluster.num_validators + val.threshold = cluster.threshold + val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm) + val.fork_version = fromHexString(cluster.fork_version) + val.operators = cluster.operators.map(operator => { + return configOnly + ? { address: fromHexString(operator.address) } + : { + address: fromHexString(operator.address), + enr: strToUint8Array(operator.enr as string), + config_signature: fromHexString(operator.config_signature as string), + enr_signature: fromHexString(operator.enr_signature as string), + } + }) + val.creator = configOnly + ? { address: fromHexString(cluster.creator.address) } + : { + address: fromHexString(cluster.creator.address), + config_signature: fromHexString(cluster.creator.config_signature as string), + } + val.validators = cluster.validators.map((validator) => { + return { + fee_recipient_address: fromHexString(validator.fee_recipient_address), + withdrawal_address: fromHexString(validator.withdrawal_address), + } + }) + val.deposit_amounts = (cluster.deposit_amounts as string[]).map((amount: string) => { + return parseInt(amount) + }) + + if (!configOnly) { + val.config_hash = fromHexString(cluster.config_hash) + } + return val +} + +// cluster lock + +const dvContainerTypeV1X8 = new ContainerType({ + distributed_public_key: new ByteVectorType(48), + public_shares: new ListCompositeType(new ByteVectorType(48), 256), + partial_deposit_data: new ListCompositeType(depositDataContainer, 256), + builder_registration: builderRegistrationContainer, +}) + +type LockContainerTypeV1X8 = ContainerType<{ + cluster_definition: DefinitionContainerTypeV1X8 + distributed_validators: ListCompositeType +}> + +/** + * @returns SSZ Containerized type of cluster lock + */ +const clusterLockContainerTypeV1X8 = (): LockContainerTypeV1X8 => { + return new ContainerType({ + cluster_definition: clusterDefinitionContainerTypeV1X8(false), + distributed_validators: new ListCompositeType(dvContainerTypeV1X8, 65536), + }) +} + +/** + * @param cluster The published cluster lock + * @returns The lock hash in of the corresponding cluster + */ +export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { + const lockType = clusterLockContainerTypeV1X8() + + const val = lockType.defaultValue() + + // Check if we can replace with definition_hash + val.cluster_definition = hashClusterDefinitionV1X8( + cluster.cluster_definition, + false, + ) + val.distributed_validators = cluster.distributed_validators.map(dValidator => { + return { + distributed_public_key: fromHexString(dValidator.distributed_public_key), + public_shares: dValidator.public_shares.map(publicShare => + fromHexString(publicShare), + ), + // should be fixed + partial_deposit_data: (dValidator.partial_deposit_data as DepositData[]).map(depositData => { + return { + pubkey: fromHexString(depositData.pubkey), + withdrawal_credentials: fromHexString( + depositData.withdrawal_credentials, + ), + amount: parseInt(depositData.amount), + signature: fromHexString(depositData.signature), + } + }), + builder_registration: { + message: { + fee_recipient: fromHexString( + dValidator.builder_registration?.message.fee_recipient as string, + ), + gas_limit: dValidator.builder_registration?.message.gas_limit as number, + timestamp: dValidator.builder_registration?.message.timestamp as number, + pubkey: fromHexString(dValidator.builder_registration?.message.pubkey as string), + }, + signature: fromHexString(dValidator.builder_registration?.signature as string), + }, + } + }) + + return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex') +} + +// DV verification +export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => { + const validators = clusterLock.distributed_validators + const pubShares = [] + const pubKeys = [] + const builderRegistrationAndDepositDataMessages = [] + const blsSignatures = [] + + for (let i = 0; i < validators.length; i++) { + const validator = validators[i] + const validatorPublicShares = validator.public_shares + const distributedPublicKey = validator.distributed_public_key + + // Needed in signature_aggregate verification + for (const element of validatorPublicShares) { + pubShares.push(fromHexString(element)) + } + + // Deposit Data Verification + for (let j = 0; j < (validator.partial_deposit_data as DepositData[]).length; j++) { + const depositData = (validator.partial_deposit_data as DepositData[])[i] + const { isValidDepositData, depositDataMsg } = verifyDepositData( + distributedPublicKey, + depositData as Partial, + clusterLock.cluster_definition.validators[i].withdrawal_address, + clusterLock.cluster_definition.fork_version + ) + + if ( + !isValidDepositData + ) { + return false + } + + pubKeys.push(fromHexString(distributedPublicKey)) + builderRegistrationAndDepositDataMessages.push(depositDataMsg) + blsSignatures.push(fromHexString(depositData?.signature)) + } + + // Builder Registration Verification + const { isValidBuilderRegistration, builderRegistrationMsg } = verifyBuilderRegistration( + validator, + clusterLock.cluster_definition.validators[i].fee_recipient_address, + clusterLock.cluster_definition.fork_version + ) + + if ( + !isValidBuilderRegistration + ) { + return false + } + + pubKeys.push(fromHexString(distributedPublicKey)) + builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg) + blsSignatures.push( + fromHexString(validator.builder_registration?.signature as string), + ) + } + + // BLS signatures verification + const aggregateBLSSignature = aggregateSignatures(blsSignatures) + + if ( + !verifyMultiple( + pubKeys, + builderRegistrationAndDepositDataMessages, + aggregateBLSSignature, + ) + ) { + return false + } + + // Node Signatures verification + if ( + !verifyNodeSignatures( + clusterLock + ) + ) { + return false + } + + // signature_aggregate verification + if ( + !verifyAggregate( + pubShares, + fromHexString(clusterLock.lock_hash), + fromHexString(clusterLock.signature_aggregate), + ) + ) { + return false + } + + return true +} diff --git a/src/verify.ts b/src/verify.ts deleted file mode 100644 index 234539d..0000000 --- a/src/verify.ts +++ /dev/null @@ -1,494 +0,0 @@ -import * as semver from 'semver' -import { - init, - aggregateSignatures, - verifyMultiple, - verifyAggregate, -} from '@chainsafe/bls' -import { ENR } from '@chainsafe/discv5' -import { ByteVectorType, ContainerType, fromHexString } from '@chainsafe/ssz' -import { - type UintNumberByteLen, - UintNumberType, -} from '@chainsafe/ssz/lib/type/uint.js' -import { SignTypedDataVersion, TypedDataUtils } from '@metamask/eth-sig-util' -import elliptic from 'elliptic' -import { ethers } from 'ethers' - -import { - type BuilderRegistrationMessage, - type ClusterDefintion, - type ClusterLock, - type DepositData, - type DistributedValidator, - FORK_MAPPING, -} from './types.js' -import { clusterConfigOrDefinitionHash, clusterLockHash } from './hash.js' -import { - DOMAIN_APPLICATION_BUILDER, - DOMAIN_DEPOSIT, - DefinitionFlow, - GENESIS_VALIDATOR_ROOT, - signCreatorConfigHashPayload, - signEnrPayload, - signOperatorConfigHashPayload, -} from './constants.js' -import { hexWithout0x } from './utils.js' - -const builderRegistrationMessageType = new ContainerType({ - fee_recipient: new ByteVectorType(20), - gas_limit: new UintNumberType(8 as UintNumberByteLen), - timestamp: new UintNumberType(8 as UintNumberByteLen), - pubkey: new ByteVectorType(48), -}) - -// For domain computation that is used in deposit data and builder registration verification for dv -const forkDataType = new ContainerType({ - currentVersion: new ByteVectorType(4), - genesisValidatorsRoot: new ByteVectorType(32), -}) - -const depositMessageType = new ContainerType({ - pubkey: new ByteVectorType(48), - withdrawal_credentials: new ByteVectorType(32), - amount: new UintNumberType(8), -}) - -const signingRootType = new ContainerType({ - objectRoot: new ByteVectorType(32), - domain: new ByteVectorType(32), -}) - -const definitionFlow = ( - clusterDefinition: ClusterDefintion, -): DefinitionFlow | null => { - if ( - clusterDefinition.creator.address && - clusterDefinition.creator.config_signature && - clusterDefinition.operators.every((operator) => { - return ( - operator.address && - operator.config_signature && - operator.enr && - operator.enr_signature - ) - }) - ) { - return DefinitionFlow.Group - } else if ( - clusterDefinition.creator.address && - clusterDefinition.creator.config_signature && - clusterDefinition.operators.every((operator) => { - return ( - !operator.address && - !operator.config_signature && - operator.enr && - !operator.enr_signature - ) - }) - ) { - return DefinitionFlow.Solo - } else if ( - !clusterDefinition.creator.address && - !clusterDefinition.creator.config_signature && - clusterDefinition.operators.every((operator) => { - return ( - !operator.address && - !operator.config_signature && - operator.enr && - !operator.enr_signature - ) - }) - ) { - return DefinitionFlow.Charon - } - return null -} - -// cluster-definition signatures verificatin - -const getPOSTConfigHashSigner = ( - signature: string, - configHash: string, - chainId: FORK_MAPPING, -): string => { - try { - const sig = ethers.Signature.from(signature) - const data = signCreatorConfigHashPayload( - { creator_config_hash: configHash }, - chainId, - ) - const digest = TypedDataUtils.eip712Hash(data, SignTypedDataVersion.V4) - - return ethers.recoverAddress(digest, sig).toLowerCase() - } catch (err) { - throw err - } -} - -const getPUTConfigHashSigner = ( - signature: string, - configHash: string, - chainId: number, -): string => { - try { - const sig = ethers.Signature.from(signature) - const data = signOperatorConfigHashPayload( - { operator_config_hash: configHash }, - chainId, - ) - const digest = TypedDataUtils.eip712Hash(data, SignTypedDataVersion.V4) - - return ethers.recoverAddress(digest, sig).toLowerCase() - } catch (err) { - throw err - } -} - -const getEnrSigner = ( - signature: string, - payload: string, - chainId: number, -): string => { - try { - const sig = ethers.Signature.from(signature) - - const data = signEnrPayload({ enr: payload }, chainId) - const digest = TypedDataUtils.eip712Hash(data, SignTypedDataVersion.V4) - - return ethers.recoverAddress(digest, sig).toLowerCase() - } catch (err) { - throw err - } -} - -const verifyDefinitionSignatures = ( - clusterDefinition: ClusterDefintion, - definitionType: DefinitionFlow, -): boolean => { - if (definitionType === 'Charon-Command') { - return true - } else { - const configSigner = getPOSTConfigHashSigner( - clusterDefinition.creator.config_signature as string, - clusterDefinition.config_hash, - FORK_MAPPING[clusterDefinition.fork_version as keyof typeof FORK_MAPPING], - ) - - if (configSigner !== clusterDefinition.creator.address.toLowerCase()) { - return false - } - if (definitionType === 'LP-Solo') { - return true - } - return clusterDefinition.operators.every((operator) => { - const configSigner = getPUTConfigHashSigner( - operator.config_signature as string, - clusterDefinition.config_hash, - FORK_MAPPING[ - clusterDefinition.fork_version as keyof typeof FORK_MAPPING - ], - ) - - const enrSigner = getEnrSigner( - operator.enr_signature as string, - operator.enr as string, - FORK_MAPPING[ - clusterDefinition.fork_version as keyof typeof FORK_MAPPING - ], - ) - - if ( - configSigner !== operator.address.toLowerCase() || - enrSigner !== operator.address.toLowerCase() - ) { - return false - } - return true - }) - } -} - -// cluster-lock data verification -const computeSigningRoot = ( - sszObjectRoot: Uint8Array, - domain: Uint8Array, -): Uint8Array => { - const val1 = signingRootType.defaultValue() - val1.objectRoot = sszObjectRoot - val1.domain = domain - return Buffer.from(signingRootType.hashTreeRoot(val1).buffer) -} - -const computeDepositMsgRoot = (msg: Partial): Buffer => { - const depositMsgVal = depositMessageType.defaultValue() - - depositMsgVal.pubkey = fromHexString(msg.pubkey as string) - depositMsgVal.withdrawal_credentials = fromHexString( - msg.withdrawal_credentials as string, - ) - depositMsgVal.amount = parseInt(msg.amount as string) - return Buffer.from(depositMessageType.hashTreeRoot(depositMsgVal).buffer) -} - -const computeForkDataRoot = ( - currentVersion: Uint8Array, - genesisValidatorsRoot: Uint8Array, -): Uint8Array => { - const forkDataVal = forkDataType.defaultValue() - forkDataVal.currentVersion = currentVersion - forkDataVal.genesisValidatorsRoot = genesisValidatorsRoot - return Buffer.from(forkDataType.hashTreeRoot(forkDataVal).buffer) -} - -const computebuilderRegistrationMsgRoot = ( - msg: BuilderRegistrationMessage, -): Buffer => { - const builderRegistrationMsgVal = - builderRegistrationMessageType.defaultValue() - - builderRegistrationMsgVal.fee_recipient = fromHexString(msg.fee_recipient) - builderRegistrationMsgVal.gas_limit = msg.gas_limit - builderRegistrationMsgVal.timestamp = msg.timestamp - builderRegistrationMsgVal.pubkey = fromHexString(msg.pubkey) - return Buffer.from( - builderRegistrationMessageType.hashTreeRoot(builderRegistrationMsgVal) - .buffer, - ) -} - -// DV data verification -const computeDomain = ( - domainType: Uint8Array, - lockForkVersion: string, - genesisValidatorsRoot: Uint8Array = fromHexString(GENESIS_VALIDATOR_ROOT), -): Uint8Array => { - const forkVersion = fromHexString( - lockForkVersion.substring(2, lockForkVersion.length), - ) - - const forkDataRoot = computeForkDataRoot(forkVersion, genesisValidatorsRoot) - const domain = new Uint8Array(32) - domain.set(domainType) - domain.set(forkDataRoot.subarray(0, 28), 4) - return domain -} - -const verifyDepositData = ( - validator: DistributedValidator, - withdrawalAddress: string, -): boolean => { - const eth1AddressWithdrawalPrefix = '0x01' - if ( - eth1AddressWithdrawalPrefix + - '0'.repeat(22) + - withdrawalAddress.toLowerCase().slice(2) !== - validator.deposit_data.withdrawal_credentials - ) { - return false - } - - if (validator.distributed_public_key !== validator.deposit_data.pubkey) { - return false - } - - return true -} - -const verifyBuilderRegistration = ( - validator: DistributedValidator, - feeRecipientAddress: string, -): boolean => { - if ( - validator.distributed_public_key !== - validator.builder_registration.message.pubkey - ) { - return false - } - if ( - feeRecipientAddress.toLowerCase() !== - validator.builder_registration.message.fee_recipient.toLowerCase() - ) { - return false - } - - return true -} - -export const signingRoot = ( - domain: Uint8Array, - messageBuffer: Buffer, -): Uint8Array => { - return computeSigningRoot(messageBuffer, domain) -} - -const verifyLockData = async (clusterLock: ClusterLock): Promise => { - const ec = new elliptic.ec('secp256k1') - const validators = clusterLock.distributed_validators - const nodeSignatures = clusterLock.node_signatures - const depositDomain = computeDomain( - fromHexString(DOMAIN_DEPOSIT), - clusterLock.cluster_definition.fork_version, - ) - const builderDomain = computeDomain( - fromHexString(DOMAIN_APPLICATION_BUILDER), - clusterLock.cluster_definition.fork_version, - ) - - const pubShares = [] - const pubKeys = [] - const builderRegistrationAndDepositDataMessages = [] - const blsSignatures = [] - - await init('herumi') - - for (let i = 0; i < validators.length; i++) { - const validator = validators[i] - const validatorPublicShares = validator.public_shares - - for (const element of validatorPublicShares) { - pubShares.push(fromHexString(element)) - } - - // Deposit data signature - if (semver.gte(clusterLock.cluster_definition.version, 'v1.6.0')) { - if ( - !verifyDepositData( - validator, - clusterLock.cluster_definition.validators[i].withdrawal_address, - ) - ) { - return false - } - - const depositMessageBuffer = computeDepositMsgRoot(validator.deposit_data) - const depositDataMessage = signingRoot( - depositDomain, - depositMessageBuffer, - ) - - pubKeys.push(fromHexString(validator.distributed_public_key)) - builderRegistrationAndDepositDataMessages.push(depositDataMessage) - blsSignatures.push(fromHexString(validator.deposit_data.signature as string)) - } - - // Builder registration signature - if (semver.gte(clusterLock.cluster_definition.version, 'v1.7.0')) { - if ( - !verifyBuilderRegistration( - validator, - clusterLock.cluster_definition.validators[i].fee_recipient_address, - ) - ) { - return false - } - - const builderRegistrationMessageBuffer = - computebuilderRegistrationMsgRoot( - validator.builder_registration.message, - ) - - const builderRegistrationMessage = signingRoot( - builderDomain, - builderRegistrationMessageBuffer, - ) - - pubKeys.push(fromHexString(validator.distributed_public_key)) - builderRegistrationAndDepositDataMessages.push(builderRegistrationMessage) - blsSignatures.push( - fromHexString(validator.builder_registration.signature), - ) - } - } - - if ( - blsSignatures.length > 0 && - pubKeys.length > 0 && - builderRegistrationAndDepositDataMessages.length > 0 - ) { - // verify all deposit data and builder registration bls signatures - const aggregateBLSSignature = aggregateSignatures(blsSignatures) - - if ( - !verifyMultiple( - pubKeys, - builderRegistrationAndDepositDataMessages, - aggregateBLSSignature, - ) - ) { - return false - } - } - - if (semver.gte(clusterLock.cluster_definition.version, 'v1.7.0')) { - const lockHashWithout0x = hexWithout0x(clusterLock.lock_hash) - // node(ENR) signatures - for (let i = 0; i < nodeSignatures.length; i++) { - const pubkey = ENR.decodeTxt( - clusterLock.cluster_definition.operators[i].enr as string, - ).publicKey.toString('hex') - - const ENRsignature = { - r: nodeSignatures[i].slice(2, 66), - s: nodeSignatures[i].slice(66, 130), - } - - const nodeSignatureVerification = ec - .keyFromPublic(pubkey, 'hex') - .verify(lockHashWithout0x, ENRsignature) - - if (!nodeSignatureVerification) { - return false - } - } - } - - // signature aggregate - if ( - !verifyAggregate( - pubShares, - fromHexString(clusterLock.lock_hash), - fromHexString(clusterLock.signature_aggregate), - ) - ) { - return false - } - - return true -} - -export const isValidClusterLock = async ( - clusterLock: ClusterLock, -): Promise => { - try { - const definitionType = definitionFlow(clusterLock.cluster_definition) - if (definitionType == null) { - return false - } - const isValidDefinitionData = verifyDefinitionSignatures( - clusterLock.cluster_definition, - definitionType, - ) - if (!isValidDefinitionData) { - return false - } - - if ( - clusterConfigOrDefinitionHash(clusterLock.cluster_definition, false) !== - clusterLock.cluster_definition.definition_hash - ) { - return false - } - if (clusterLockHash(clusterLock) !== clusterLock.lock_hash) { - return false - } - - const isValidLockData = await verifyLockData(clusterLock) - if (!isValidLockData) { - return false - } - return true - } catch (err) { - return false - } -} diff --git a/test/fixtures.ts b/test/fixtures.ts index 12ca763..fd815c5 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,3 +1,112 @@ +export const enr = + 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak' + +// v1.6.0 +export const clusterLockV1X6 = { + cluster_definition: { + name: 'test v.1.6', + creator: { + address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', + config_signature: + '0x705534bdce89175379a6c0e346d93adc1bfa41552bcb5cecfcc7b20c0663c6c1188aa09352b9085b2c7c0644d4506838234eebbbacba3caac2f6c227de050a821c', + }, + operators: [ + { + address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', + enr: 'enr:-Iu4QCdreXm-iHrd2Y-QgLAHeGAkQSrZNvfPL-l6IuGEuKoMHnZsg93EgIWWOtcBzKs_-skexEKvY3CmcJ8SOzMIGMiAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQL4r6dX8heIruf3OW_hfcctLtsaX8roj8E-8s0-IpH9rYN0Y3CCDhqDdWRwgg4u', + config_signature: + '0xbcbec314ce8a54c784069006dc23dd897696402487bdae982601ca1fdbc565af35a7d2e682f6051b3fe1c90f51ee5f908bec4d6a3ba0c29068316c85538d5e041c', + enr_signature: + '0x1dc963f01eb794170e35a972ec8b487bdea2e3c1acbbe2fc2ab7936e7fe99e407583489a7dff3fbb08f4902e77867d795a7196a83d91b0a0eb8e50b8d96d35ba1c', + }, + { + address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81', + enr: 'enr:-Iu4QNbiUUUwT18LynBbVPJhNxvzQsaSpUr40mQTWscnZaqKb6vAlvV8j-eDDR3E0wjMQumGRbGm2IAb5_k4bVWJiVGAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPOiodUji0ohgJb5sNK1hgv8g6xO5_znZz3NkkBkyYyKIN0Y3CCDhqDdWRwgg4u', + config_signature: + '0xb95ccbca31a648a642ab2e273a0d66743921f0e9c67a5122fc229f0898ca4a1e7ac0b5b8698dfc6f3eccad7000f5aabc53666cd8b4cc7272abeb3f407571ac111c', + enr_signature: + '0xb580f1380a62d299587357181561c8db8d67f4cc92d094b2ca3c84eddde3759567cfe60669b30ef55308a749c3c6a32f52148ac6b667cc6554f63a04c55350451b', + }, + { + address: '0x33807D6F1DCe44b9C599fFE03640762A6F08C496', + enr: 'enr:-Iu4QJyserRukhG0Vgi2csu7GjpHYUGufNEbZ8Q7ZBrcZUb0KqpL5QzHonkh1xxHlxatTxrIcX_IS5J3SEWR_sa0ptGAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQMAUgEqczOjevyculnUIofhCj0DkgJudErM7qCYIvIkzIN0Y3CCDhqDdWRwgg4u', + config_signature: + '0x59f7173b7f7eaa6f9a3619b508241ae4b8788ce64b23554eb2057b15d1570ed56ed25fd9d98321ffb6b30f119b8802f626f3ed78665b9b272e6f650412de37af1c', + enr_signature: + '0xf63195e4238eac6d9deae5ec56626ac16a7a861294587c3ee144853ace76f8a2089980a2cbf17c72a8c5ac0651c6935d023db34fc0be58a91f0c70c26017597a1b', + }, + { + address: '0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f', + enr: 'enr:-HW4QKJTwXC6Chw6zbnA3HFZi6Jo0DkIgjKy4eUBpsSOGnAeWE6ChEjEyk_6R6Qrm7jI-iqfs3_HYxiKde8vFgvHHrCAgmlkgnY0iXNlY3AyNTZrMaECfFKQH4spdZCHqrKVz1Q02xYla6J_RQECDNNYBRWdzv8', + config_signature: + '0x6458cc392ec9824a3713efb7469907b2ba9956b0729d1a080ef86bd092748f294e9a24e9176bfa95975c8426ea94159699df4f54b636708013a24b74483b30d91c', + enr_signature: + '0x05d801705908933b7d1566f48f5726d36874423b1bbdd3f582e08c754220d211492b46ee434f1d1f5bd1507f80f9ca1df569354892e7d2eda87861bc2279be6e1c', + }, + ], + uuid: 'f96771cf-290a-430f-8a8a-f999f5e9d35b', + version: 'v1.6.0', + timestamp: '2023-05-19T14:52:22.655Z', + num_validators: 1, + threshold: 3, + validators: [ + { + fee_recipient_address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', + withdrawal_address: '0x3C75594181e03E8ECD8468A0037F058a9dAfad79', + }, + ], + dkg_algorithm: 'default', + fork_version: '0x00001020', + config_hash: + '0xd50651bc2ae522e3d473a07ebf86c4486de0d479ce8881be0572019cf319a974', + definition_hash: + '0xac4ffb5a5f50bbfafac4e320f52a63f77bf3ced1b78b00b5635f488d9efa8576', + }, + distributed_validators: [ + { + distributed_public_key: + '0xa29529bcf747faedd53b4e1a8f6181ed55fad34f5eb3376ce65d444c0ecf79fab761bcd8607d12ad79f72bae537e6d38', + public_shares: [ + '0x94cfd584f8b1ea26944d4339c19d8552a7fa4326dddc16a9f15a9ea962f2cdc09bf5b58f10f90de95afac218daa2fb93', + '0x95a727a6975e1eaad3504e6252a0840ad042ae0b46e8f7a8139341883e0d6d1e983dbf334a02efea93828daecb9fc9e7', + '0x8c38f9ed7cf995759a60f1d173671e420eb78d763ea139b7f3d5858283f9cbf05e682721330d2c6dc91389fe9db0397b', + '0xa36b7f0d46e29107c70350cb605bd22718c1c8af890dabed7c875e9c0c9f7727eb190b01e04ce16e1c954427ef4e8b56', + ], + deposit_data: { + pubkey: + '0xa29529bcf747faedd53b4e1a8f6181ed55fad34f5eb3376ce65d444c0ecf79fab761bcd8607d12ad79f72bae537e6d38', + withdrawal_credentials: + '0x0100000000000000000000003c75594181e03e8ecd8468a0037f058a9dafad79', + amount: '32000000000', + signature: + '0x8a7ee66acd9d5200c26dd644f3275a2847dd000330d509a9a94f7338c4f38dc7533e2ad70f6a3f10339a2e74a5ac94c518ce62efb8b01eb46f4b44f853d74e194c9eb8c4af34f9a29d3ece7cfdd916c2d6b5013717919e5fe91dd95bd3ae4852', + }, + }, + ], + signature_aggregate: + '0xb7f49e8eaa4015a3118deace6d17c9aef8a495b0ce460b0f1d27423101177000541a9d422fcc4eeedbaaa2497c555d8d0ba7ee882a5eaecfb89e7dcec2f2f3f5df78bc172e03be426c5f0835cbe58dac43e5812de5c21d2755693de2af80f491', + lock_hash: + '0x6d2b38d098143c8f0bc5076f4e9b6081cbba040a5aea6649e6223e7a4131241b', +} + +// v1.7.0 + +export const clusterConfigV1X7 = { + name: 'testSDK', + operators: [ + { address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81' }, + { address: '0x33807D6F1DCe44b9C599fFE03640762A6F08C496' }, + { address: '0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f' }, + { address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC' }, + ], + validators: [ + { + fee_recipient_address: '0x3CD4958e76C317abcEA19faDd076348808424F99', + withdrawal_address: '0xE0C5ceA4D3869F156717C66E188Ae81C80914a6e', + }, + ], +} + export const clusterLockV1X7 = { cluster_definition: { name: 'v1.7.0 group test', @@ -76,8 +185,6 @@ export const clusterLockV1X7 = { amount: '32000000000', signature: '0xae016c6c42daa8d1517d0e10370cf7882b28149635f734c5f3d83f781cd61f5df6d5203ec11bd0ca9d9e51c6030b66330476a93a65de6151d110e0f6482591f53678d863e55392e9cfb55fecac537edac51979790bcde38250a141348f116d46', - deposit_data_root: - 'fbada6c7c4cba867780eead34c1462339795fe9b417db466ce2f9d4822e8a4bb', }, builder_registration: { message: { @@ -104,7 +211,9 @@ export const clusterLockV1X7 = { ], } -export const clusterConfig = { +// v1.8.0 + +export const clusterConfigV1X8 = { name: 'testSDK', operators: [ { address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81' }, @@ -118,4 +227,134 @@ export const clusterConfig = { withdrawal_address: '0xE0C5ceA4D3869F156717C66E188Ae81C80914a6e', }, ], + deposit_amounts: [ + '8000000000', + '16000000000', + '8000000000' + ], +} + +export const clusterLockV1X8 = { + cluster_definition: { + name: 'test cluster', + creator: { + address: '0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c', + config_signature: '0x03b41a12847064090333026a10bc0c6f9c51400e67b414fe74aa7df91388583d6bea930d525478e25d85aa49f3c649723e4158895fadd0e787fe8579d43c18cb00' + }, + operators: [ + { + address: '0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c', + enr: 'enr:-HW4QIHPUOMb34YoizKGhz7nsDNQ7hCaiuwyscmeaOQ04awdH05gDnGrZhxDfzcfHssCDeB-esi99A2RoZia6UaYBCuAgmlkgnY0iXNlY3AyNTZrMaECTUts0TYQMsqb0q652QCqTUXZ6tgKyUIzdMRRpyVNB2Y', + config_signature: '0xffafd355831aa993e5a019419403d61533649edc546b4f497bc305d7620dcb787756f9748be1ea76f7236692faeff7c1d2e7b06bf89894d07518de2d4ff45b4d00', + enr_signature: '0x20b5b4ba720053c6ea35a710cdd9d81440ae3a69c204edb06184ea2328ff3a290bd00c256d71f6f4daed2f995931b38c3f6bd0b17796f4e121278073e049086800' + }, + { + address: '0x3325a78425F17a7E487Eb5666b2bFd93aBb06c70', + enr: 'enr:-HW4QDztNDqgEPAgJoHkcF4LfXyjXUo1r_xYoNv48H0PFItwYx-OnviqgfHxEz51RDOGvUMiTpXyo0HBjK5ZZ8YxS9WAgmlkgnY0iXNlY3AyNTZrMaECUx_mBoE0UD0nIxMyJ8hnrI-myDxTfppEw8W9vcsf4zc', + config_signature: '0x2053ba17731221d4ed919de72010b559a924143f74998c94b71e95cb1fdbe3a05ad0cbdf61cf174ef3509ce86bc03633f5215065d71f93bd15e1e506db71420e00', + enr_signature: '0x9aa50b499754e19b7e30e12d6b2d63abc916edc7810aae9f3427f7d2a3cc33ad10f84d638ccb73817cd6a6eee311a52d45ea24f0d0f5452dc845ef24749e71ca00' + }, + { + address: '0xc48B812bB43401392c037381AcA934F4069C0517', + enr: 'enr:-HW4QGSS-HN3zRfCJGISFmDT59Cpo-daC4U2vSjqPZWegHVSJklFsDs0f1fF_E7X4q8NUbR3bWDlX7IifsjQ_Xrm7QuAgmlkgnY0iXNlY3AyNTZrMaEDRid5rUqtOVFGFHUacQhfLxDhx6WT5OAw77W4chzlWws', + config_signature: '0xa08dcb9c91fe562fb24862ba4ccd8ec881436e5563182d819d0eb1d1e4293ef40fd7e03094f5ed5c5165101cdb009ccab7eee813f01530f4f81a180d11f61cce01', + enr_signature: '0x6ecb15dda256fd34ea09a04db6c140387790d6902509df81fabab3889de4980f30c5d07480b12a0d4f3c6f75f56fe8c0f2b344311e092f53cd959367c5d67f7201' + } + ], + uuid: '8D019192-C242-24E2-CAFC-CAE3A61FB586', + version: 'v1.8.0', + timestamp: '2024-03-07T17:05:34+03:00', + num_validators: 2, + threshold: 3, + validators: [ + { + fee_recipient_address: '0x52fdfc072182654f163f5f0f9a621d729566c74d', + withdrawal_address: '0x81855ad8681d0d86d1e91e00167939cb6694d2c4' + }, + { + fee_recipient_address: '0xeb9d18a44784045d87f3c67cf22746e995af5a25', + withdrawal_address: '0x5fb90badb37c5821b6d95526a41a9504680b4e7c' + } + ], + dkg_algorithm: 'frost', + fork_version: '0x00001020', + deposit_amounts: [ + '8000000000', + '16000000000', + '8000000000' + ], + config_hash: '0xe604bdf1649e2bcc5399149d4a683feacfc5678abe990d75e202791984208c53', + definition_hash: '0x123be6c24ec74366b0a318de42d36e09a43a08c3db72800698a958510c804a0b' + }, + distributed_validators: [ + { + distributed_public_key: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', + public_shares: [ + '0x804841f5b773b7cda35f2ceaacbd7b52afba38b6d65d5c4b3b1d3cdc905c21c0f7d1ac18cd4847b0cf56ac7ed41d5c19', + '0xac2362cbfdd573137a5f46727981363198c8a8b66eb29123014f3e1dee335132973973bddb4a4c592c8c74ff270b5982', + '0xb63dd0fb59a513b0f9f10ed3d88a54aa72c189faf2c2d2e4d66a81730a81a89d6feac0ff8e7b6b488c5131aa33845b47' + ], + builder_registration: { + message: { + fee_recipient: '0x52fdfc072182654f163f5f0f9a621d729566c74d', + gas_limit: 30000000, + timestamp: 1616508000, + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7' + }, + signature: '0x8a8085f002d0332c689baef8ecbab1ca3632e2536fa9f0587212f50429a4617d1cac1722b55d521ffb58424f6bc4f9640bdd1994e9abaff1fe00ea641aabf89249a8ed64aee5f7508a78dc9a6e2fa626cc707e5f9f94b9634084ea825c082b79' + }, + partial_deposit_data: [ + { + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', + withdrawal_credentials: '0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4', + amount: '8000000000', + signature: '0x84614b278beed177d17f8e61ec6c4c4c17fb41adde71dedb5977ce19354a4ec24bed65021109d7d690d014fc531cf7040b3285877c8bfc35b1a2dd64fdbcab086132982fb036c31071824ea9ec6ca28ff6aaf86a425350c2bec8012b399342eb' + }, + { + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', + withdrawal_credentials: '0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4', + amount: '16000000000', + signature: '0xac5bcb369e8dde110604f6ae829a3432f82a99b0a996e15f4be6426acbe690a1aadb4b365d8b10a36737b2cd8c7f561214d4e4df3626cc9664f663111d15efbd8d18cffff5c3eff407fe2cc478244caea7f9f2afee83a0ae8aa2587365b8e54a' + } + ] + }, + { + distributed_public_key: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', + public_shares: [ + '0x898c28241cb2386fdbfa26ee08fcc804ee953695741691d4f8c45a36f08dd319a09173a9ef632eb7a35f94ff9241cd8e', + '0xb7d73b8ea0d74dc7eb70f305c6666dd9dca749ea1084b25f942e0d0909211f6556c2955266a7ff54a204146676bf1c8c', + '0x8fbe3bb3c23e9dcb093ee45a28efc120ee2a923d4c62a0377d0a6ed7a3da8fa185456bbaec41e13fd84a2a410023a742' + ], + builder_registration: { + message: { + fee_recipient: '0xeb9d18a44784045d87f3c67cf22746e995af5a25', + gas_limit: 30000000, + timestamp: 1616508000, + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a' + }, + signature: '0xa941fcec27add0165a1bd76bb4b5d3a5f4e96e0e7b9a9edad4188dda914b97519c71f5964a467061cfee91f317eaa321174d5dbd8e94a6486c62e8bd10aad6ead7494696e2926b68fea446b9d868abde763a177083e87921d5e1b09c6b2aec2a' + }, + partial_deposit_data: [ + { + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', + withdrawal_credentials: '0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c', + amount: '8000000000', + signature: '0x88b20e744a83679da4df81416358214f1e62535498b9ac38eb622b01cad2090554b2f1f7b3ac9032c15ccd31fffbb1cf0f5589b7703ecc4441e5bd7bf7c388ac1423c41b5c76cbee9969ffade054edcd1a883f80df813b52786393d318db007b' + }, + { + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', + withdrawal_credentials: '0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c', + amount: '16000000000', + signature: '0x94d9db7b4527e6eb308d387f168089a51d1deffc2c985faf1f7f8e82fbc9cb93c7f10c6a7bbca4fc25a1cfc95de28432037cf7727c1db0ad6d1fb0f1813d5904fba4ab8aebfeccfcded2f915bd48fb46155131b24adb0ba5e764d7ff6d3c82a5' + } + ] + } + ], + signature_aggregate: '0xb54fc9fcfe6827f519a29ff0a8bc9a06aafd197253a6def9f45bf79b023e71f3bd26bd0365f0beb7d60c1146e33be127161eb034af4a4de619e9d6971174224fdc18c04821d9e5b7abaeaedc01755b6e33addb2dc820aa361890a634a0252422', + lock_hash: '0x1f598e309b715ba0141034b495975e3bed0231ad92da49dfff462765049df671', + node_signatures: [ + '0xf4317dc1f01738f84b2624866e8b4e85e92394fabb49218ef8a6dfe7ee4fdaab015742379328b173204504332a5e15450d5a127bbe8b8a2209cd9fa12b85cf4501', + '0x9e4726f7cce4cfad963eb04aaeec677fa7d1010d66640867d0ee11c75fad45dd6ad8fad9ad4a3c042bd1ab298a5598896b9de08acfde476f9aa65c48e3def7f901', + '0x54a89155ef4a6e319c0411f29963554fe551abce6d8463661cc5449a67243d053292f0190432cdcbcfc6e651815b093d55b4adbfc8c82f85ee1e1af798d9bae400' + ] } diff --git a/test/methods.test.ts b/test/methods.test.ts index c6b3777..91b4a65 100644 --- a/test/methods.test.ts +++ b/test/methods.test.ts @@ -1,6 +1,6 @@ import { ethers } from 'ethers' import { Client, validateClusterLock } from '../src/index' -import { clusterConfig, clusterLockV1X7 } from './fixtures.js' +import { clusterConfigV1X7, clusterLockV1X6, clusterLockV1X7, clusterLockV1X8 } from './fixtures.js' import { SDK_VERSION } from '../src/constants' import { Base } from '../src/base' import { validatePayload } from '../src/ajv' @@ -35,7 +35,7 @@ describe('Cluster Client', () => { .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) const configHash = - await clientInstance.createClusterDefinition(clusterConfig) + await clientInstance.createClusterDefinition(clusterConfigV1X7) expect(configHash).toEqual(mockConfigHash) }) @@ -60,7 +60,7 @@ describe('Cluster Client', () => { .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) try { await clientInstance.createClusterDefinition({ - ...clusterConfig, + ...clusterConfigV1X7, operators: [], }) } catch (error: any) { @@ -72,7 +72,7 @@ describe('Cluster Client', () => { test('validatePayload should throw an error on empty schema', async () => { try { - validatePayload({ ...clusterConfig, operators: [] }, '') + validatePayload({ ...clusterConfigV1X7, operators: [] }, '') } catch (error: any) { expect(error.message).toEqual('schema must be object or boolean') } @@ -86,6 +86,7 @@ describe('Cluster Client', () => { const clusterDefinition = await clientInstance.getClusterDefinition( clusterLockV1X7.cluster_definition.config_hash, ) + expect(clusterDefinition.config_hash).toEqual( clusterLockV1X7.cluster_definition.config_hash, ) @@ -139,7 +140,7 @@ describe('Cluster Client without a signer', () => { test('createClusterDefinition should throw an error without signer', async () => { try { - await clientInstance.createClusterDefinition(clusterConfig) + await clientInstance.createClusterDefinition(clusterConfigV1X7) } catch (err: any) { expect(err.message).toEqual('Signer is required in createClusterDefinition') } @@ -183,8 +184,10 @@ describe('Cluster Client without a signer', () => { expect(clusterLock.lock_hash).toEqual(clusterLockV1X7.lock_hash) }) - it('should return true on verified cluster lock', async () => { - const isValidLock: boolean = await validateClusterLock(clusterLockV1X7) - expect(isValidLock).toEqual(true) - }) + test.each([{ version: 'v1.6.0', clusterLock: clusterLockV1X6 }, { version: 'v1.7.0', clusterLock: clusterLockV1X7 }, { version: 'v1.8.0', clusterLock: clusterLockV1X8 }])( + '$version: \'should return true on verified cluster lock\'', + async ({ clusterLock }) => { + const isValidLock: boolean = await validateClusterLock(clusterLock) + expect(isValidLock).toEqual(true) + }) }) diff --git a/test/sdk-package-test/cluster.test.ts b/test/sdk-package-test/cluster.test.ts index c5f8fbb..13c111c 100755 --- a/test/sdk-package-test/cluster.test.ts +++ b/test/sdk-package-test/cluster.test.ts @@ -1,6 +1,6 @@ import request from 'supertest' import dotenv from 'dotenv' -import { clusterConfig, clusterLockV1X7, enr } from './fixtures' +import { clusterConfigV1X7, clusterLockV1X6, clusterLockV1X7, clusterLockV1X8, enr } from './../fixtures' import { client, updateClusterDef, @@ -27,12 +27,12 @@ describe('Cluster Definition', () => { let clusterDefinition: ClusterDefintion let secondConfigHash: string const clientWithoutAsigner = new Client({ - baseUrl: 'https://obol-api-dev.gcp.obol.tech', + baseUrl: 'https://obol-api-nonprod-dev.dev.obol.tech', chainId: 17000, }) beforeAll(async () => { - configHash = await client.createClusterDefinition(clusterConfig) + configHash = await client.createClusterDefinition(clusterConfigV1X7) }) it('should post a cluster definition and return confighash', async () => { @@ -41,7 +41,7 @@ describe('Cluster Definition', () => { it('should throw on post a cluster without a signer', async () => { try { - await clientWithoutAsigner.createClusterDefinition(clusterConfig) + await clientWithoutAsigner.createClusterDefinition(clusterConfigV1X7) } catch (err: any) { expect(err.message).toEqual('Signer is required in createClusterDefinition') } @@ -71,9 +71,9 @@ describe('Cluster Definition', () => { it('should update the cluster which the operator belongs to', async () => { const signerAddress = await signer.getAddress() - clusterConfig.operators.push({ address: signerAddress }) + clusterConfigV1X7.operators.push({ address: signerAddress }) - secondConfigHash = await client.createClusterDefinition(clusterConfig) + secondConfigHash = await client.createClusterDefinition(clusterConfigV1X7) const definitionData: ClusterDefintion = await client.acceptClusterDefinition( @@ -111,7 +111,7 @@ describe('Poll Cluster Lock', () => { const { definition_hash: _, ...rest } = clusterLockV1X7.cluster_definition const clusterWithoutDefHash = rest const clientWithoutAsigner = new Client({ - baseUrl: 'https://obol-api-dev.gcp.obol.tech', + baseUrl: 'https://obol-api-nonprod-dev.dev.obol.tech', chainId: 17000, }) @@ -192,10 +192,12 @@ describe('Poll Cluster Lock', () => { ) }) - it('should return true on verified cluster lock', async () => { - const isValidLock: boolean = await validateClusterLock(clusterLockV1X7) - expect(isValidLock).toEqual(true) - }) + test.each([{ version: 'v1.6.0', clusterLock: clusterLockV1X6 }, { version: 'v1.7.0', clusterLock: clusterLockV1X7 }, { version: 'v1.8.0', clusterLock: clusterLockV1X8 }])( + '$version: \'should return true on verified cluster lock\'', + async ({ clusterLock }) => { + const isValidLock: boolean = await validateClusterLock(clusterLock) + expect(isValidLock).toEqual(true) + }) afterAll(async () => { const configHash = clusterLockV1X7.cluster_definition.config_hash diff --git a/test/sdk-package-test/fixtures.ts b/test/sdk-package-test/fixtures.ts deleted file mode 100644 index 631e836..0000000 --- a/test/sdk-package-test/fixtures.ts +++ /dev/null @@ -1,124 +0,0 @@ -export const clusterLockV1X7 = { - cluster_definition: { - name: 'v1.7.0 group test', - creator: { - address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', - config_signature: - '0x269aefc773de5fbfe41001cbd160b62747a27d76a92c8a6a7eae19d0f172c4b44d445ee0992e1ba6e271740a59051bf9cd8fda4042572bde75e40e8d28f7e6561b', - }, - operators: [ - { - address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', - enr: 'enr:-Iu4QCdreXm-iHrd2Y-QgLAHeGAkQSrZNvfPL-l6IuGEuKoMHnZsg93EgIWWOtcBzKs_-skexEKvY3CmcJ8SOzMIGMiAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQL4r6dX8heIruf3OW_hfcctLtsaX8roj8E-8s0-IpH9rYN0Y3CCDhqDdWRwgg4u', - config_signature: - '0x73bc8d23dee307a02791339300b6405573e686c22222d6e6c8fe349f52bb8c0620ea1ed476fe569ed8c8d21751893216b248eb28dd4de7aa263a234efe3129181b', - enr_signature: - '0x1dc963f01eb794170e35a972ec8b487bdea2e3c1acbbe2fc2ab7936e7fe99e407583489a7dff3fbb08f4902e77867d795a7196a83d91b0a0eb8e50b8d96d35ba1c', - }, - { - address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81', - enr: 'enr:-Iu4QNbiUUUwT18LynBbVPJhNxvzQsaSpUr40mQTWscnZaqKb6vAlvV8j-eDDR3E0wjMQumGRbGm2IAb5_k4bVWJiVGAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPOiodUji0ohgJb5sNK1hgv8g6xO5_znZz3NkkBkyYyKIN0Y3CCDhqDdWRwgg4u', - config_signature: - '0x0ab6f58c612cd0c6af395769132fccc5c0804fd40cc395ae7ab2069a7aedb2884f2fa07a91eee57e13c3407dbeeb81b2256312d14006bdb1c19d4206b66899a41c', - enr_signature: - '0xb580f1380a62d299587357181561c8db8d67f4cc92d094b2ca3c84eddde3759567cfe60669b30ef55308a749c3c6a32f52148ac6b667cc6554f63a04c55350451b', - }, - { - address: '0x33807D6F1DCe44b9C599fFE03640762A6F08C496', - enr: 'enr:-Iu4QJyserRukhG0Vgi2csu7GjpHYUGufNEbZ8Q7ZBrcZUb0KqpL5QzHonkh1xxHlxatTxrIcX_IS5J3SEWR_sa0ptGAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQMAUgEqczOjevyculnUIofhCj0DkgJudErM7qCYIvIkzIN0Y3CCDhqDdWRwgg4u', - config_signature: - '0x6f4f030aedba854cc4fa626171038e0125a93b3c3017af932d5b2a159076d0e17c1641f28cb58c29039e2c33074dd729c3198253ea17cc38074274f5e13676441b', - enr_signature: - '0xf63195e4238eac6d9deae5ec56626ac16a7a861294587c3ee144853ace76f8a2089980a2cbf17c72a8c5ac0651c6935d023db34fc0be58a91f0c70c26017597a1b', - }, - { - address: '0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f', - enr: 'enr:-HW4QKJTwXC6Chw6zbnA3HFZi6Jo0DkIgjKy4eUBpsSOGnAeWE6ChEjEyk_6R6Qrm7jI-iqfs3_HYxiKde8vFgvHHrCAgmlkgnY0iXNlY3AyNTZrMaECfFKQH4spdZCHqrKVz1Q02xYla6J_RQECDNNYBRWdzv8', - config_signature: - '0x8c09f7163c20cd0a2d28cb4fbfda22e93bc53bc537f6143407065922a25e40ab39f52b232ecb9241b3e1674f87a16d263181a17a80de55fb92b9659211428b581b', - enr_signature: - '0x05d801705908933b7d1566f48f5726d36874423b1bbdd3f582e08c754220d211492b46ee434f1d1f5bd1507f80f9ca1df569354892e7d2eda87861bc2279be6e1c', - }, - ], - uuid: 'a1d642aa-07ed-4d48-9eda-0e70cb4bb03f', - version: 'v1.7.0', - timestamp: '2023-07-18T10:36:04.505Z', - num_validators: 1, - threshold: 3, - validators: [ - { - fee_recipient_address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', - withdrawal_address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', - }, - ], - dkg_algorithm: 'default', - fork_version: '0x00001020', - config_hash: - '0x4c3e37cbdb2fb850150f6e112c4ea03cdc388bff059081182659b3407183b431', - definition_hash: - '0xe7bf484f38a45c96e9a3fac60d3e39b88eeb9979fad983e06b0ec90e90aa20b3', - }, - distributed_validators: [ - { - distributed_public_key: - '0xb61b17f3b6425eb2636bc6378de0ed8aab918c3346b59d297828e7c74643d51e80edc2b41290c568614cfb80d2b0be34', - public_shares: [ - '0xab6c1448221f664c145a4a574302fd4419ccfe1178487b2fa4629ee9fc2999c43188c96a52ad795074124a7eb0f63841', - '0x8a2a265fbe9854b1532be335272717a5650e19ecc4d6ea54ed8d8d239200f5b860e5710f7a3b9f5d8a100782cbaf4ede', - '0xa8a0aaf1119afe1c2b21d7dbf18bbe107586dc49028d285886c2e7f2bcf3f1c6817fff1250f4a4a370229a0266ea9bff', - '0x93f62a042d304bbb316761712f5a39a9d549c71275e5d891afa3688b9224ebfa3bfd22f8b76f31d8ad88f65812b27dc3', - ], - deposit_data: { - pubkey: - '0xb61b17f3b6425eb2636bc6378de0ed8aab918c3346b59d297828e7c74643d51e80edc2b41290c568614cfb80d2b0be34', - withdrawal_credentials: - '0x01000000000000000000000086b8145c98e5bd25ba722645b15ed65f024a87ec', - amount: '32000000000', - signature: - '0xae016c6c42daa8d1517d0e10370cf7882b28149635f734c5f3d83f781cd61f5df6d5203ec11bd0ca9d9e51c6030b66330476a93a65de6151d110e0f6482591f53678d863e55392e9cfb55fecac537edac51979790bcde38250a141348f116d46', - deposit_data_root: - 'fbada6c7c4cba867780eead34c1462339795fe9b417db466ce2f9d4822e8a4bb', - }, - builder_registration: { - message: { - fee_recipient: '0x86b8145c98e5bd25ba722645b15ed65f024a87ec', - gas_limit: 30000000, - timestamp: 1616508000, - pubkey: - '0xb61b17f3b6425eb2636bc6378de0ed8aab918c3346b59d297828e7c74643d51e80edc2b41290c568614cfb80d2b0be34', - }, - signature: - '0xb1de0eeb44c3b9d598d50c8d48a676e45dd63a5a3040caa34e34ab8c60d0b2f079419d8699c97e76b641326845c99ee309096de1878547e370d4b82e2e4e580650fee2e46dc7b9b3bd805b7fe6f95ba6a9e2734c3ddd23bf6b1f5597e9a3f834', - }, - }, - ], - signature_aggregate: - '0x90c32196e4dda81b39faaaec283e3ec5620b7c25c1a35949d54eb53a7c1c5a3963614c0d147085d82f9c52f550556ba406c0c5c8a4cec3fec825e6663a8792a9205f1a36fdde3e8c810cfd8861963190dd9b9eadd9a803bd5765c0b93d146542', - lock_hash: - '0xdb19ef9c0677713f55502448b7c63d58fb25c81d34a5a8ce07a19bcfb3a9c0a0', - node_signatures: [ - '0xa5230ba0586b21d49e790bc99304dc2245f8222c17d456ef60b848e3b0c5541d61825b2f9c2bda87ba3952979f28f6ba2338026603de74f925d9603aa823d42f01', - '0xc22ac5dc3a6f98471f2f25d11fd48600f955f68cb940e9da6789ab8fc50ca1bf40c8fb3200132ad6b2c66be7e256979fe182f8f924506ad8ba2c827401038ec600', - '0xebd08c9ece21abd78cfe82bc32eae68ccd77fc1e96e56ce93679918c5adcb2c92564a4fa609d7649587fbfb0c581403da8553e9e62c910e5ae589625704aa02b00', - '0xa07fc8f89f32a5b2551cc2173b0486f86142ee2a67400d2d4a956a2b948da96b58adddf558db6ac84de62242b5e56b1a1e95d26451be3a922fe3929f2a367a7400', - ], -} - -export const enr = - 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak' - -export const clusterConfig = { - name: 'testSDK', - operators: [ - { address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81' }, - { address: '0x33807D6F1DCe44b9C599fFE03640762A6F08C496' }, - { address: '0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f' }, - { address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC' }, - ], - validators: [ - { - fee_recipient_address: '0x3CD4958e76C317abcEA19faDd076348808424F99', - withdrawal_address: '0xE0C5ceA4D3869F156717C66E188Ae81C80914a6e', - }, - ], -} diff --git a/test/sdk-package-test/utils.ts b/test/sdk-package-test/utils.ts index f9b67c4..d6ecb3e 100644 --- a/test/sdk-package-test/utils.ts +++ b/test/sdk-package-test/utils.ts @@ -15,7 +15,7 @@ const wallet = new ethers.Wallet(privateKey) export const signer = wallet.connect(null) export const client: Client = new Client( - { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, + { baseUrl: 'https://obol-api-nonprod-dev.dev.obol.tech', chainId: 17000 }, signer, ) diff --git a/test/sdk-package-test/yarn.lock b/test/sdk-package-test/yarn.lock index 1f56d09..5975631 100644 --- a/test/sdk-package-test/yarn.lock +++ b/test/sdk-package-test/yarn.lock @@ -8,12 +8,12 @@ integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== "@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": version "7.23.5" @@ -637,44 +637,44 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz#9b18145d26cf33d08576cf4c7665b28554480ed7" - integrity sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw== +"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: - "@jridgewell/set-array" "^1.0.1" + "@jridgewell/set-array" "^1.2.1" "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.23" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz#afc96847f3f07841477f303eed687707a5aacd80" - integrity sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.24": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" "@ljharb/through@^2.3.12": - version "2.3.12" - resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.12.tgz#c418c43060eee193adce48b15c2206096a28e9ea" - integrity sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g== + version "2.3.13" + resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.13.tgz#b7e4766e0b65aa82e529be945ab078de79874edc" + integrity sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" "@metamask/abi-utils@^2.0.2": version "2.0.2" @@ -697,9 +697,9 @@ tweetnacl-util "^0.15.1" "@metamask/utils@^8.0.0", "@metamask/utils@^8.1.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.3.0.tgz#a20de447aeb9ffb75924d822a186a597033984b6" - integrity sha512-WFVcMPEkKKRCJ8DDkZUTVbLlpwgRn98F4VM/WzN89HM8PmHMnCyk/oG0AmK/seOxtik7uC7Bbi2YBC5Z5XB2zw== + version "8.4.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.4.0.tgz#f44812c96467a4e1b70b2edff6ee89a9caa4e354" + integrity sha512-dbIc3C7alOe0agCuBHM1h71UaEaEqOk2W8rAtEn8QGz4haH2Qq7MoK6i7v2guzvkJVVh79c+QCzIqphC3KvrJg== dependencies: "@ethereumjs/tx" "^4.2.0" "@noble/hashes" "^1.3.1" @@ -709,6 +709,7 @@ pony-cause "^2.1.10" semver "^7.5.4" superstruct "^1.0.3" + uuid "^9.0.1" "@multiformats/base-x@^4.0.1": version "4.0.1" @@ -734,11 +735,16 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/hashes@1.3.3", "@noble/hashes@^1.2.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1", "@noble/hashes@~1.3.2": +"@noble/hashes@1.3.3", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== +"@noble/hashes@^1.2.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -777,7 +783,7 @@ rimraf "^3.0.2" "@obolnetwork/obol-sdk@file:../..": - version "1.0.12" + version "1.0.13" dependencies: "@chainsafe/bls" "6.0.3" "@chainsafe/blst" "^0.2.9" @@ -794,6 +800,7 @@ ethers "^6.4.0" nock "^13.5.3" release-it "^17.1.1" + semver "^7.6.0" typescript-eslint "^7.1.0" uuid "^9.0.0" @@ -838,21 +845,21 @@ integrity sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA== "@octokit/plugin-paginate-rest@^9.0.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.0.tgz#ca08e32adfab72a1223c4f4b77c9f0222087f879" - integrity sha512-NKi0bJEZqOSbBLMv9kdAcuocpe05Q2xAXNLTGi0HN2GSMFJHNZuSoPNa0tcQFTOFCKe+ZaYBZ3lpXh1yxgUDCA== + version "9.2.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz#2e2a2f0f52c9a4b1da1a3aa17dabe3c459b9e401" + integrity sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw== dependencies: "@octokit/types" "^12.6.0" "@octokit/plugin-request-log@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-4.0.0.tgz#260fa6970aa97bbcbd91f99f3cd812e2b285c9f1" - integrity sha512-2uJI1COtYCq8Z4yNSnM231TgH50bRkheQ9+aH8TnZanB6QilOnx8RMD2qsnamSOXtDj0ilxvevf5fGsBhBBzKA== + version "4.0.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz#98a3ca96e0b107380664708111864cb96551f958" + integrity sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA== "@octokit/plugin-rest-endpoint-methods@^10.0.0": - version "10.4.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.0.tgz#f3756b080b75c397e82052de0105535b5d830ead" - integrity sha512-INw5rGXWlbv/p/VvQL63dhlXr38qYTHkQ5bANi9xofrF9OraqmjHsIGyenmjmul1JVRHpUlw5heFOj1UZLEolA== + version "10.4.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz#41ba478a558b9f554793075b2e20cd2ef973be17" + integrity sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg== dependencies: "@octokit/types" "^12.6.0" @@ -1149,9 +1156,9 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node@*", "@types/node@>=13.7.0": - version "20.11.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.21.tgz#ad67e65652f7be15686e2df87a38076a81c5e9c5" - integrity sha512-/ySDLGscFPNasfqStUuWWPfL78jompfIoVzLJPVVAHBh6rpG68+pI2Gk+fNLeI8/f1yPYL4s46EleVIc20F1Ow== + version "20.11.28" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.28.tgz#4fd5b2daff2e580c12316e457473d68f15ee6f66" + integrity sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA== dependencies: undici-types "~5.26.4" @@ -1211,16 +1218,16 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz#22bb999a8d59893c0ea07923e8a21f9d985ad740" - integrity sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w== +"@typescript-eslint/eslint-plugin@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz#5a5fcad1a7baed85c10080d71ad901f98c38d5b7" + integrity sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "7.1.0" - "@typescript-eslint/type-utils" "7.1.0" - "@typescript-eslint/utils" "7.1.0" - "@typescript-eslint/visitor-keys" "7.1.0" + "@typescript-eslint/scope-manager" "7.2.0" + "@typescript-eslint/type-utils" "7.2.0" + "@typescript-eslint/utils" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -1228,15 +1235,15 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.1.0.tgz#b89dab90840f7d2a926bf4c23b519576e8c31970" - integrity sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w== +"@typescript-eslint/parser@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.2.0.tgz#44356312aea8852a3a82deebdacd52ba614ec07a" + integrity sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg== dependencies: - "@typescript-eslint/scope-manager" "7.1.0" - "@typescript-eslint/types" "7.1.0" - "@typescript-eslint/typescript-estree" "7.1.0" - "@typescript-eslint/visitor-keys" "7.1.0" + "@typescript-eslint/scope-manager" "7.2.0" + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/typescript-estree" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" debug "^4.3.4" "@typescript-eslint/parser@^6.4.0": @@ -1258,21 +1265,21 @@ "@typescript-eslint/types" "6.21.0" "@typescript-eslint/visitor-keys" "6.21.0" -"@typescript-eslint/scope-manager@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz#e4babaa39a3d612eff0e3559f3e99c720a2b4a54" - integrity sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A== +"@typescript-eslint/scope-manager@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz#cfb437b09a84f95a0930a76b066e89e35d94e3da" + integrity sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg== dependencies: - "@typescript-eslint/types" "7.1.0" - "@typescript-eslint/visitor-keys" "7.1.0" + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" -"@typescript-eslint/type-utils@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz#372dfa470df181bcee0072db464dc778b75ed722" - integrity sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew== +"@typescript-eslint/type-utils@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz#7be5c30e9b4d49971b79095a1181324ef6089a19" + integrity sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA== dependencies: - "@typescript-eslint/typescript-estree" "7.1.0" - "@typescript-eslint/utils" "7.1.0" + "@typescript-eslint/typescript-estree" "7.2.0" + "@typescript-eslint/utils" "7.2.0" debug "^4.3.4" ts-api-utils "^1.0.1" @@ -1281,10 +1288,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== -"@typescript-eslint/types@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.1.0.tgz#52a86d6236fda646e7e5fe61154991dc0dc433ef" - integrity sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA== +"@typescript-eslint/types@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.2.0.tgz#0feb685f16de320e8520f13cca30779c8b7c403f" + integrity sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA== "@typescript-eslint/typescript-estree@6.21.0": version "6.21.0" @@ -1300,13 +1307,13 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/typescript-estree@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz#419b1310f061feee6df676c5bed460537310c593" - integrity sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ== +"@typescript-eslint/typescript-estree@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz#5beda2876c4137f8440c5a84b4f0370828682556" + integrity sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA== dependencies: - "@typescript-eslint/types" "7.1.0" - "@typescript-eslint/visitor-keys" "7.1.0" + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -1314,17 +1321,17 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.1.0.tgz#710ecda62aff4a3c8140edabf3c5292d31111ddd" - integrity sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw== +"@typescript-eslint/utils@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.2.0.tgz#fc8164be2f2a7068debb4556881acddbf0b7ce2a" + integrity sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "7.1.0" - "@typescript-eslint/types" "7.1.0" - "@typescript-eslint/typescript-estree" "7.1.0" + "@typescript-eslint/scope-manager" "7.2.0" + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/typescript-estree" "7.2.0" semver "^7.5.4" "@typescript-eslint/visitor-keys@6.21.0": @@ -1335,12 +1342,12 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@typescript-eslint/visitor-keys@7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz#576c4ad462ca1378135a55e2857d7aced96ce0a0" - integrity sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA== +"@typescript-eslint/visitor-keys@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz#5035f177752538a5750cca1af6044b633610bf9e" + integrity sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A== dependencies: - "@typescript-eslint/types" "7.1.0" + "@typescript-eslint/types" "7.2.0" eslint-visitor-keys "^3.4.1" "@zxing/text-encoding@0.9.0": @@ -1619,7 +1626,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.6, available-typed-arrays@^1.0.7: +available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== @@ -1953,9 +1960,9 @@ camelcase@^7.0.1: integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== caniuse-lite@^1.0.30001587: - version "1.0.30001591" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz#16745e50263edc9f395895a7cd468b9f3767cf33" - integrity sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ== + version "1.0.30001599" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce" + integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA== chalk@5.3.0, chalk@^5.2.0, chalk@^5.3.0: version "5.3.0" @@ -2215,6 +2222,33 @@ data-uri-to-buffer@^6.0.2: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz#8a58bb67384b261a38ef18bea1810cb01badd28b" integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -2276,7 +2310,7 @@ defer-to-connect@^2.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-data-property@^1.0.1, define-data-property@^1.1.2, define-data-property@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -2387,14 +2421,14 @@ eastasianwidth@^0.2.0: integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== electron-to-chromium@^1.4.668: - version "1.4.685" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.685.tgz#3ce988e4dfbb3aa984840394b1d7064c01ad74c1" - integrity sha512-yDYeobbTEe4TNooEzOQO6xFqg9XnAkVy2Lod1C1B2it8u47JNLYvl9nLDWBamqUakWB8Jc1hhS1uHUNYTNQdfw== + version "1.4.708" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.708.tgz#d54d3b47cb44ae6b190067439c42135456907893" + integrity sha512-iWgEEvREL4GTXXHKohhh33+6Y8XkPI5eHihDmm8zUk5Zo7HICEW+wI/j5kJ2tbuNUCXJ/sNXa03ajW635DiJXA== elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + version "6.5.5" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded" + integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw== dependencies: bn.js "^4.11.9" brorand "^1.1.0" @@ -2454,17 +2488,17 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.4.tgz#26eb2e7538c3271141f5754d31aabfdb215f27bf" - integrity sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg== + version "1.22.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.5.tgz#1417df4e97cc55f09bf7e58d1e614bc61cb8df46" + integrity sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.6" + available-typed-arrays "^1.0.7" call-bind "^1.0.7" es-define-property "^1.0.0" es-errors "^1.3.0" - es-set-tostringtag "^2.0.2" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" get-intrinsic "^1.2.4" @@ -2472,15 +2506,15 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: globalthis "^1.0.3" gopd "^1.0.1" has-property-descriptors "^1.0.2" - has-proto "^1.0.1" + has-proto "^1.0.3" has-symbols "^1.0.3" hasown "^2.0.1" internal-slot "^1.0.7" is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" is-typed-array "^1.1.13" is-weakref "^1.0.2" @@ -2493,13 +2527,65 @@ es-abstract@^1.22.1, es-abstract@^1.22.3: string.prototype.trim "^1.2.8" string.prototype.trimend "^1.0.7" string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.1" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.5" unbox-primitive "^1.0.2" which-typed-array "^1.1.14" +es-abstract@^1.23.0: + version "1.23.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.2.tgz#693312f3940f967b8dd3eebacb590b01712622e0" + integrity sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" + is-callable "^1.2.7" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.5" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" @@ -2532,7 +2618,14 @@ es-get-iterator@^1.0.2: isarray "^2.0.5" stop-iteration-iterator "^1.0.0" -es-set-tostringtag@^2.0.2: +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== @@ -2977,7 +3070,7 @@ get-east-asian-width@^1.0.0: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e" integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -3013,9 +3106,9 @@ get-symbol-description@^1.0.2: get-intrinsic "^1.2.4" get-tsconfig@^4.7.0: - version "4.7.2" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" - integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + version "4.7.3" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.3.tgz#0498163d98f7b58484dd4906999c0c9d5f103f83" + integrity sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg== dependencies: resolve-pkg-maps "^1.0.0" @@ -3184,7 +3277,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1, has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== @@ -3201,7 +3294,7 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0, has-tostringtag@^1.0.1, has-tostringtag@^1.0.2: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== @@ -3221,10 +3314,10 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasown@^2.0.0, hasown@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa" - integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -3511,6 +3604,13 @@ is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.13.1: dependencies: hasown "^2.0.0" +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -3595,9 +3695,9 @@ is-lambda@^1.0.1: integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== is-nan@^1.3.2: version "1.3.2" @@ -3607,7 +3707,7 @@ is-nan@^1.3.2: call-bind "^1.0.0" define-properties "^1.1.3" -is-negative-zero@^2.0.2: +is-negative-zero@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== @@ -3648,11 +3748,11 @@ is-regex@^1.1.4: has-tostringtag "^1.0.0" is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== -is-shared-array-buffer@^1.0.2: +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== @@ -4735,9 +4835,9 @@ mute-stream@1.0.0: integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== nan@^2.14.2: - version "2.18.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" - integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== + version "2.19.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" + integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== native-fetch@^3.0.0: version "3.0.0" @@ -4855,9 +4955,9 @@ normalize-path@^3.0.0: integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-url@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.0.tgz#593dbd284f743e8dcf6a5ddf8fadff149c82701a" - integrity sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw== + version "8.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" + integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== npm-run-path@^4.0.1: version "4.0.1" @@ -5326,11 +5426,11 @@ pupa@^3.1.0: escape-goat "^4.0.0" qs@^6.11.0: - version "6.11.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + version "6.12.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.0.tgz#edd40c3b823995946a8a0b1f208669c7a200db77" + integrity sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" queue-microtask@^1.2.2: version "1.2.3" @@ -5571,13 +5671,13 @@ rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" - integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== +safe-array-concat@^1.1.0, safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" has-symbols "^1.0.3" isarray "^2.0.5" @@ -5616,7 +5716,7 @@ semver-diff@^4.0.0: dependencies: semver "^7.3.5" -semver@7.6.0, semver@7.x, semver@^7.0.0, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@7.6.0, semver@7.x, semver@^7.0.0, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== @@ -5634,16 +5734,16 @@ set-blocking@^2.0.0: integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== set-function-length@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" - integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - define-data-property "^1.1.2" + define-data-property "^1.1.4" es-errors "^1.3.0" function-bind "^1.1.2" - get-intrinsic "^1.2.3" + get-intrinsic "^1.2.4" gopd "^1.0.1" - has-property-descriptors "^1.0.1" + has-property-descriptors "^1.0.2" set-function-name@^2.0.1: version "2.0.2" @@ -5676,12 +5776,12 @@ shelljs@0.8.5: interpret "^1.0.0" rechoir "^0.6.2" -side-channel@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.5.tgz#9a84546599b48909fb6af1211708d23b1946221b" - integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== +side-channel@^1.0.4, side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.6" + call-bind "^1.0.7" es-errors "^1.3.0" get-intrinsic "^1.2.4" object-inspect "^1.13.1" @@ -5838,23 +5938,24 @@ string-width@^7.0.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.trim@^1.2.8, string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.trimend@^1.0.7, string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string.prototype.trimstart@^1.0.7: version "1.0.7" @@ -5933,9 +6034,9 @@ superagent@^8.1.2: semver "^7.3.8" superstruct@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.3.tgz#de626a5b49c6641ff4d37da3c7598e7a87697046" - integrity sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg== + version "1.0.4" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" + integrity sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ== supertest@^6.3.3: version "6.3.4" @@ -6038,9 +6139,9 @@ tr46@~0.0.3: integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-api-utils@^1.0.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b" - integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== ts-jest@^28.0.8: version "28.0.8" @@ -6111,7 +6212,7 @@ type-fest@^2.13.0, type-fest@^2.5.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -typed-array-buffer@^1.0.1: +typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== @@ -6120,7 +6221,7 @@ typed-array-buffer@^1.0.1: es-errors "^1.3.0" is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.0: +typed-array-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== @@ -6131,7 +6232,7 @@ typed-array-byte-length@^1.0.0: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-byte-offset@^1.0.0: +typed-array-byte-offset@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== @@ -6143,7 +6244,7 @@ typed-array-byte-offset@^1.0.0: has-proto "^1.0.3" is-typed-array "^1.1.13" -typed-array-length@^1.0.4: +typed-array-length@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== @@ -6163,12 +6264,12 @@ typedarray-to-buffer@^3.1.5: is-typedarray "^1.0.0" typescript-eslint@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-7.1.0.tgz#e98e26ea2346e7058c025a1545522bdfa8fcd30f" - integrity sha512-GfAALH4zoqae5mIfHr7WU3BsULHP73hjwF8vCmyTkH3IXHXjqg3JNWwUcd8CwOTLIr4tjRTZQWpToyESPnpOhg== + version "7.2.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-7.2.0.tgz#4cb084a74cbfc73085c8f98f1025203721ca2a98" + integrity sha512-VqXEBqzPxJlR8Lfg2Dywe4XpIk637kwp2sfMQ+vudNHo48TUvnlHzAyFMQknv0AdhvZFXQN0a0t9SPI3rsAYew== dependencies: - "@typescript-eslint/eslint-plugin" "7.1.0" - "@typescript-eslint/parser" "7.1.0" + "@typescript-eslint/eslint-plugin" "7.2.0" + "@typescript-eslint/parser" "7.2.0" uint8arrays@1.1.0, uint8arrays@^1.1.0: version "1.1.0" @@ -6305,7 +6406,7 @@ util@^0.12.3, util@^0.12.5: is-typed-array "^1.1.3" which-typed-array "^1.1.2" -uuid@^9.0.0: +uuid@^9.0.0, uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== @@ -6390,16 +6491,16 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.14, which-typed-array@^1.1.2: - version "1.1.14" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" - integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.6" - call-bind "^1.0.5" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.1" + has-tostringtag "^1.0.2" which@^2.0.1, which@^2.0.2: version "2.0.2" diff --git a/yarn.lock b/yarn.lock index 5888071..0f23bb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6346,7 +6346,7 @@ semver-diff@^4.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@7.6.0, semver@7.x, semver@^7.0.0, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: +semver@7.6.0, semver@7.x, semver@^7.0.0, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==