From 2119a4803ee5f0fb18174b2a59c6b28da0b3407b Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 02:10:24 +0300 Subject: [PATCH 01/12] support v1.8.0 --- package.json | 1 + src/constants.ts | 5 +- src/hash.ts | 256 ----------------- src/index.ts | 13 +- src/services.ts | 2 +- src/types.ts | 16 +- src/utils.ts | 49 ++++ src/verification/common.ts | 532 +++++++++++++++++++++++++++++++++++ src/verification/sszTypes.ts | 79 ++++++ src/verification/v1.6.0.ts | 169 +++++++++++ src/verification/v1.7.0.ts | 184 ++++++++++++ src/verification/v1.8.0.ts | 192 +++++++++++++ src/verify.ts | 494 -------------------------------- yarn.lock | 2 +- 14 files changed, 1232 insertions(+), 762 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 diff --git a/package.json b/package.json index bcb3bb3..ff39aa7 100644 --- a/package.json +++ b/package.json @@ -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..84652f9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -98,7 +98,7 @@ export const signEnrPayload = ( export const DKG_ALGORITHM = 'default' -export const CONFIG_VERSION = 'v1.7.0' +export const CONFIG_VERSION = 'v1.8.0' export const SDK_VERSION = pjson.version @@ -116,3 +116,6 @@ 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..ea83979 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' @@ -39,7 +39,7 @@ export class Client extends Base { * An example of how to instantiate obol-sdk Client: * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L29) */ - constructor ( + constructor( config: { baseUrl?: string, chainId?: number }, signer?: Signer, ) { @@ -56,7 +56,7 @@ export class Client extends Base { * An example of how to use createClusterDefinition: * [createObolCluster](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async createClusterDefinition (newCluster: ClusterPayload): Promise { + async createClusterDefinition(newCluster: ClusterPayload): Promise { if (!this.signer) { throw new Error('Signer is required in createClusterDefinition') } validatePayload(newCluster, definitionSchema) @@ -70,6 +70,7 @@ export class Client extends Base { timestamp: new Date().toISOString(), threshold: Math.ceil((2 * newCluster.operators.length) / 3), num_validators: newCluster.validators.length, + deposit_amounts: newCluster.deposit_amounts ? newCluster.deposit_amounts : ["32000000000"] } try { @@ -114,7 +115,7 @@ export class Client extends Base { * An example of how to use acceptClusterDefinition: * [acceptClusterDefinition](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async acceptClusterDefinition ( + async acceptClusterDefinition( operatorPayload: OperatorPayload, configHash: string, ): Promise { @@ -166,7 +167,7 @@ export class Client extends Base { * An example of how to use getClusterDefinition: * [getObolClusterDefinition](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async getClusterDefinition (configHash: string): Promise { + async getClusterDefinition(configHash: string): Promise { const clusterDefinition: ClusterDefintion = await this.request( `/dv/${configHash}`, { @@ -185,7 +186,7 @@ export class Client extends Base { * An example of how to use getClusterLock: * [getObolClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async getClusterLock (configHash: string): Promise { + async getClusterLock(configHash: string): Promise { const lock: ClusterLock = await this.request( `/lock/configHash/${configHash}`, { diff --git a/src/services.ts b/src/services.ts index 83834a6..16faad1 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/verify.js' /** * Verifies Cluster Lock's validity. diff --git a/src/types.ts b/src/types.ts index 119c02c..13b67a8 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,13 +178,17 @@ 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?: Partial[] /** pre-generated signed validator builder registration to be sent to builder network. */ builder_registration: BuilderRegistration } + /** * Cluster Details after DKG is complete */ diff --git a/src/utils.ts b/src/utils.ts index cf7e05d..65a81ba 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,6 @@ +import { DefinitionFlow } from "./constants" +import { 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..424c3d5 --- /dev/null +++ b/src/verification/common.ts @@ -0,0 +1,532 @@ +import { + fromHexString, +} from '@chainsafe/ssz' +import elliptic from 'elliptic' +import { + init, + aggregateSignatures, + verifyMultiple, + verifyAggregate, +} from '@chainsafe/bls' + +import { FORK_MAPPING, type ClusterDefintion, type ClusterLock, DepositData, BuilderRegistrationMessage, DistributedValidator } from '../types.js' +import * as semver from 'semver' +import { clusterDefinitionContainerTypeV1X6, hashClusterDefinitionV1X6, hashClusterLockV1X6 } from './v1.6.0.js' +import { clusterDefinitionContainerTypeV1X7, hashClusterLockV1X7 } 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 } 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 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, + ) +} + +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. + */ +const verifyDepositData = ( + distributedPublicKey: string, + depositData: Partial, + withdrawalAddress: string, +): boolean => { + const eth1AddressWithdrawalPrefix = '0x01'; + if ( + eth1AddressWithdrawalPrefix + + '0'.repeat(22) + + withdrawalAddress.toLowerCase().slice(2) !== + depositData.withdrawal_credentials + ) { + return false; + } + + if (distributedPublicKey !== depositData.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) +} + +function hashClusterDefinitionV1X7(cluster: ClusterDefintion, configOnly: boolean): any { + throw new Error('Function not implemented.') +} + + +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; + const distributedPublicKey = validator.distributed_public_key; + + + for (const element of validatorPublicShares) { + pubShares.push(fromHexString(element)) + } + + // Deposit data signature + if ( + semver.gte(clusterLock.cluster_definition.version, 'v1.6.0') && + validator.deposit_data + ) { + if ( + !verifyDepositData( + distributedPublicKey, + validator.deposit_data, + 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 ( + semver.gte(clusterLock.cluster_definition.version, 'v1.8.0') && + validator.partial_deposit_data + ) { + for (let j = 0; j < validator.partial_deposit_data.length; j++) { + const depositData = validator.partial_deposit_data[i]; + if ( + !verifyDepositData( + distributedPublicKey, + depositData, + clusterLock.cluster_definition.validators[i].withdrawal_address, + ) + ) { + return false; + } + + const depositMessageBuffer = computeDepositMsgRoot(depositData); + const depositDataMessage = signingRoot( + depositDomain, + depositMessageBuffer, + ); + + pubKeys.push(fromHexString(validator.distributed_public_key)); + builderRegistrationAndDepositDataMessages.push(depositDataMessage); + blsSignatures.push(fromHexString(depositData.signature as string)); + } + } + } + + 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/src/verification/sszTypes.ts b/src/verification/sszTypes.ts new file mode 100644 index 0000000..4096923 --- /dev/null +++ b/src/verification/sszTypes.ts @@ -0,0 +1,79 @@ +import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, UintNumberType } from "@chainsafe/ssz" +import { 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), +}) \ No newline at end of file diff --git a/src/verification/v1.6.0.ts b/src/verification/v1.6.0.ts new file mode 100644 index 0000000..2bceeca --- /dev/null +++ b/src/verification/v1.6.0.ts @@ -0,0 +1,169 @@ +import { UintNumberByteLen, UintNumberType } from "@chainsafe/ssz/lib/type/uint"; +import { strToUint8Array } from "../utils" +import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; +import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; +import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; +import { ClusterDefintion, ClusterLock } from "../types"; + +// 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(dVaidator => { + return { + distributed_public_key: fromHexString(dVaidator.distributed_public_key), + public_shares: dVaidator.public_shares.map(publicShare => + fromHexString(publicShare), + ), + 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), + }; + }); + + return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex') +} + + + + + + diff --git a/src/verification/v1.7.0.ts b/src/verification/v1.7.0.ts new file mode 100644 index 0000000..6ec4a60 --- /dev/null +++ b/src/verification/v1.7.0.ts @@ -0,0 +1,184 @@ +import { UintNumberByteLen, UintNumberType } from "@chainsafe/ssz/lib/type/uint"; +import { strToUint8Array } from "../utils" +import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; +import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; +import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; +import { ClusterDefintion, ClusterLock } from "../types"; + +// 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( + (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') +} + + + + + + diff --git a/src/verification/v1.8.0.ts b/src/verification/v1.8.0.ts new file mode 100644 index 0000000..6f1aafb --- /dev/null +++ b/src/verification/v1.8.0.ts @@ -0,0 +1,192 @@ +import { UintNumberByteLen, UintNumberType } from "@chainsafe/ssz/lib/type/uint"; +import { strToUint8Array } from "../utils" +import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; +import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; +import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; +import { ClusterDefintion, ClusterLock } from "../types"; + +// 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?.map((amount: string) => { + return parseInt(amount); + }) || ["32000000000"].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(dVaidator => { + return { + distributed_public_key: fromHexString(dVaidator.distributed_public_key), + public_shares: dVaidator.public_shares.map(publicShare => + fromHexString(publicShare), + ), + //should be fixed + partial_deposit_data: (dVaidator.partial_deposit_data || []).map(depositData => { + return { + pubkey: fromHexString(depositData.pubkey as string), + withdrawal_credentials: fromHexString( + depositData.withdrawal_credentials as string, + ), + amount: parseInt(depositData.amount as string), + signature: fromHexString(depositData.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') +} + + + + + + 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/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== From d2845387a9540597cbebf2dfa9f9c2aa7fc7dbc9 Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 13:05:14 +0300 Subject: [PATCH 02/12] remove not needed function --- src/services.ts | 2 +- src/verification/common.ts | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/services.ts b/src/services.ts index 16faad1..7a47626 100644 --- a/src/services.ts +++ b/src/services.ts @@ -1,5 +1,5 @@ import { type ClusterLock } from './types.js' -import { isValidClusterLock } from './verification/verify.js' +import { isValidClusterLock } from './verification/common.js' /** * Verifies Cluster Lock's validity. diff --git a/src/verification/common.ts b/src/verification/common.ts index 424c3d5..b903267 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -12,7 +12,7 @@ import { import { FORK_MAPPING, type ClusterDefintion, type ClusterLock, DepositData, BuilderRegistrationMessage, DistributedValidator } from '../types.js' import * as semver from 'semver' import { clusterDefinitionContainerTypeV1X6, hashClusterDefinitionV1X6, hashClusterLockV1X6 } from './v1.6.0.js' -import { clusterDefinitionContainerTypeV1X7, hashClusterLockV1X7 } from './v1.7.0.js' +import { clusterDefinitionContainerTypeV1X7, hashClusterDefinitionV1X7, hashClusterLockV1X7 } 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' @@ -318,10 +318,6 @@ export const signingRoot = ( return computeSigningRoot(messageBuffer, domain) } -function hashClusterDefinitionV1X7(cluster: ClusterDefintion, configOnly: boolean): any { - throw new Error('Function not implemented.') -} - const verifyLockData = async (clusterLock: ClusterLock): Promise => { const ec = new elliptic.ec('secp256k1') From 0a72baaa3e6c7993e325fe9bd8dc0e2b49e7ab20 Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 14:14:40 +0300 Subject: [PATCH 03/12] add tests for v1.8.0 --- test/fixtures.ts | 152 +++++++++++++++++++++++- test/methods.test.ts | 52 ++++----- test/sdk-package-test/cluster.test.ts | 38 +++--- test/sdk-package-test/fixtures.ts | 160 +++++++++++++++++++++++++- test/sdk-package-test/utils.ts | 2 +- test/sdk-package-test/yarn.lock | 3 +- 6 files changed, 355 insertions(+), 52 deletions(-) diff --git a/test/fixtures.ts b/test/fixtures.ts index 12ca763..5693d6f 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,3 +1,21 @@ +//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', @@ -104,7 +122,9 @@ export const clusterLockV1X7 = { ], } -export const clusterConfig = { +// v1.8.0 + +export const clusterConfigV1X8 = { name: 'testSDK', operators: [ { address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81' }, @@ -118,4 +138,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..ea74fa5 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 { clusterConfigV1X8, clusterLockV1X8 } from './fixtures.js' import { SDK_VERSION } from '../src/constants' import { Base } from '../src/base' import { validatePayload } from '../src/ajv' @@ -35,23 +35,23 @@ describe('Cluster Client', () => { .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) const configHash = - await clientInstance.createClusterDefinition(clusterConfig) + await clientInstance.createClusterDefinition(clusterConfigV1X8) expect(configHash).toEqual(mockConfigHash) }) test('acceptClusterDefinition should return cluster definition', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X7.cluster_definition)) + .mockReturnValue(Promise.resolve(clusterLockV1X8.cluster_definition)) const clusterDefinition = await clientInstance.acceptClusterDefinition( { - enr: clusterLockV1X7.cluster_definition.operators[0].enr, - version: clusterLockV1X7.cluster_definition.version, + enr: clusterLockV1X8.cluster_definition.operators[0].enr, + version: clusterLockV1X8.cluster_definition.version, }, - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) - expect(clusterDefinition).toEqual(clusterLockV1X7.cluster_definition) + expect(clusterDefinition).toEqual(clusterLockV1X8.cluster_definition) }) test('createClusterDefinition should throw an error on invalid operators', async () => { @@ -60,7 +60,7 @@ describe('Cluster Client', () => { .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) try { await clientInstance.createClusterDefinition({ - ...clusterConfig, + ...clusterConfigV1X8, 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({ ...clusterConfigV1X8, operators: [] }, '') } catch (error: any) { expect(error.message).toEqual('schema must be object or boolean') } @@ -81,25 +81,25 @@ describe('Cluster Client', () => { test('getClusterdefinition should return cluster definition if config hash exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X7.cluster_definition)) + .mockReturnValue(Promise.resolve(clusterLockV1X8.cluster_definition)) const clusterDefinition = await clientInstance.getClusterDefinition( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) }) test('getClusterLock should return lockFile if exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X7)) + .mockReturnValue(Promise.resolve(clusterLockV1X8)) const clusterLock = await clientInstance.getClusterLock( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) - expect(clusterLock.lock_hash).toEqual(clusterLockV1X7.lock_hash) + expect(clusterLock.lock_hash).toEqual(clusterLockV1X8.lock_hash) }) test('request method should set user agent header', async () => { @@ -139,7 +139,7 @@ describe('Cluster Client without a signer', () => { test('createClusterDefinition should throw an error without signer', async () => { try { - await clientInstance.createClusterDefinition(clusterConfig) + await clientInstance.createClusterDefinition(clusterConfigV1X8) } catch (err: any) { expect(err.message).toEqual('Signer is required in createClusterDefinition') } @@ -149,10 +149,10 @@ describe('Cluster Client without a signer', () => { try { await clientInstance.acceptClusterDefinition( { - enr: clusterLockV1X7.cluster_definition.operators[0].enr, - version: clusterLockV1X7.cluster_definition.version, + enr: clusterLockV1X8.cluster_definition.operators[0].enr, + version: clusterLockV1X8.cluster_definition.version, }, - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) } catch (err: any) { expect(err.message).toEqual('Signer is required in acceptClusterDefinition') @@ -162,29 +162,29 @@ describe('Cluster Client without a signer', () => { test('getClusterdefinition should return cluster definition if config hash exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X7.cluster_definition)) + .mockReturnValue(Promise.resolve(clusterLockV1X8.cluster_definition)) const clusterDefinition = await clientInstance.getClusterDefinition( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) }) test('getClusterLock should return lockFile if exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X7)) + .mockReturnValue(Promise.resolve(clusterLockV1X8)) const clusterLock = await clientInstance.getClusterLock( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) - expect(clusterLock.lock_hash).toEqual(clusterLockV1X7.lock_hash) + expect(clusterLock.lock_hash).toEqual(clusterLockV1X8.lock_hash) }) it('should return true on verified cluster lock', async () => { - const isValidLock: boolean = await validateClusterLock(clusterLockV1X7) + const isValidLock: boolean = await validateClusterLock(clusterLockV1X8) expect(isValidLock).toEqual(true) }) }) diff --git a/test/sdk-package-test/cluster.test.ts b/test/sdk-package-test/cluster.test.ts index c5f8fbb..1614f96 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 { clusterConfigV1X8, 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://b90b-2a01-9700-155f-0-5d1-55a8-b411-54d7.ngrok-free.app', chainId: 17000, }) beforeAll(async () => { - configHash = await client.createClusterDefinition(clusterConfig) + configHash = await client.createClusterDefinition(clusterConfigV1X8) }) 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(clusterConfigV1X8) } 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 }) + clusterConfigV1X8.operators.push({ address: signerAddress }) - secondConfigHash = await client.createClusterDefinition(clusterConfig) + secondConfigHash = await client.createClusterDefinition(clusterConfigV1X8) const definitionData: ClusterDefintion = await client.acceptClusterDefinition( @@ -108,10 +108,10 @@ describe('Cluster Definition', () => { describe('Poll Cluster Lock', () => { // Test polling getClusterLock through mimicing the whole flow using obol-api endpoints - const { definition_hash: _, ...rest } = clusterLockV1X7.cluster_definition + const { definition_hash: _, ...rest } = clusterLockV1X8.cluster_definition const clusterWithoutDefHash = rest const clientWithoutAsigner = new Client({ - baseUrl: 'https://obol-api-dev.gcp.obol.tech', + baseUrl: 'https://b90b-2a01-9700-155f-0-5d1-55a8-b411-54d7.ngrok-free.app', chainId: 17000, }) @@ -126,7 +126,7 @@ describe('Poll Cluster Lock', () => { const pollReqIntervalId = setInterval(async function () { try { const lockFile = await client.getClusterLock( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) if (lockFile?.lock_hash) { clearInterval(pollReqIntervalId) @@ -144,8 +144,8 @@ describe('Poll Cluster Lock', () => { }, 5000) }), (async () => { - await updateClusterDef(clusterLockV1X7.cluster_definition) - await publishLockFile(clusterLockV1X7) + await updateClusterDef(clusterLockV1X8.cluster_definition) + await publishLockFile(clusterLockV1X8) })(), ]) expect(lockObject).toHaveProperty('lock_hash') @@ -158,7 +158,7 @@ describe('Poll Cluster Lock', () => { const pollReqIntervalId = setInterval(async function () { try { const lockFile = await clientWithoutAsigner.getClusterLock( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) if (lockFile?.lock_hash) { clearInterval(pollReqIntervalId) @@ -175,8 +175,8 @@ describe('Poll Cluster Lock', () => { }, 5000) }), (async () => { - await updateClusterDef(clusterLockV1X7.cluster_definition) - await publishLockFile(clusterLockV1X7) + await updateClusterDef(clusterLockV1X8.cluster_definition) + await publishLockFile(clusterLockV1X8) })(), ]) expect(lockObject).toHaveProperty('lock_hash') @@ -185,21 +185,21 @@ describe('Poll Cluster Lock', () => { it('should fetch the cluster definition for the configHash', async () => { const clusterDefinition: ClusterDefintion = await client.getClusterDefinition( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X7.cluster_definition.config_hash, + clusterLockV1X8.cluster_definition.config_hash, ) }) it('should return true on verified cluster lock', async () => { - const isValidLock: boolean = await validateClusterLock(clusterLockV1X7) + const isValidLock: boolean = await validateClusterLock(clusterLockV1X8) expect(isValidLock).toEqual(true) }) afterAll(async () => { - const configHash = clusterLockV1X7.cluster_definition.config_hash - const lockHash = clusterLockV1X7.lock_hash + const configHash = clusterLockV1X8.cluster_definition.config_hash + const lockHash = clusterLockV1X8.lock_hash await request(app) .delete(`/lock/${lockHash}`) diff --git a/test/sdk-package-test/fixtures.ts b/test/sdk-package-test/fixtures.ts index 631e836..53d1b0e 100644 --- a/test/sdk-package-test/fixtures.ts +++ b/test/sdk-package-test/fixtures.ts @@ -1,3 +1,25 @@ + +export const enr = + 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak' + +// 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', @@ -104,10 +126,8 @@ export const clusterLockV1X7 = { ], } -export const enr = - 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak' - -export const clusterConfig = { +// v1.8.0 +export const clusterConfigV1X8 = { name: 'testSDK', operators: [ { address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81' }, @@ -121,4 +141,136 @@ 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/sdk-package-test/utils.ts b/test/sdk-package-test/utils.ts index f9b67c4..a37765b 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://b90b-2a01-9700-155f-0-5d1-55a8-b411-54d7.ngrok-free.app', chainId: 17000 }, signer, ) diff --git a/test/sdk-package-test/yarn.lock b/test/sdk-package-test/yarn.lock index 1f56d09..78c313a 100644 --- a/test/sdk-package-test/yarn.lock +++ b/test/sdk-package-test/yarn.lock @@ -794,6 +794,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" @@ -5616,7 +5617,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== From a2992bd6eac96d70db2d6819f0f4bd5a605609da Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 14:20:01 +0300 Subject: [PATCH 04/12] test to validate v1.7.0 lock --- test/methods.test.ts | 8 +++++--- test/sdk-package-test/cluster.test.ts | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/methods.test.ts b/test/methods.test.ts index ea74fa5..06da310 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 { clusterConfigV1X8, clusterLockV1X8 } from './fixtures.js' +import { clusterConfigV1X8, clusterLockV1X7, clusterLockV1X8 } from './fixtures.js' import { SDK_VERSION } from '../src/constants' import { Base } from '../src/base' import { validatePayload } from '../src/ajv' @@ -183,8 +183,10 @@ describe('Cluster Client without a signer', () => { expect(clusterLock.lock_hash).toEqual(clusterLockV1X8.lock_hash) }) - it('should return true on verified cluster lock', async () => { - const isValidLock: boolean = await validateClusterLock(clusterLockV1X8) + test.each([{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 1614f96..9203f3b 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 { clusterConfigV1X8, clusterLockV1X8, enr } from './fixtures' +import { clusterConfigV1X8, clusterLockV1X7, clusterLockV1X8, enr } from './fixtures' import { client, updateClusterDef, @@ -192,8 +192,10 @@ describe('Poll Cluster Lock', () => { ) }) - it('should return true on verified cluster lock', async () => { - const isValidLock: boolean = await validateClusterLock(clusterLockV1X8) + test.each([{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) }) From 47664f2eb54abb7c8a02254ba3dd93ac1d2d6e86 Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 14:25:11 +0300 Subject: [PATCH 05/12] add tests for deposit_amounts --- test/methods.test.ts | 12 ++++++++---- test/sdk-package-test/cluster.test.ts | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/test/methods.test.ts b/test/methods.test.ts index 06da310..9834d8d 100644 --- a/test/methods.test.ts +++ b/test/methods.test.ts @@ -86,6 +86,10 @@ describe('Cluster Client', () => { const clusterDefinition = await clientInstance.getClusterDefinition( clusterLockV1X8.cluster_definition.config_hash, ) + + expect(clusterDefinition.deposit_amounts?.length).toEqual( + clusterLockV1X8.cluster_definition.deposit_amounts.length, + ) expect(clusterDefinition.config_hash).toEqual( clusterLockV1X8.cluster_definition.config_hash, ) @@ -183,10 +187,10 @@ describe('Cluster Client without a signer', () => { expect(clusterLock.lock_hash).toEqual(clusterLockV1X8.lock_hash) }) - test.each([{version:"v1.7.0", clusterLock:clusterLockV1X7},{version:"v1.8.0", clusterLock:clusterLockV1X8}])( + test.each([{ 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) - }) + 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 9203f3b..af5043e 100755 --- a/test/sdk-package-test/cluster.test.ts +++ b/test/sdk-package-test/cluster.test.ts @@ -187,17 +187,21 @@ describe('Poll Cluster Lock', () => { await client.getClusterDefinition( clusterLockV1X8.cluster_definition.config_hash, ) + + expect(clusterDefinition.deposit_amounts?.length).toEqual( + clusterLockV1X8.cluster_definition.deposit_amounts.length, + ) expect(clusterDefinition.config_hash).toEqual( clusterLockV1X8.cluster_definition.config_hash, ) }) - test.each([{version:"v1.7.0", clusterLock:clusterLockV1X7},{version:"v1.8.0", clusterLock:clusterLockV1X8}])( + test.each([{ 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) - }) + const isValidLock: boolean = await validateClusterLock(clusterLock) + expect(isValidLock).toEqual(true) + }) afterAll(async () => { const configHash = clusterLockV1X8.cluster_definition.config_hash From b4e19bb7340ebbd04e4690887c2a6e1086fb6f16 Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 16:59:58 +0300 Subject: [PATCH 06/12] deposit amounts validation --- src/ajv.ts | 23 ++++++++++++++++++++++- src/schema.ts | 10 +++++++++- src/verification/common.ts | 9 +++++---- test/methods.test.ts | 32 +++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/ajv.ts b/src/ajv.ts index 693b83e..d8d9268 100644 --- a/src/ajv.ts +++ b/src/ajv.ts @@ -1,10 +1,31 @@ import Ajv, { type ErrorObject } from 'ajv' +import { ether_to_gwei } from './constants'; -export function validatePayload ( + +function validDpositAmounts(data: boolean, deposits: string[]) { + let sum = 0; + for (let i = 0; i < deposits.length; i++) { + const amount = parseInt(deposits[i]); + if (amount % ether_to_gwei !== 0 || amount > 32 * ether_to_gwei) { + return false + } + sum += amount; + } + if (sum !== 32 * ether_to_gwei) { return false } { + return true + } +} + +export function validatePayload( data: any, schema: any, ): ErrorObject[] | undefined | null | boolean { const ajv = new Ajv() + ajv.addKeyword({ + keyword: 'validDpositAmounts', + validate: validDpositAmounts, + errors: true, + }); const validate = ajv.compile(schema) const isValid = validate(data) if (!isValid) { diff --git a/src/schema.ts b/src/schema.ts index d431816..8467a39 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -53,6 +53,14 @@ export const definitionSchema = { required: ['fee_recipient_address', 'withdrawal_address'], }, }, + deposit_amounts: { + type: 'array', + items: { + type: 'string', + pattern: "^[0-9]+$", + }, + validDpositAmounts:true + }, }, - required: ['name', 'operators', 'validators'], + required: ['name','operators', 'validators'], } diff --git a/src/verification/common.ts b/src/verification/common.ts index b903267..9f015db 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -320,9 +320,10 @@ export const signingRoot = ( const verifyLockData = async (clusterLock: ClusterLock): Promise => { - const ec = new elliptic.ec('secp256k1') - const validators = clusterLock.distributed_validators - const nodeSignatures = clusterLock.node_signatures + 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, @@ -344,7 +345,7 @@ const verifyLockData = async (clusterLock: ClusterLock): Promise => { 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)) } diff --git a/test/methods.test.ts b/test/methods.test.ts index 9834d8d..ba38392 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 { clusterConfigV1X8, clusterLockV1X7, clusterLockV1X8 } from './fixtures.js' +import { clusterConfigV1X7, clusterConfigV1X8, clusterLockV1X7, clusterLockV1X8 } from './fixtures.js' import { SDK_VERSION } from '../src/constants' import { Base } from '../src/base' import { validatePayload } from '../src/ajv' @@ -70,6 +70,36 @@ describe('Cluster Client', () => { } }) + test('createClusterDefinition should accept a configuration without deposit_amounts ', async () => { + clientInstance['request'] = jest + .fn() + .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) + + const configHash = await clientInstance.createClusterDefinition({ + ...clusterConfigV1X7, + }) + + expect(configHash).toEqual(mockConfigHash) + }) + + test('createClusterDefinition should throw on not valid deposit_amounts ', async () => { + clientInstance['request'] = jest + .fn() + .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) + try { + await clientInstance.createClusterDefinition({ + ...clusterConfigV1X7, + deposit_amounts: ["34000000"] + }) + + } catch (error: any) { + console.log(error.message) + expect(error.message).toEqual( + "Schema compilation errors', must pass \"validDpositAmounts\" keyword validation", + ) + } + }) + test('validatePayload should throw an error on empty schema', async () => { try { validatePayload({ ...clusterConfigV1X8, operators: [] }, '') From 9e9cfe758ee63e41817dfb7acc557d4221f374de Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 22:26:48 +0300 Subject: [PATCH 07/12] clean the code --- src/verification/common.ts | 246 ++++++++------------------ src/verification/v1.6.0.ts | 66 ++++++- src/verification/v1.7.0.ts | 103 ++++++++++- src/verification/v1.8.0.ts | 103 ++++++++++- test/sdk-package-test/cluster.test.ts | 4 +- test/sdk-package-test/utils.ts | 2 +- 6 files changed, 348 insertions(+), 176 deletions(-) diff --git a/src/verification/common.ts b/src/verification/common.ts index 9f015db..9a1f786 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -11,15 +11,15 @@ import { import { FORK_MAPPING, type ClusterDefintion, type ClusterLock, DepositData, BuilderRegistrationMessage, DistributedValidator } from '../types.js' import * as semver from 'semver' -import { clusterDefinitionContainerTypeV1X6, hashClusterDefinitionV1X6, hashClusterLockV1X6 } from './v1.6.0.js' -import { clusterDefinitionContainerTypeV1X7, hashClusterDefinitionV1X7, hashClusterLockV1X7 } from './v1.7.0.js' +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 } from './v1.8.0.js' +import { clusterDefinitionContainerTypeV1X8, hashClusterDefinitionV1X8, hashClusterLockV1X8, verifyDVV1X8 } from './v1.8.0.js' // cluster-definition hash @@ -269,11 +269,16 @@ const computeDomain = ( * @param {string} withdrawalAddress - withdrawal address in definition file. * @returns {boolean} - return if deposit data is valid. */ -const verifyDepositData = ( +export const verifyDepositData = ( distributedPublicKey: string, depositData: Partial, withdrawalAddress: string, -): boolean => { + forkVersion: string, +): { isValidDepositData: boolean, depositDataMsg: Uint8Array } => { + const depositDomain = computeDomain( + fromHexString(DOMAIN_DEPOSIT), + forkVersion, + ) const eth1AddressWithdrawalPrefix = '0x01'; if ( eth1AddressWithdrawalPrefix + @@ -281,214 +286,119 @@ const verifyDepositData = ( withdrawalAddress.toLowerCase().slice(2) !== depositData.withdrawal_credentials ) { - return false; + return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) }; } if (distributedPublicKey !== depositData.pubkey) { - return false; + return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) }; } - return true; + + const depositMessageBuffer = computeDepositMsgRoot( + depositData + ); + const depositDataMessage = signingRoot( + depositDomain, + depositMessageBuffer, + ); + + + return { isValidDepositData: true, depositDataMsg: depositDataMessage }; }; -const verifyBuilderRegistration = ( +export const verifyBuilderRegistration = ( validator: DistributedValidator, feeRecipientAddress: string, -): boolean => { + 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 false + return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) }; } if ( feeRecipientAddress.toLowerCase() !== validator.builder_registration.message.fee_recipient.toLowerCase() ) { - return false + return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) }; } - return true -} + const builderRegistrationMessageBuffer = + computebuilderRegistrationMsgRoot( + validator.builder_registration.message, + ) -export const signingRoot = ( - domain: Uint8Array, - messageBuffer: Buffer, -): Uint8Array => { - return computeSigningRoot(messageBuffer, domain) + const builderRegistrationMessage = signingRoot( + builderDomain, + builderRegistrationMessageBuffer, + ) + + return { isValidBuilderRegistration: true, builderRegistrationMsg: builderRegistrationMessage } } -const verifyLockData = async (clusterLock: ClusterLock): Promise => { +export const verifyNodeSignatures = (clusterLock: ClusterLock):boolean => { 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; - const distributedPublicKey = validator.distributed_public_key; + 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') - //Needed in signature_aggregate verification - for (const element of validatorPublicShares) { - pubShares.push(fromHexString(element)) + const ENRsignature = { + r: nodeSignatures[i].slice(2, 66), + s: nodeSignatures[i].slice(66, 130), } - // Deposit data signature - if ( - semver.gte(clusterLock.cluster_definition.version, 'v1.6.0') && - validator.deposit_data - ) { - if ( - !verifyDepositData( - distributedPublicKey, - validator.deposit_data, - clusterLock.cluster_definition.validators[i].withdrawal_address, - ) - ) { - return false; - } + const nodeSignatureVerification = ec + .keyFromPublic(pubkey, 'hex') + .verify(lockHashWithout0x, ENRsignature) - 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)); + if (!nodeSignatureVerification) { + return false } + } - // 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 - } + return true +} - const builderRegistrationMessageBuffer = - computebuilderRegistrationMsgRoot( - validator.builder_registration.message, - ) - const builderRegistrationMessage = signingRoot( - builderDomain, - builderRegistrationMessageBuffer, - ) +export const signingRoot = ( + domain: Uint8Array, + messageBuffer: Buffer, +): Uint8Array => { + return computeSigningRoot(messageBuffer, domain) +} - pubKeys.push(fromHexString(validator.distributed_public_key)) - builderRegistrationAndDepositDataMessages.push(builderRegistrationMessage) - blsSignatures.push( - fromHexString(validator.builder_registration.signature), - ) - } - if ( - semver.gte(clusterLock.cluster_definition.version, 'v1.8.0') && - validator.partial_deposit_data - ) { - for (let j = 0; j < validator.partial_deposit_data.length; j++) { - const depositData = validator.partial_deposit_data[i]; - if ( - !verifyDepositData( - distributedPublicKey, - depositData, - clusterLock.cluster_definition.validators[i].withdrawal_address, - ) - ) { - return false; - } - - const depositMessageBuffer = computeDepositMsgRoot(depositData); - const depositDataMessage = signingRoot( - depositDomain, - depositMessageBuffer, - ); - - pubKeys.push(fromHexString(validator.distributed_public_key)); - builderRegistrationAndDepositDataMessages.push(depositDataMessage); - blsSignatures.push(fromHexString(depositData.signature as string)); - } - } - } - if ( - blsSignatures.length > 0 && - pubKeys.length > 0 && - builderRegistrationAndDepositDataMessages.length > 0 - ) { - // verify all deposit data and builder registration bls signatures - const aggregateBLSSignature = aggregateSignatures(blsSignatures) +const verifyLockData = async (clusterLock: ClusterLock): Promise => { - if ( - !verifyMultiple( - pubKeys, - builderRegistrationAndDepositDataMessages, - aggregateBLSSignature, - ) - ) { - return false - } - } + await init('herumi') - 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), - } + if (semver.eq(clusterLock.cluster_definition.version, 'v1.6.0')) { + return verifyDVV1X6(clusterLock) + } - const nodeSignatureVerification = ec - .keyFromPublic(pubkey, 'hex') - .verify(lockHashWithout0x, ENRsignature) + if (semver.eq(clusterLock.cluster_definition.version, 'v1.7.0')) { + return verifyDVV1X7(clusterLock) - if (!nodeSignatureVerification) { - return false - } - } } - // signature aggregate - if ( - !verifyAggregate( - pubShares, - fromHexString(clusterLock.lock_hash), - fromHexString(clusterLock.signature_aggregate), - ) - ) { - return false - } + if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) { + return verifyDVV1X8(clusterLock) - return true + } + return false } export const isValidClusterLock = async ( diff --git a/src/verification/v1.6.0.ts b/src/verification/v1.6.0.ts index 2bceeca..25dd879 100644 --- a/src/verification/v1.6.0.ts +++ b/src/verification/v1.6.0.ts @@ -3,7 +3,9 @@ import { strToUint8Array } from "../utils" import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; -import { ClusterDefintion, ClusterLock } from "../types"; +import { ClusterDefintion, ClusterLock, DepositData } from "../types"; +import { verifyDepositData } from "./common"; +import { aggregateSignatures, verifyAggregate, verifyMultiple } from "@chainsafe/bls"; // cluster defintion type DefinitionFieldsV1X6 = { @@ -162,7 +164,69 @@ export const hashClusterLockV1X6 = (cluster: ClusterLock): 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 index 6ec4a60..919f19f 100644 --- a/src/verification/v1.7.0.ts +++ b/src/verification/v1.7.0.ts @@ -3,7 +3,9 @@ import { strToUint8Array } from "../utils" import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; -import { ClusterDefintion, ClusterLock } from "../types"; +import { ClusterDefintion, ClusterLock, DepositData } from "../types"; +import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from "./common"; +import { aggregateSignatures, verifyAggregate, verifyMultiple } from "@chainsafe/bls"; // cluster defintion type DefinitionFieldsV1X7 = { @@ -116,7 +118,7 @@ const dvContainerTypeV1X7 = new ContainerType({ type LockContainerTypeV1X7 = ContainerType<{ cluster_definition: DefinitionContainerTypeV1X7; distributed_validators: ListCompositeType; - }>; +}>; /** * @returns SSZ Containerized type of cluster lock @@ -178,6 +180,103 @@ export const hashClusterLockV1X7 = (cluster: ClusterLock): string => { } +// 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), + ) + + } + + //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 index 6f1aafb..580b37f 100644 --- a/src/verification/v1.8.0.ts +++ b/src/verification/v1.8.0.ts @@ -3,7 +3,9 @@ import { strToUint8Array } from "../utils" import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; -import { ClusterDefintion, ClusterLock } from "../types"; +import { ClusterDefintion, ClusterLock, DepositData } from "../types"; +import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from "./common"; +import { aggregateSignatures, verifyAggregate, verifyMultiple } from "@chainsafe/bls"; // cluster defintion type DefinitionFieldsV1X8 = { @@ -158,7 +160,7 @@ export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { fromHexString(publicShare), ), //should be fixed - partial_deposit_data: (dVaidator.partial_deposit_data || []).map(depositData => { + partial_deposit_data: (dVaidator.partial_deposit_data as DepositData[]).map(depositData => { return { pubkey: fromHexString(depositData.pubkey as string), withdrawal_credentials: fromHexString( @@ -186,6 +188,103 @@ export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { } +// 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 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), + ) + + } + + //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/test/sdk-package-test/cluster.test.ts b/test/sdk-package-test/cluster.test.ts index af5043e..30afda5 100755 --- a/test/sdk-package-test/cluster.test.ts +++ b/test/sdk-package-test/cluster.test.ts @@ -27,7 +27,7 @@ describe('Cluster Definition', () => { let clusterDefinition: ClusterDefintion let secondConfigHash: string const clientWithoutAsigner = new Client({ - baseUrl: 'https://b90b-2a01-9700-155f-0-5d1-55a8-b411-54d7.ngrok-free.app', + baseUrl: 'https://obol-api-nonprod-dev.dev.obol.tech', chainId: 17000, }) @@ -111,7 +111,7 @@ describe('Poll Cluster Lock', () => { const { definition_hash: _, ...rest } = clusterLockV1X8.cluster_definition const clusterWithoutDefHash = rest const clientWithoutAsigner = new Client({ - baseUrl: 'https://b90b-2a01-9700-155f-0-5d1-55a8-b411-54d7.ngrok-free.app', + baseUrl: 'https://obol-api-nonprod-dev.dev.obol.tech', chainId: 17000, }) diff --git a/test/sdk-package-test/utils.ts b/test/sdk-package-test/utils.ts index a37765b..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://b90b-2a01-9700-155f-0-5d1-55a8-b411-54d7.ngrok-free.app', chainId: 17000 }, + { baseUrl: 'https://obol-api-nonprod-dev.dev.obol.tech', chainId: 17000 }, signer, ) From 54423bae85661ccb4f15d151bc5e1ed5ca1405ee Mon Sep 17 00:00:00 2001 From: HananINouman Date: Wed, 13 Mar 2024 22:42:49 +0300 Subject: [PATCH 08/12] fix lint errors --- src/ajv.ts | 21 ++-- src/constants.ts | 3 +- src/index.ts | 12 +- src/schema.ts | 6 +- src/types.ts | 3 +- src/utils.ts | 4 +- src/verification/common.ts | 70 ++++------- src/verification/sszTypes.ts | 6 +- src/verification/v1.6.0.ts | 131 ++++++++++---------- src/verification/v1.7.0.ts | 137 ++++++++++----------- src/verification/v1.8.0.ts | 164 ++++++++++++-------------- test/fixtures.ts | 136 ++++++++++----------- test/methods.test.ts | 8 +- test/sdk-package-test/cluster.test.ts | 4 +- test/sdk-package-test/fixtures.ts | 137 +++++++++++---------- 15 files changed, 395 insertions(+), 447 deletions(-) diff --git a/src/ajv.ts b/src/ajv.ts index d8d9268..ba7dfa0 100644 --- a/src/ajv.ts +++ b/src/ajv.ts @@ -1,22 +1,23 @@ import Ajv, { type ErrorObject } from 'ajv' -import { ether_to_gwei } from './constants'; +import { ETHER_TO_GWEI } from './constants' - -function validDpositAmounts(data: boolean, deposits: string[]) { - let sum = 0; +function validDpositAmounts (data: boolean, deposits: string[]): boolean { + let sum = 0 for (let i = 0; i < deposits.length; i++) { - const amount = parseInt(deposits[i]); - if (amount % ether_to_gwei !== 0 || amount > 32 * ether_to_gwei) { + const amount = parseInt(deposits[i]) + if (amount % ETHER_TO_GWEI !== 0 || amount > 32 * ETHER_TO_GWEI) { return false } - sum += amount; + sum += amount } - if (sum !== 32 * ether_to_gwei) { return false } { + if (sum !== 32 * ETHER_TO_GWEI) { + return false + } else { return true } } -export function validatePayload( +export function validatePayload ( data: any, schema: any, ): ErrorObject[] | undefined | null | boolean { @@ -25,7 +26,7 @@ export function validatePayload( keyword: 'validDpositAmounts', validate: validDpositAmounts, errors: true, - }); + }) const validate = ajv.compile(schema) const isValid = validate(data) if (!isValid) { diff --git a/src/constants.ts b/src/constants.ts index 84652f9..274d3e8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -117,5 +117,4 @@ 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; - +export const ETHER_TO_GWEI = 10 ** 9 diff --git a/src/index.ts b/src/index.ts index ea83979..82b2fb4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,7 +39,7 @@ export class Client extends Base { * An example of how to instantiate obol-sdk Client: * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L29) */ - constructor( + constructor ( config: { baseUrl?: string, chainId?: number }, signer?: Signer, ) { @@ -56,7 +56,7 @@ export class Client extends Base { * An example of how to use createClusterDefinition: * [createObolCluster](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async createClusterDefinition(newCluster: ClusterPayload): Promise { + async createClusterDefinition (newCluster: ClusterPayload): Promise { if (!this.signer) { throw new Error('Signer is required in createClusterDefinition') } validatePayload(newCluster, definitionSchema) @@ -70,7 +70,7 @@ export class Client extends Base { timestamp: new Date().toISOString(), threshold: Math.ceil((2 * newCluster.operators.length) / 3), num_validators: newCluster.validators.length, - deposit_amounts: newCluster.deposit_amounts ? newCluster.deposit_amounts : ["32000000000"] + deposit_amounts: newCluster.deposit_amounts ? newCluster.deposit_amounts : ['32000000000'] } try { @@ -115,7 +115,7 @@ export class Client extends Base { * An example of how to use acceptClusterDefinition: * [acceptClusterDefinition](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async acceptClusterDefinition( + async acceptClusterDefinition ( operatorPayload: OperatorPayload, configHash: string, ): Promise { @@ -167,7 +167,7 @@ export class Client extends Base { * An example of how to use getClusterDefinition: * [getObolClusterDefinition](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async getClusterDefinition(configHash: string): Promise { + async getClusterDefinition (configHash: string): Promise { const clusterDefinition: ClusterDefintion = await this.request( `/dv/${configHash}`, { @@ -186,7 +186,7 @@ export class Client extends Base { * An example of how to use getClusterLock: * [getObolClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts) */ - async getClusterLock(configHash: string): Promise { + async getClusterLock (configHash: string): Promise { const lock: ClusterLock = await this.request( `/lock/configHash/${configHash}`, { diff --git a/src/schema.ts b/src/schema.ts index 8467a39..474a3b3 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -57,10 +57,10 @@ export const definitionSchema = { type: 'array', items: { type: 'string', - pattern: "^[0-9]+$", + pattern: '^[0-9]+$', }, - validDpositAmounts:true + validDpositAmounts: true }, }, - required: ['name','operators', 'validators'], + required: ['name', 'operators', 'validators'], } diff --git a/src/types.ts b/src/types.ts index 13b67a8..251e805 100644 --- a/src/types.ts +++ b/src/types.ts @@ -182,13 +182,12 @@ export interface DistributedValidator { deposit_data?: Partial /** The deposit data with partial amounts or full amount for activating the DV. */ - partial_deposit_data?: Partial[] + partial_deposit_data?: Array> /** pre-generated signed validator builder registration to be sent to builder network. */ builder_registration: BuilderRegistration } - /** * Cluster Details after DKG is complete */ diff --git a/src/utils.ts b/src/utils.ts index 65a81ba..38025e5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ -import { DefinitionFlow } from "./constants" -import { ClusterDefintion } from "./types" +import { DefinitionFlow } from './constants' +import { type ClusterDefintion } from './types' export const hexWithout0x = (hex: string): string => { return hex.slice(2, hex.length) diff --git a/src/verification/common.ts b/src/verification/common.ts index 9a1f786..27609cd 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -4,17 +4,14 @@ import { import elliptic from 'elliptic' import { init, - aggregateSignatures, - verifyMultiple, - verifyAggregate, } from '@chainsafe/bls' -import { FORK_MAPPING, type ClusterDefintion, type ClusterLock, DepositData, BuilderRegistrationMessage, DistributedValidator } from '../types.js' +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 { DOMAIN_APPLICATION_BUILDER, DOMAIN_DEPOSIT, type 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' @@ -51,20 +48,16 @@ export const clusterConfigOrDefinitionHash = ( } if (semver.eq(cluster.version, 'v1.8.0')) { - definitionType = clusterDefinitionContainerTypeV1X8(configOnly); - val = hashClusterDefinitionV1X8(cluster, configOnly); + definitionType = clusterDefinitionContainerTypeV1X8(configOnly) + val = hashClusterDefinitionV1X8(cluster, configOnly) return ( '0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex') ) } - throw new Error("unsupported version") - + throw new Error('unsupported version') } - - - // cluster-lock hash /** @@ -74,25 +67,22 @@ export const clusterConfigOrDefinitionHash = ( */ export const clusterLockHash = (clusterLock: ClusterLock): string => { if (semver.eq(clusterLock.cluster_definition.version, 'v1.6.0')) { - return hashClusterLockV1X6(clusterLock); + return hashClusterLockV1X6(clusterLock) } if (semver.eq(clusterLock.cluster_definition.version, 'v1.7.0')) { - return hashClusterLockV1X7(clusterLock); + return hashClusterLockV1X7(clusterLock) } if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) { - return hashClusterLockV1X8(clusterLock); + return hashClusterLockV1X8(clusterLock) } - //other versions - throw new Error('unsupported version'); -}; - - - + // other versions + throw new Error('unsupported version') +} -//Lock verification +// Lock verification // cluster-definition signatures verificatin @@ -279,32 +269,30 @@ export const verifyDepositData = ( fromHexString(DOMAIN_DEPOSIT), forkVersion, ) - const eth1AddressWithdrawalPrefix = '0x01'; + const eth1AddressWithdrawalPrefix = '0x01' if ( eth1AddressWithdrawalPrefix + '0'.repeat(22) + withdrawalAddress.toLowerCase().slice(2) !== depositData.withdrawal_credentials ) { - return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) }; + return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) } } if (distributedPublicKey !== depositData.pubkey) { - return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) }; + return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) } } - const depositMessageBuffer = computeDepositMsgRoot( depositData - ); + ) const depositDataMessage = signingRoot( depositDomain, depositMessageBuffer, - ); - + ) - return { isValidDepositData: true, depositDataMsg: depositDataMessage }; -}; + return { isValidDepositData: true, depositDataMsg: depositDataMessage } +} export const verifyBuilderRegistration = ( validator: DistributedValidator, @@ -314,19 +302,19 @@ export const verifyBuilderRegistration = ( ): { isValidBuilderRegistration: boolean, builderRegistrationMsg: Uint8Array } => { const builderDomain = computeDomain( fromHexString(DOMAIN_APPLICATION_BUILDER), - forkVersion); + forkVersion) if ( validator.distributed_public_key !== validator.builder_registration.message.pubkey ) { - return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) }; + return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) } } if ( feeRecipientAddress.toLowerCase() !== validator.builder_registration.message.fee_recipient.toLowerCase() ) { - return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) }; + return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) } } const builderRegistrationMessageBuffer = @@ -342,10 +330,9 @@ export const verifyBuilderRegistration = ( return { isValidBuilderRegistration: true, builderRegistrationMsg: builderRegistrationMessage } } - -export const verifyNodeSignatures = (clusterLock: ClusterLock):boolean => { - const ec = new elliptic.ec('secp256k1'); - const nodeSignatures = clusterLock.node_signatures; +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 @@ -371,7 +358,6 @@ export const verifyNodeSignatures = (clusterLock: ClusterLock):boolean => { return true } - export const signingRoot = ( domain: Uint8Array, messageBuffer: Buffer, @@ -379,10 +365,7 @@ export const signingRoot = ( return computeSigningRoot(messageBuffer, domain) } - - const verifyLockData = async (clusterLock: ClusterLock): Promise => { - await init('herumi') if (semver.eq(clusterLock.cluster_definition.version, 'v1.6.0')) { @@ -391,12 +374,10 @@ const verifyLockData = async (clusterLock: ClusterLock): Promise => { 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 } @@ -436,4 +417,3 @@ export const isValidClusterLock = async ( return false } } - diff --git a/src/verification/sszTypes.ts b/src/verification/sszTypes.ts index 4096923..05c9302 100644 --- a/src/verification/sszTypes.ts +++ b/src/verification/sszTypes.ts @@ -1,5 +1,5 @@ -import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, UintNumberType } from "@chainsafe/ssz" -import { UintNumberByteLen } from "@chainsafe/ssz/lib/type/uint" +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), @@ -76,4 +76,4 @@ export const depositMessageType = new ContainerType({ export const signingRootType = new ContainerType({ objectRoot: new ByteVectorType(32), domain: new ByteVectorType(32), -}) \ No newline at end of file +}) diff --git a/src/verification/v1.6.0.ts b/src/verification/v1.6.0.ts index 25dd879..95ad644 100644 --- a/src/verification/v1.6.0.ts +++ b/src/verification/v1.6.0.ts @@ -1,32 +1,32 @@ -import { UintNumberByteLen, UintNumberType } from "@chainsafe/ssz/lib/type/uint"; -import { strToUint8Array } from "../utils" -import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; -import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; -import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; -import { ClusterDefintion, ClusterLock, DepositData } from "../types"; -import { verifyDepositData } from "./common"; -import { aggregateSignatures, verifyAggregate, verifyMultiple } from "@chainsafe/bls"; +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; + 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; -}; + > + creator: typeof creatorContainerType | typeof creatorAddressWrapperType + validators: ListCompositeType + config_hash?: ByteVectorType +} type DefinitionContainerTypeV1X6 = - ContainerType; + ContainerType /** * Returns the containerized cluster definition @@ -48,35 +48,35 @@ export const clusterDefinitionContainerTypeV1X6 = ( 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); -}; + 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); + 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) } @@ -85,26 +85,26 @@ export const hashClusterDefinitionV1X6 = ( 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); + val.config_hash = fromHexString(cluster.config_hash) } - return val; -}; + return val +} // cluster lock @@ -118,9 +118,9 @@ const dvContainerTypeV1X6 = new ContainerType({ }) type LockContainerTypeV1X6 = ContainerType<{ - cluster_definition: DefinitionContainerTypeV1X6; - distributed_validators: ListCompositeType; -}>; + cluster_definition: DefinitionContainerTypeV1X6 + distributed_validators: ListCompositeType +}> /** * @returns SSZ Containerized type of cluster lock @@ -158,27 +158,26 @@ export const hashClusterLockV1X6 = (cluster: ClusterLock): string => { ), amount: parseInt(dVaidator.deposit_data?.amount as string), signature: fromHexString(dVaidator.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 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; + const validator = validators[i] + const validatorPublicShares = validator.public_shares + const distributedPublicKey = validator.distributed_public_key - //Needed in signature_aggregate verification + // Needed in signature_aggregate verification for (const element of validatorPublicShares) { pubShares.push(fromHexString(element)) } @@ -188,18 +187,17 @@ export const verifyDVV1X6 = (clusterLock: ClusterLock): boolean => { validator.deposit_data as Partial, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version - ); + ) if ( !isValidDepositData ) { - return false; + return false } - pubKeys.push(fromHexString(validator.distributed_public_key)); - builderRegistrationAndDepositDataMessages.push(depositDataMsg); - blsSignatures.push(fromHexString(validator.deposit_data?.signature as string)); - + pubKeys.push(fromHexString(validator.distributed_public_key)) + builderRegistrationAndDepositDataMessages.push(depositDataMsg) + blsSignatures.push(fromHexString(validator.deposit_data?.signature as string)) } const aggregateBLSSignature = aggregateSignatures(blsSignatures) @@ -214,7 +212,6 @@ export const verifyDVV1X6 = (clusterLock: ClusterLock): boolean => { return false } - if ( !verifyAggregate( pubShares, @@ -227,7 +224,3 @@ export const verifyDVV1X6 = (clusterLock: ClusterLock): boolean => { return true } - - - - diff --git a/src/verification/v1.7.0.ts b/src/verification/v1.7.0.ts index 919f19f..ae194a7 100644 --- a/src/verification/v1.7.0.ts +++ b/src/verification/v1.7.0.ts @@ -1,32 +1,32 @@ -import { UintNumberByteLen, UintNumberType } from "@chainsafe/ssz/lib/type/uint"; -import { strToUint8Array } from "../utils" -import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; -import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; -import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; -import { ClusterDefintion, ClusterLock, DepositData } from "../types"; -import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from "./common"; -import { aggregateSignatures, verifyAggregate, verifyMultiple } from "@chainsafe/bls"; +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; + 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; -}; + > + creator: typeof creatorContainerType | typeof creatorAddressWrapperType + validators: ListCompositeType + config_hash?: ByteVectorType +} type DefinitionContainerTypeV1X7 = - ContainerType; + ContainerType /** * Returns the containerized cluster definition @@ -48,35 +48,35 @@ export const clusterDefinitionContainerTypeV1X7 = ( 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); -}; + 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); + 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) } @@ -85,26 +85,26 @@ export const hashClusterDefinitionV1X7 = ( 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); + val.config_hash = fromHexString(cluster.config_hash) } - return val; -}; + return val +} // cluster lock @@ -116,9 +116,9 @@ const dvContainerTypeV1X7 = new ContainerType({ }) type LockContainerTypeV1X7 = ContainerType<{ - cluster_definition: DefinitionContainerTypeV1X7; - distributed_validators: ListCompositeType; -}>; + cluster_definition: DefinitionContainerTypeV1X7 + distributed_validators: ListCompositeType +}> /** * @returns SSZ Containerized type of cluster lock @@ -179,10 +179,9 @@ export const hashClusterLockV1X7 = (cluster: ClusterLock): 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 validators = clusterLock.distributed_validators const pubShares = [] @@ -190,36 +189,35 @@ export const verifyDVV1X7 = (clusterLock: ClusterLock): boolean => { 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; + const validator = validators[i] + const validatorPublicShares = validator.public_shares + const distributedPublicKey = validator.distributed_public_key - //Needed in signature_aggregate verification + // Needed in signature_aggregate verification for (const element of validatorPublicShares) { pubShares.push(fromHexString(element)) } - //Deposit Data Verification + // 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; + return false } - pubKeys.push(fromHexString(distributedPublicKey)); - builderRegistrationAndDepositDataMessages.push(depositDataMsg); - blsSignatures.push(fromHexString(validator.deposit_data?.signature as string)); + pubKeys.push(fromHexString(distributedPublicKey)) + builderRegistrationAndDepositDataMessages.push(depositDataMsg) + blsSignatures.push(fromHexString(validator.deposit_data?.signature as string)) - //Builder Registration Verification + // Builder Registration Verification const { isValidBuilderRegistration, builderRegistrationMsg } = verifyBuilderRegistration( validator, clusterLock.cluster_definition.validators[i].fee_recipient_address, @@ -229,7 +227,7 @@ export const verifyDVV1X7 = (clusterLock: ClusterLock): boolean => { if ( !isValidBuilderRegistration ) { - return false; + return false } pubKeys.push(fromHexString(distributedPublicKey)) @@ -237,10 +235,9 @@ export const verifyDVV1X7 = (clusterLock: ClusterLock): boolean => { blsSignatures.push( fromHexString(validator.builder_registration.signature), ) - } - //BLS signatures verification + // BLS signatures verification const aggregateBLSSignature = aggregateSignatures(blsSignatures) if ( @@ -275,9 +272,3 @@ export const verifyDVV1X7 = (clusterLock: ClusterLock): boolean => { return true } - - - - - - diff --git a/src/verification/v1.8.0.ts b/src/verification/v1.8.0.ts index 580b37f..5a38ad8 100644 --- a/src/verification/v1.8.0.ts +++ b/src/verification/v1.8.0.ts @@ -1,32 +1,32 @@ -import { UintNumberByteLen, UintNumberType } from "@chainsafe/ssz/lib/type/uint"; -import { strToUint8Array } from "../utils" -import { builderRegistrationContainer, creatorAddressWrapperType, creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, operatorAddressWrapperType, operatorContainerType, validatorsContainerType } from "./sszTypes"; -import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString } from "@chainsafe/ssz"; -import { ValueOfFields } from "@chainsafe/ssz/lib/view/container"; -import { ClusterDefintion, ClusterLock, DepositData } from "../types"; -import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from "./common"; -import { aggregateSignatures, verifyAggregate, verifyMultiple } from "@chainsafe/bls"; +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; + 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; -}; + > + creator: typeof creatorContainerType | typeof creatorAddressWrapperType + validators: ListCompositeType + deposit_amounts: ListBasicType + config_hash?: ByteVectorType +} -type DefinitionContainerTypeV1X8 = ContainerType; +type DefinitionContainerTypeV1X8 = ContainerType /** * Returns the containerized cluster definition @@ -52,35 +52,35 @@ export const clusterDefinitionContainerTypeV1X8 = ( new UintNumberType(8 as UintNumberByteLen), 256, ), - }; + } if (!configOnly) { returnedContainerType = { ...returnedContainerType, config_hash: new ByteVectorType(32), - }; + } } - return new ContainerType(returnedContainerType); -}; + 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); + 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) } @@ -89,31 +89,29 @@ export const hashClusterDefinitionV1X8 = ( 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?.map((amount: string) => { - return parseInt(amount); - }) || ["32000000000"].map((amount: string) => { - return parseInt(amount); - }); + } + }) + val.deposit_amounts = (cluster.deposit_amounts as string[]).map((amount: string) => { + return parseInt(amount) + }) if (!configOnly) { - val.config_hash = fromHexString(cluster.config_hash); + val.config_hash = fromHexString(cluster.config_hash) } - return val; -}; + return val +} // cluster lock @@ -125,9 +123,9 @@ const dvContainerTypeV1X8 = new ContainerType({ }) type LockContainerTypeV1X8 = ContainerType<{ - cluster_definition: DefinitionContainerTypeV1X8; - distributed_validators: ListCompositeType; -}>; + cluster_definition: DefinitionContainerTypeV1X8 + distributed_validators: ListCompositeType +}> /** * @returns SSZ Containerized type of cluster lock @@ -159,16 +157,16 @@ export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { public_shares: dVaidator.public_shares.map(publicShare => fromHexString(publicShare), ), - //should be fixed + // should be fixed partial_deposit_data: (dVaidator.partial_deposit_data as DepositData[]).map(depositData => { return { - pubkey: fromHexString(depositData.pubkey as string), + pubkey: fromHexString(depositData.pubkey), withdrawal_credentials: fromHexString( - depositData.withdrawal_credentials as string, + depositData.withdrawal_credentials, ), - amount: parseInt(depositData.amount as string), - signature: fromHexString(depositData.signature as string), - }; + amount: parseInt(depositData.amount), + signature: fromHexString(depositData.signature), + } }), builder_registration: { message: { @@ -181,54 +179,52 @@ export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { }, signature: fromHexString(dVaidator.builder_registration.signature), }, - }; - }); + } + }) return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex') } - // DV verification export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => { - const validators = clusterLock.distributed_validators; + 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; + const validator = validators[i] + const validatorPublicShares = validator.public_shares + const distributedPublicKey = validator.distributed_public_key - //Needed in signature_aggregate verification + // Needed in signature_aggregate verification for (const element of validatorPublicShares) { pubShares.push(fromHexString(element)) } - //Deposit Data Verification + // 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 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; + return false } - pubKeys.push(fromHexString(distributedPublicKey)); - builderRegistrationAndDepositDataMessages.push(depositDataMsg); - blsSignatures.push(fromHexString(depositData?.signature as string)); + pubKeys.push(fromHexString(distributedPublicKey)) + builderRegistrationAndDepositDataMessages.push(depositDataMsg) + blsSignatures.push(fromHexString(depositData?.signature)) } - //Builder Registration Verification + // Builder Registration Verification const { isValidBuilderRegistration, builderRegistrationMsg } = verifyBuilderRegistration( validator, clusterLock.cluster_definition.validators[i].fee_recipient_address, @@ -238,7 +234,7 @@ export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => { if ( !isValidBuilderRegistration ) { - return false; + return false } pubKeys.push(fromHexString(distributedPublicKey)) @@ -246,10 +242,9 @@ export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => { blsSignatures.push( fromHexString(validator.builder_registration.signature), ) - } - //BLS signatures verification + // BLS signatures verification const aggregateBLSSignature = aggregateSignatures(blsSignatures) if ( @@ -284,8 +279,3 @@ export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => { return true } - - - - - diff --git a/test/fixtures.ts b/test/fixtures.ts index 5693d6f..4bcf2b2 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,4 +1,4 @@ -//v1.7.0 +// v1.7.0 export const clusterConfigV1X7 = { name: 'testSDK', @@ -139,133 +139,133 @@ export const clusterConfigV1X8 = { }, ], deposit_amounts: [ - "8000000000", - "16000000000", - "8000000000" + '8000000000', + '16000000000', + '8000000000' ], } export const clusterLockV1X8 = { cluster_definition: { - name: "test cluster", + name: 'test cluster', creator: { - address: "0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c", - config_signature: "0x03b41a12847064090333026a10bc0c6f9c51400e67b414fe74aa7df91388583d6bea930d525478e25d85aa49f3c649723e4158895fadd0e787fe8579d43c18cb00" + address: '0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c', + config_signature: '0x03b41a12847064090333026a10bc0c6f9c51400e67b414fe74aa7df91388583d6bea930d525478e25d85aa49f3c649723e4158895fadd0e787fe8579d43c18cb00' }, operators: [ { - "address": "0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c", - "enr": "enr:-HW4QIHPUOMb34YoizKGhz7nsDNQ7hCaiuwyscmeaOQ04awdH05gDnGrZhxDfzcfHssCDeB-esi99A2RoZia6UaYBCuAgmlkgnY0iXNlY3AyNTZrMaECTUts0TYQMsqb0q652QCqTUXZ6tgKyUIzdMRRpyVNB2Y", - "config_signature": "0xffafd355831aa993e5a019419403d61533649edc546b4f497bc305d7620dcb787756f9748be1ea76f7236692faeff7c1d2e7b06bf89894d07518de2d4ff45b4d00", - "enr_signature": "0x20b5b4ba720053c6ea35a710cdd9d81440ae3a69c204edb06184ea2328ff3a290bd00c256d71f6f4daed2f995931b38c3f6bd0b17796f4e121278073e049086800" + 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: '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" + 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", + 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: '0x52fdfc072182654f163f5f0f9a621d729566c74d', + withdrawal_address: '0x81855ad8681d0d86d1e91e00167939cb6694d2c4' }, { - fee_recipient_address: "0xeb9d18a44784045d87f3c67cf22746e995af5a25", - withdrawal_address: "0x5fb90badb37c5821b6d95526a41a9504680b4e7c" + fee_recipient_address: '0xeb9d18a44784045d87f3c67cf22746e995af5a25', + withdrawal_address: '0x5fb90badb37c5821b6d95526a41a9504680b4e7c' } ], - dkg_algorithm: "frost", - fork_version: "0x00001020", + dkg_algorithm: 'frost', + fork_version: '0x00001020', deposit_amounts: [ - "8000000000", - "16000000000", - "8000000000" + '8000000000', + '16000000000', + '8000000000' ], - config_hash: "0xe604bdf1649e2bcc5399149d4a683feacfc5678abe990d75e202791984208c53", - definition_hash: "0x123be6c24ec74366b0a318de42d36e09a43a08c3db72800698a958510c804a0b" + config_hash: '0xe604bdf1649e2bcc5399149d4a683feacfc5678abe990d75e202791984208c53', + definition_hash: '0x123be6c24ec74366b0a318de42d36e09a43a08c3db72800698a958510c804a0b' }, distributed_validators: [ { - distributed_public_key: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7", + distributed_public_key: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', public_shares: [ - "0x804841f5b773b7cda35f2ceaacbd7b52afba38b6d65d5c4b3b1d3cdc905c21c0f7d1ac18cd4847b0cf56ac7ed41d5c19", - "0xac2362cbfdd573137a5f46727981363198c8a8b66eb29123014f3e1dee335132973973bddb4a4c592c8c74ff270b5982", - "0xb63dd0fb59a513b0f9f10ed3d88a54aa72c189faf2c2d2e4d66a81730a81a89d6feac0ff8e7b6b488c5131aa33845b47" + '0x804841f5b773b7cda35f2ceaacbd7b52afba38b6d65d5c4b3b1d3cdc905c21c0f7d1ac18cd4847b0cf56ac7ed41d5c19', + '0xac2362cbfdd573137a5f46727981363198c8a8b66eb29123014f3e1dee335132973973bddb4a4c592c8c74ff270b5982', + '0xb63dd0fb59a513b0f9f10ed3d88a54aa72c189faf2c2d2e4d66a81730a81a89d6feac0ff8e7b6b488c5131aa33845b47' ], builder_registration: { message: { - fee_recipient: "0x52fdfc072182654f163f5f0f9a621d729566c74d", + fee_recipient: '0x52fdfc072182654f163f5f0f9a621d729566c74d', gas_limit: 30000000, timestamp: 1616508000, - pubkey: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7" + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7' }, - signature: "0x8a8085f002d0332c689baef8ecbab1ca3632e2536fa9f0587212f50429a4617d1cac1722b55d521ffb58424f6bc4f9640bdd1994e9abaff1fe00ea641aabf89249a8ed64aee5f7508a78dc9a6e2fa626cc707e5f9f94b9634084ea825c082b79" + signature: '0x8a8085f002d0332c689baef8ecbab1ca3632e2536fa9f0587212f50429a4617d1cac1722b55d521ffb58424f6bc4f9640bdd1994e9abaff1fe00ea641aabf89249a8ed64aee5f7508a78dc9a6e2fa626cc707e5f9f94b9634084ea825c082b79' }, partial_deposit_data: [ { - pubkey: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7", - withdrawal_credentials: "0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4", - amount: "8000000000", - signature: "0x84614b278beed177d17f8e61ec6c4c4c17fb41adde71dedb5977ce19354a4ec24bed65021109d7d690d014fc531cf7040b3285877c8bfc35b1a2dd64fdbcab086132982fb036c31071824ea9ec6ca28ff6aaf86a425350c2bec8012b399342eb" + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', + withdrawal_credentials: '0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4', + amount: '8000000000', + signature: '0x84614b278beed177d17f8e61ec6c4c4c17fb41adde71dedb5977ce19354a4ec24bed65021109d7d690d014fc531cf7040b3285877c8bfc35b1a2dd64fdbcab086132982fb036c31071824ea9ec6ca28ff6aaf86a425350c2bec8012b399342eb' }, { - pubkey: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7", - withdrawal_credentials: "0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4", - amount: "16000000000", - signature: "0xac5bcb369e8dde110604f6ae829a3432f82a99b0a996e15f4be6426acbe690a1aadb4b365d8b10a36737b2cd8c7f561214d4e4df3626cc9664f663111d15efbd8d18cffff5c3eff407fe2cc478244caea7f9f2afee83a0ae8aa2587365b8e54a" + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', + withdrawal_credentials: '0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4', + amount: '16000000000', + signature: '0xac5bcb369e8dde110604f6ae829a3432f82a99b0a996e15f4be6426acbe690a1aadb4b365d8b10a36737b2cd8c7f561214d4e4df3626cc9664f663111d15efbd8d18cffff5c3eff407fe2cc478244caea7f9f2afee83a0ae8aa2587365b8e54a' } ] }, { - distributed_public_key: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a", + distributed_public_key: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', public_shares: [ - "0x898c28241cb2386fdbfa26ee08fcc804ee953695741691d4f8c45a36f08dd319a09173a9ef632eb7a35f94ff9241cd8e", - "0xb7d73b8ea0d74dc7eb70f305c6666dd9dca749ea1084b25f942e0d0909211f6556c2955266a7ff54a204146676bf1c8c", - "0x8fbe3bb3c23e9dcb093ee45a28efc120ee2a923d4c62a0377d0a6ed7a3da8fa185456bbaec41e13fd84a2a410023a742" + '0x898c28241cb2386fdbfa26ee08fcc804ee953695741691d4f8c45a36f08dd319a09173a9ef632eb7a35f94ff9241cd8e', + '0xb7d73b8ea0d74dc7eb70f305c6666dd9dca749ea1084b25f942e0d0909211f6556c2955266a7ff54a204146676bf1c8c', + '0x8fbe3bb3c23e9dcb093ee45a28efc120ee2a923d4c62a0377d0a6ed7a3da8fa185456bbaec41e13fd84a2a410023a742' ], builder_registration: { message: { - fee_recipient: "0xeb9d18a44784045d87f3c67cf22746e995af5a25", + fee_recipient: '0xeb9d18a44784045d87f3c67cf22746e995af5a25', gas_limit: 30000000, timestamp: 1616508000, - pubkey: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a" + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a' }, - signature: "0xa941fcec27add0165a1bd76bb4b5d3a5f4e96e0e7b9a9edad4188dda914b97519c71f5964a467061cfee91f317eaa321174d5dbd8e94a6486c62e8bd10aad6ead7494696e2926b68fea446b9d868abde763a177083e87921d5e1b09c6b2aec2a" + signature: '0xa941fcec27add0165a1bd76bb4b5d3a5f4e96e0e7b9a9edad4188dda914b97519c71f5964a467061cfee91f317eaa321174d5dbd8e94a6486c62e8bd10aad6ead7494696e2926b68fea446b9d868abde763a177083e87921d5e1b09c6b2aec2a' }, partial_deposit_data: [ { - pubkey: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a", - withdrawal_credentials: "0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c", - amount: "8000000000", - signature: "0x88b20e744a83679da4df81416358214f1e62535498b9ac38eb622b01cad2090554b2f1f7b3ac9032c15ccd31fffbb1cf0f5589b7703ecc4441e5bd7bf7c388ac1423c41b5c76cbee9969ffade054edcd1a883f80df813b52786393d318db007b" + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', + withdrawal_credentials: '0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c', + amount: '8000000000', + signature: '0x88b20e744a83679da4df81416358214f1e62535498b9ac38eb622b01cad2090554b2f1f7b3ac9032c15ccd31fffbb1cf0f5589b7703ecc4441e5bd7bf7c388ac1423c41b5c76cbee9969ffade054edcd1a883f80df813b52786393d318db007b' }, { - pubkey: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a", - withdrawal_credentials: "0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c", - amount: "16000000000", - signature: "0x94d9db7b4527e6eb308d387f168089a51d1deffc2c985faf1f7f8e82fbc9cb93c7f10c6a7bbca4fc25a1cfc95de28432037cf7727c1db0ad6d1fb0f1813d5904fba4ab8aebfeccfcded2f915bd48fb46155131b24adb0ba5e764d7ff6d3c82a5" + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', + withdrawal_credentials: '0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c', + amount: '16000000000', + signature: '0x94d9db7b4527e6eb308d387f168089a51d1deffc2c985faf1f7f8e82fbc9cb93c7f10c6a7bbca4fc25a1cfc95de28432037cf7727c1db0ad6d1fb0f1813d5904fba4ab8aebfeccfcded2f915bd48fb46155131b24adb0ba5e764d7ff6d3c82a5' } ] } ], - signature_aggregate: "0xb54fc9fcfe6827f519a29ff0a8bc9a06aafd197253a6def9f45bf79b023e71f3bd26bd0365f0beb7d60c1146e33be127161eb034af4a4de619e9d6971174224fdc18c04821d9e5b7abaeaedc01755b6e33addb2dc820aa361890a634a0252422", - lock_hash: "0x1f598e309b715ba0141034b495975e3bed0231ad92da49dfff462765049df671", + signature_aggregate: '0xb54fc9fcfe6827f519a29ff0a8bc9a06aafd197253a6def9f45bf79b023e71f3bd26bd0365f0beb7d60c1146e33be127161eb034af4a4de619e9d6971174224fdc18c04821d9e5b7abaeaedc01755b6e33addb2dc820aa361890a634a0252422', + lock_hash: '0x1f598e309b715ba0141034b495975e3bed0231ad92da49dfff462765049df671', node_signatures: [ - "0xf4317dc1f01738f84b2624866e8b4e85e92394fabb49218ef8a6dfe7ee4fdaab015742379328b173204504332a5e15450d5a127bbe8b8a2209cd9fa12b85cf4501", - "0x9e4726f7cce4cfad963eb04aaeec677fa7d1010d66640867d0ee11c75fad45dd6ad8fad9ad4a3c042bd1ab298a5598896b9de08acfde476f9aa65c48e3def7f901", - "0x54a89155ef4a6e319c0411f29963554fe551abce6d8463661cc5449a67243d053292f0190432cdcbcfc6e651815b093d55b4adbfc8c82f85ee1e1af798d9bae400" + '0xf4317dc1f01738f84b2624866e8b4e85e92394fabb49218ef8a6dfe7ee4fdaab015742379328b173204504332a5e15450d5a127bbe8b8a2209cd9fa12b85cf4501', + '0x9e4726f7cce4cfad963eb04aaeec677fa7d1010d66640867d0ee11c75fad45dd6ad8fad9ad4a3c042bd1ab298a5598896b9de08acfde476f9aa65c48e3def7f901', + '0x54a89155ef4a6e319c0411f29963554fe551abce6d8463661cc5449a67243d053292f0190432cdcbcfc6e651815b093d55b4adbfc8c82f85ee1e1af798d9bae400' ] } diff --git a/test/methods.test.ts b/test/methods.test.ts index ba38392..dbd6f5a 100644 --- a/test/methods.test.ts +++ b/test/methods.test.ts @@ -89,11 +89,9 @@ describe('Cluster Client', () => { try { await clientInstance.createClusterDefinition({ ...clusterConfigV1X7, - deposit_amounts: ["34000000"] + deposit_amounts: ['34000000'] }) - } catch (error: any) { - console.log(error.message) expect(error.message).toEqual( "Schema compilation errors', must pass \"validDpositAmounts\" keyword validation", ) @@ -217,8 +215,8 @@ describe('Cluster Client without a signer', () => { expect(clusterLock.lock_hash).toEqual(clusterLockV1X8.lock_hash) }) - test.each([{ version: "v1.7.0", clusterLock: clusterLockV1X7 }, { version: "v1.8.0", clusterLock: clusterLockV1X8 }])( - `$version: 'should return true on verified cluster lock'`, + test.each([{ 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 30afda5..b8b55f8 100755 --- a/test/sdk-package-test/cluster.test.ts +++ b/test/sdk-package-test/cluster.test.ts @@ -196,8 +196,8 @@ describe('Poll Cluster Lock', () => { ) }) - test.each([{ version: "v1.7.0", clusterLock: clusterLockV1X7 }, { version: "v1.8.0", clusterLock: clusterLockV1X8 }])( - `$version: 'should return true on verified cluster lock'`, + test.each([{ 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/fixtures.ts b/test/sdk-package-test/fixtures.ts index 53d1b0e..be95cd1 100644 --- a/test/sdk-package-test/fixtures.ts +++ b/test/sdk-package-test/fixtures.ts @@ -1,4 +1,3 @@ - export const enr = 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak' @@ -142,135 +141,133 @@ export const clusterConfigV1X8 = { }, ], deposit_amounts: [ - "8000000000", - "16000000000", - "8000000000" + '8000000000', + '16000000000', + '8000000000' ], } export const clusterLockV1X8 = { cluster_definition: { - name: "test cluster", + name: 'test cluster', creator: { - address: "0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c", - config_signature: "0x03b41a12847064090333026a10bc0c6f9c51400e67b414fe74aa7df91388583d6bea930d525478e25d85aa49f3c649723e4158895fadd0e787fe8579d43c18cb00" + address: '0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c', + config_signature: '0x03b41a12847064090333026a10bc0c6f9c51400e67b414fe74aa7df91388583d6bea930d525478e25d85aa49f3c649723e4158895fadd0e787fe8579d43c18cb00' }, operators: [ { - "address": "0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c", - "enr": "enr:-HW4QIHPUOMb34YoizKGhz7nsDNQ7hCaiuwyscmeaOQ04awdH05gDnGrZhxDfzcfHssCDeB-esi99A2RoZia6UaYBCuAgmlkgnY0iXNlY3AyNTZrMaECTUts0TYQMsqb0q652QCqTUXZ6tgKyUIzdMRRpyVNB2Y", - "config_signature": "0xffafd355831aa993e5a019419403d61533649edc546b4f497bc305d7620dcb787756f9748be1ea76f7236692faeff7c1d2e7b06bf89894d07518de2d4ff45b4d00", - "enr_signature": "0x20b5b4ba720053c6ea35a710cdd9d81440ae3a69c204edb06184ea2328ff3a290bd00c256d71f6f4daed2f995931b38c3f6bd0b17796f4e121278073e049086800" + 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: '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" + 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", + 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: '0x52fdfc072182654f163f5f0f9a621d729566c74d', + withdrawal_address: '0x81855ad8681d0d86d1e91e00167939cb6694d2c4' }, { - fee_recipient_address: "0xeb9d18a44784045d87f3c67cf22746e995af5a25", - withdrawal_address: "0x5fb90badb37c5821b6d95526a41a9504680b4e7c" + fee_recipient_address: '0xeb9d18a44784045d87f3c67cf22746e995af5a25', + withdrawal_address: '0x5fb90badb37c5821b6d95526a41a9504680b4e7c' } ], - dkg_algorithm: "frost", - fork_version: "0x00001020", + dkg_algorithm: 'frost', + fork_version: '0x00001020', deposit_amounts: [ - "8000000000", - "16000000000", - "8000000000" + '8000000000', + '16000000000', + '8000000000' ], - config_hash: "0xe604bdf1649e2bcc5399149d4a683feacfc5678abe990d75e202791984208c53", - definition_hash: "0x123be6c24ec74366b0a318de42d36e09a43a08c3db72800698a958510c804a0b" + config_hash: '0xe604bdf1649e2bcc5399149d4a683feacfc5678abe990d75e202791984208c53', + definition_hash: '0x123be6c24ec74366b0a318de42d36e09a43a08c3db72800698a958510c804a0b' }, distributed_validators: [ { - distributed_public_key: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7", + distributed_public_key: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', public_shares: [ - "0x804841f5b773b7cda35f2ceaacbd7b52afba38b6d65d5c4b3b1d3cdc905c21c0f7d1ac18cd4847b0cf56ac7ed41d5c19", - "0xac2362cbfdd573137a5f46727981363198c8a8b66eb29123014f3e1dee335132973973bddb4a4c592c8c74ff270b5982", - "0xb63dd0fb59a513b0f9f10ed3d88a54aa72c189faf2c2d2e4d66a81730a81a89d6feac0ff8e7b6b488c5131aa33845b47" + '0x804841f5b773b7cda35f2ceaacbd7b52afba38b6d65d5c4b3b1d3cdc905c21c0f7d1ac18cd4847b0cf56ac7ed41d5c19', + '0xac2362cbfdd573137a5f46727981363198c8a8b66eb29123014f3e1dee335132973973bddb4a4c592c8c74ff270b5982', + '0xb63dd0fb59a513b0f9f10ed3d88a54aa72c189faf2c2d2e4d66a81730a81a89d6feac0ff8e7b6b488c5131aa33845b47' ], builder_registration: { message: { - fee_recipient: "0x52fdfc072182654f163f5f0f9a621d729566c74d", + fee_recipient: '0x52fdfc072182654f163f5f0f9a621d729566c74d', gas_limit: 30000000, timestamp: 1616508000, - pubkey: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7" + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7' }, - signature: "0x8a8085f002d0332c689baef8ecbab1ca3632e2536fa9f0587212f50429a4617d1cac1722b55d521ffb58424f6bc4f9640bdd1994e9abaff1fe00ea641aabf89249a8ed64aee5f7508a78dc9a6e2fa626cc707e5f9f94b9634084ea825c082b79" + signature: '0x8a8085f002d0332c689baef8ecbab1ca3632e2536fa9f0587212f50429a4617d1cac1722b55d521ffb58424f6bc4f9640bdd1994e9abaff1fe00ea641aabf89249a8ed64aee5f7508a78dc9a6e2fa626cc707e5f9f94b9634084ea825c082b79' }, partial_deposit_data: [ { - pubkey: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7", - withdrawal_credentials: "0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4", - amount: "8000000000", - signature: "0x84614b278beed177d17f8e61ec6c4c4c17fb41adde71dedb5977ce19354a4ec24bed65021109d7d690d014fc531cf7040b3285877c8bfc35b1a2dd64fdbcab086132982fb036c31071824ea9ec6ca28ff6aaf86a425350c2bec8012b399342eb" + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', + withdrawal_credentials: '0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4', + amount: '8000000000', + signature: '0x84614b278beed177d17f8e61ec6c4c4c17fb41adde71dedb5977ce19354a4ec24bed65021109d7d690d014fc531cf7040b3285877c8bfc35b1a2dd64fdbcab086132982fb036c31071824ea9ec6ca28ff6aaf86a425350c2bec8012b399342eb' }, { - pubkey: "0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7", - withdrawal_credentials: "0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4", - amount: "16000000000", - signature: "0xac5bcb369e8dde110604f6ae829a3432f82a99b0a996e15f4be6426acbe690a1aadb4b365d8b10a36737b2cd8c7f561214d4e4df3626cc9664f663111d15efbd8d18cffff5c3eff407fe2cc478244caea7f9f2afee83a0ae8aa2587365b8e54a" + pubkey: '0x87382e8cc3e2c9c2d03ac1af7ae0bcc1be468c596a8a8b8059153ca9ce7746d459dd0603858e858355cb96d67a2a87a7', + withdrawal_credentials: '0x01000000000000000000000081855ad8681d0d86d1e91e00167939cb6694d2c4', + amount: '16000000000', + signature: '0xac5bcb369e8dde110604f6ae829a3432f82a99b0a996e15f4be6426acbe690a1aadb4b365d8b10a36737b2cd8c7f561214d4e4df3626cc9664f663111d15efbd8d18cffff5c3eff407fe2cc478244caea7f9f2afee83a0ae8aa2587365b8e54a' } ] }, { - distributed_public_key: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a", + distributed_public_key: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', public_shares: [ - "0x898c28241cb2386fdbfa26ee08fcc804ee953695741691d4f8c45a36f08dd319a09173a9ef632eb7a35f94ff9241cd8e", - "0xb7d73b8ea0d74dc7eb70f305c6666dd9dca749ea1084b25f942e0d0909211f6556c2955266a7ff54a204146676bf1c8c", - "0x8fbe3bb3c23e9dcb093ee45a28efc120ee2a923d4c62a0377d0a6ed7a3da8fa185456bbaec41e13fd84a2a410023a742" + '0x898c28241cb2386fdbfa26ee08fcc804ee953695741691d4f8c45a36f08dd319a09173a9ef632eb7a35f94ff9241cd8e', + '0xb7d73b8ea0d74dc7eb70f305c6666dd9dca749ea1084b25f942e0d0909211f6556c2955266a7ff54a204146676bf1c8c', + '0x8fbe3bb3c23e9dcb093ee45a28efc120ee2a923d4c62a0377d0a6ed7a3da8fa185456bbaec41e13fd84a2a410023a742' ], builder_registration: { message: { - fee_recipient: "0xeb9d18a44784045d87f3c67cf22746e995af5a25", + fee_recipient: '0xeb9d18a44784045d87f3c67cf22746e995af5a25', gas_limit: 30000000, timestamp: 1616508000, - pubkey: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a" + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a' }, - signature: "0xa941fcec27add0165a1bd76bb4b5d3a5f4e96e0e7b9a9edad4188dda914b97519c71f5964a467061cfee91f317eaa321174d5dbd8e94a6486c62e8bd10aad6ead7494696e2926b68fea446b9d868abde763a177083e87921d5e1b09c6b2aec2a" + signature: '0xa941fcec27add0165a1bd76bb4b5d3a5f4e96e0e7b9a9edad4188dda914b97519c71f5964a467061cfee91f317eaa321174d5dbd8e94a6486c62e8bd10aad6ead7494696e2926b68fea446b9d868abde763a177083e87921d5e1b09c6b2aec2a' }, partial_deposit_data: [ { - pubkey: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a", - withdrawal_credentials: "0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c", - amount: "8000000000", - signature: "0x88b20e744a83679da4df81416358214f1e62535498b9ac38eb622b01cad2090554b2f1f7b3ac9032c15ccd31fffbb1cf0f5589b7703ecc4441e5bd7bf7c388ac1423c41b5c76cbee9969ffade054edcd1a883f80df813b52786393d318db007b" + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', + withdrawal_credentials: '0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c', + amount: '8000000000', + signature: '0x88b20e744a83679da4df81416358214f1e62535498b9ac38eb622b01cad2090554b2f1f7b3ac9032c15ccd31fffbb1cf0f5589b7703ecc4441e5bd7bf7c388ac1423c41b5c76cbee9969ffade054edcd1a883f80df813b52786393d318db007b' }, { - pubkey: "0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a", - withdrawal_credentials: "0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c", - amount: "16000000000", - signature: "0x94d9db7b4527e6eb308d387f168089a51d1deffc2c985faf1f7f8e82fbc9cb93c7f10c6a7bbca4fc25a1cfc95de28432037cf7727c1db0ad6d1fb0f1813d5904fba4ab8aebfeccfcded2f915bd48fb46155131b24adb0ba5e764d7ff6d3c82a5" + pubkey: '0x90b5773dc3dc11480a7ebf68005980ca26be65fad6565ce655f0a9e24083a7ad2e22d7102368a8292fcd18021272a87a', + withdrawal_credentials: '0x0100000000000000000000005fb90badb37c5821b6d95526a41a9504680b4e7c', + amount: '16000000000', + signature: '0x94d9db7b4527e6eb308d387f168089a51d1deffc2c985faf1f7f8e82fbc9cb93c7f10c6a7bbca4fc25a1cfc95de28432037cf7727c1db0ad6d1fb0f1813d5904fba4ab8aebfeccfcded2f915bd48fb46155131b24adb0ba5e764d7ff6d3c82a5' } ] } ], - signature_aggregate: "0xb54fc9fcfe6827f519a29ff0a8bc9a06aafd197253a6def9f45bf79b023e71f3bd26bd0365f0beb7d60c1146e33be127161eb034af4a4de619e9d6971174224fdc18c04821d9e5b7abaeaedc01755b6e33addb2dc820aa361890a634a0252422", - lock_hash: "0x1f598e309b715ba0141034b495975e3bed0231ad92da49dfff462765049df671", + signature_aggregate: '0xb54fc9fcfe6827f519a29ff0a8bc9a06aafd197253a6def9f45bf79b023e71f3bd26bd0365f0beb7d60c1146e33be127161eb034af4a4de619e9d6971174224fdc18c04821d9e5b7abaeaedc01755b6e33addb2dc820aa361890a634a0252422', + lock_hash: '0x1f598e309b715ba0141034b495975e3bed0231ad92da49dfff462765049df671', node_signatures: [ - "0xf4317dc1f01738f84b2624866e8b4e85e92394fabb49218ef8a6dfe7ee4fdaab015742379328b173204504332a5e15450d5a127bbe8b8a2209cd9fa12b85cf4501", - "0x9e4726f7cce4cfad963eb04aaeec677fa7d1010d66640867d0ee11c75fad45dd6ad8fad9ad4a3c042bd1ab298a5598896b9de08acfde476f9aa65c48e3def7f901", - "0x54a89155ef4a6e319c0411f29963554fe551abce6d8463661cc5449a67243d053292f0190432cdcbcfc6e651815b093d55b4adbfc8c82f85ee1e1af798d9bae400" + '0xf4317dc1f01738f84b2624866e8b4e85e92394fabb49218ef8a6dfe7ee4fdaab015742379328b173204504332a5e15450d5a127bbe8b8a2209cd9fa12b85cf4501', + '0x9e4726f7cce4cfad963eb04aaeec677fa7d1010d66640867d0ee11c75fad45dd6ad8fad9ad4a3c042bd1ab298a5598896b9de08acfde476f9aa65c48e3def7f901', + '0x54a89155ef4a6e319c0411f29963554fe551abce6d8463661cc5449a67243d053292f0190432cdcbcfc6e651815b093d55b4adbfc8c82f85ee1e1af798d9bae400' ] } - - From 0a31856ed4a892bb735a7943dd296b8ae1df135b Mon Sep 17 00:00:00 2001 From: HananINouman Date: Thu, 14 Mar 2024 15:56:30 +0300 Subject: [PATCH 09/12] use v1.7.0 for creation --- src/ajv.ts | 22 -------- src/constants.ts | 2 +- src/index.ts | 1 - src/schema.ts | 8 --- src/verification/common.ts | 8 --- test/methods.test.ts | 79 ++++++++------------------- test/sdk-package-test/cluster.test.ts | 36 ++++++------ 7 files changed, 41 insertions(+), 115 deletions(-) diff --git a/src/ajv.ts b/src/ajv.ts index ba7dfa0..693b83e 100644 --- a/src/ajv.ts +++ b/src/ajv.ts @@ -1,32 +1,10 @@ import Ajv, { type ErrorObject } from 'ajv' -import { ETHER_TO_GWEI } from './constants' - -function validDpositAmounts (data: boolean, deposits: string[]): boolean { - let sum = 0 - for (let i = 0; i < deposits.length; i++) { - const amount = parseInt(deposits[i]) - if (amount % ETHER_TO_GWEI !== 0 || amount > 32 * ETHER_TO_GWEI) { - return false - } - sum += amount - } - if (sum !== 32 * ETHER_TO_GWEI) { - return false - } else { - return true - } -} export function validatePayload ( data: any, schema: any, ): ErrorObject[] | undefined | null | boolean { const ajv = new Ajv() - ajv.addKeyword({ - keyword: 'validDpositAmounts', - validate: validDpositAmounts, - errors: true, - }) const validate = ajv.compile(schema) const isValid = validate(data) if (!isValid) { diff --git a/src/constants.ts b/src/constants.ts index 274d3e8..0a8d0f8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -98,7 +98,7 @@ export const signEnrPayload = ( export const DKG_ALGORITHM = 'default' -export const CONFIG_VERSION = 'v1.8.0' +export const CONFIG_VERSION = 'v1.7.0' export const SDK_VERSION = pjson.version diff --git a/src/index.ts b/src/index.ts index 82b2fb4..f3ca275 100644 --- a/src/index.ts +++ b/src/index.ts @@ -70,7 +70,6 @@ export class Client extends Base { timestamp: new Date().toISOString(), threshold: Math.ceil((2 * newCluster.operators.length) / 3), num_validators: newCluster.validators.length, - deposit_amounts: newCluster.deposit_amounts ? newCluster.deposit_amounts : ['32000000000'] } try { diff --git a/src/schema.ts b/src/schema.ts index 474a3b3..d431816 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -53,14 +53,6 @@ export const definitionSchema = { required: ['fee_recipient_address', 'withdrawal_address'], }, }, - deposit_amounts: { - type: 'array', - items: { - type: 'string', - pattern: '^[0-9]+$', - }, - validDpositAmounts: true - }, }, required: ['name', 'operators', 'validators'], } diff --git a/src/verification/common.ts b/src/verification/common.ts index 27609cd..426ea4a 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -31,14 +31,6 @@ export const clusterConfigOrDefinitionHash = ( ): 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) diff --git a/test/methods.test.ts b/test/methods.test.ts index dbd6f5a..2e6443f 100644 --- a/test/methods.test.ts +++ b/test/methods.test.ts @@ -35,23 +35,23 @@ describe('Cluster Client', () => { .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) const configHash = - await clientInstance.createClusterDefinition(clusterConfigV1X8) + await clientInstance.createClusterDefinition(clusterConfigV1X7) expect(configHash).toEqual(mockConfigHash) }) test('acceptClusterDefinition should return cluster definition', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X8.cluster_definition)) + .mockReturnValue(Promise.resolve(clusterLockV1X7.cluster_definition)) const clusterDefinition = await clientInstance.acceptClusterDefinition( { - enr: clusterLockV1X8.cluster_definition.operators[0].enr, - version: clusterLockV1X8.cluster_definition.version, + enr: clusterLockV1X7.cluster_definition.operators[0].enr, + version: clusterLockV1X7.cluster_definition.version, }, - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) - expect(clusterDefinition).toEqual(clusterLockV1X8.cluster_definition) + expect(clusterDefinition).toEqual(clusterLockV1X7.cluster_definition) }) test('createClusterDefinition should throw an error on invalid operators', async () => { @@ -60,7 +60,7 @@ describe('Cluster Client', () => { .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) try { await clientInstance.createClusterDefinition({ - ...clusterConfigV1X8, + ...clusterConfigV1X7, operators: [], }) } catch (error: any) { @@ -70,37 +70,9 @@ describe('Cluster Client', () => { } }) - test('createClusterDefinition should accept a configuration without deposit_amounts ', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) - - const configHash = await clientInstance.createClusterDefinition({ - ...clusterConfigV1X7, - }) - - expect(configHash).toEqual(mockConfigHash) - }) - - test('createClusterDefinition should throw on not valid deposit_amounts ', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })) - try { - await clientInstance.createClusterDefinition({ - ...clusterConfigV1X7, - deposit_amounts: ['34000000'] - }) - } catch (error: any) { - expect(error.message).toEqual( - "Schema compilation errors', must pass \"validDpositAmounts\" keyword validation", - ) - } - }) - test('validatePayload should throw an error on empty schema', async () => { try { - validatePayload({ ...clusterConfigV1X8, operators: [] }, '') + validatePayload({ ...clusterConfigV1X7, operators: [] }, '') } catch (error: any) { expect(error.message).toEqual('schema must be object or boolean') } @@ -109,29 +81,26 @@ describe('Cluster Client', () => { test('getClusterdefinition should return cluster definition if config hash exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X8.cluster_definition)) + .mockReturnValue(Promise.resolve(clusterLockV1X7.cluster_definition)) const clusterDefinition = await clientInstance.getClusterDefinition( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) - expect(clusterDefinition.deposit_amounts?.length).toEqual( - clusterLockV1X8.cluster_definition.deposit_amounts.length, - ) expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) }) test('getClusterLock should return lockFile if exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X8)) + .mockReturnValue(Promise.resolve(clusterLockV1X7)) const clusterLock = await clientInstance.getClusterLock( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) - expect(clusterLock.lock_hash).toEqual(clusterLockV1X8.lock_hash) + expect(clusterLock.lock_hash).toEqual(clusterLockV1X7.lock_hash) }) test('request method should set user agent header', async () => { @@ -171,7 +140,7 @@ describe('Cluster Client without a signer', () => { test('createClusterDefinition should throw an error without signer', async () => { try { - await clientInstance.createClusterDefinition(clusterConfigV1X8) + await clientInstance.createClusterDefinition(clusterConfigV1X7) } catch (err: any) { expect(err.message).toEqual('Signer is required in createClusterDefinition') } @@ -181,10 +150,10 @@ describe('Cluster Client without a signer', () => { try { await clientInstance.acceptClusterDefinition( { - enr: clusterLockV1X8.cluster_definition.operators[0].enr, - version: clusterLockV1X8.cluster_definition.version, + enr: clusterLockV1X7.cluster_definition.operators[0].enr, + version: clusterLockV1X7.cluster_definition.version, }, - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) } catch (err: any) { expect(err.message).toEqual('Signer is required in acceptClusterDefinition') @@ -194,25 +163,25 @@ describe('Cluster Client without a signer', () => { test('getClusterdefinition should return cluster definition if config hash exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X8.cluster_definition)) + .mockReturnValue(Promise.resolve(clusterLockV1X7.cluster_definition)) const clusterDefinition = await clientInstance.getClusterDefinition( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) }) test('getClusterLock should return lockFile if exist', async () => { clientInstance['request'] = jest .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X8)) + .mockReturnValue(Promise.resolve(clusterLockV1X7)) const clusterLock = await clientInstance.getClusterLock( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) - expect(clusterLock.lock_hash).toEqual(clusterLockV1X8.lock_hash) + expect(clusterLock.lock_hash).toEqual(clusterLockV1X7.lock_hash) }) test.each([{ version: 'v1.7.0', clusterLock: clusterLockV1X7 }, { version: 'v1.8.0', clusterLock: clusterLockV1X8 }])( diff --git a/test/sdk-package-test/cluster.test.ts b/test/sdk-package-test/cluster.test.ts index b8b55f8..6ec4a8c 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 { clusterConfigV1X8, clusterLockV1X7, clusterLockV1X8, enr } from './fixtures' +import { clusterConfigV1X7, clusterLockV1X7, clusterLockV1X8, enr } from './fixtures' import { client, updateClusterDef, @@ -32,7 +32,7 @@ describe('Cluster Definition', () => { }) beforeAll(async () => { - configHash = await client.createClusterDefinition(clusterConfigV1X8) + 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(clusterConfigV1X8) + 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() - clusterConfigV1X8.operators.push({ address: signerAddress }) + clusterConfigV1X7.operators.push({ address: signerAddress }) - secondConfigHash = await client.createClusterDefinition(clusterConfigV1X8) + secondConfigHash = await client.createClusterDefinition(clusterConfigV1X7) const definitionData: ClusterDefintion = await client.acceptClusterDefinition( @@ -108,7 +108,7 @@ describe('Cluster Definition', () => { describe('Poll Cluster Lock', () => { // Test polling getClusterLock through mimicing the whole flow using obol-api endpoints - const { definition_hash: _, ...rest } = clusterLockV1X8.cluster_definition + const { definition_hash: _, ...rest } = clusterLockV1X7.cluster_definition const clusterWithoutDefHash = rest const clientWithoutAsigner = new Client({ baseUrl: 'https://obol-api-nonprod-dev.dev.obol.tech', @@ -126,7 +126,7 @@ describe('Poll Cluster Lock', () => { const pollReqIntervalId = setInterval(async function () { try { const lockFile = await client.getClusterLock( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) if (lockFile?.lock_hash) { clearInterval(pollReqIntervalId) @@ -144,8 +144,8 @@ describe('Poll Cluster Lock', () => { }, 5000) }), (async () => { - await updateClusterDef(clusterLockV1X8.cluster_definition) - await publishLockFile(clusterLockV1X8) + await updateClusterDef(clusterLockV1X7.cluster_definition) + await publishLockFile(clusterLockV1X7) })(), ]) expect(lockObject).toHaveProperty('lock_hash') @@ -158,7 +158,7 @@ describe('Poll Cluster Lock', () => { const pollReqIntervalId = setInterval(async function () { try { const lockFile = await clientWithoutAsigner.getClusterLock( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) if (lockFile?.lock_hash) { clearInterval(pollReqIntervalId) @@ -175,8 +175,8 @@ describe('Poll Cluster Lock', () => { }, 5000) }), (async () => { - await updateClusterDef(clusterLockV1X8.cluster_definition) - await publishLockFile(clusterLockV1X8) + await updateClusterDef(clusterLockV1X7.cluster_definition) + await publishLockFile(clusterLockV1X7) })(), ]) expect(lockObject).toHaveProperty('lock_hash') @@ -185,14 +185,10 @@ describe('Poll Cluster Lock', () => { it('should fetch the cluster definition for the configHash', async () => { const clusterDefinition: ClusterDefintion = await client.getClusterDefinition( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) - - expect(clusterDefinition.deposit_amounts?.length).toEqual( - clusterLockV1X8.cluster_definition.deposit_amounts.length, - ) expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X8.cluster_definition.config_hash, + clusterLockV1X7.cluster_definition.config_hash, ) }) @@ -204,8 +200,8 @@ describe('Poll Cluster Lock', () => { }) afterAll(async () => { - const configHash = clusterLockV1X8.cluster_definition.config_hash - const lockHash = clusterLockV1X8.lock_hash + const configHash = clusterLockV1X7.cluster_definition.config_hash + const lockHash = clusterLockV1X7.lock_hash await request(app) .delete(`/lock/${lockHash}`) From a2aa3e4fc1c953df34984539d828ef7e47b0df62 Mon Sep 17 00:00:00 2001 From: HananINouman Date: Thu, 14 Mar 2024 16:47:35 +0300 Subject: [PATCH 10/12] add v1.6.0 data --- src/types.ts | 4 +- src/verification/common.ts | 21 +- src/verification/v1.7.0.ts | 12 +- src/verification/v1.8.0.ts | 12 +- test/fixtures.ts | 320 +++++++++++++++++--------- test/methods.test.ts | 4 +- test/sdk-package-test/cluster.test.ts | 4 +- test/sdk-package-test/fixtures.ts | 273 ---------------------- 8 files changed, 241 insertions(+), 409 deletions(-) delete mode 100644 test/sdk-package-test/fixtures.ts diff --git a/src/types.ts b/src/types.ts index 251e805..d3334cf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -185,7 +185,7 @@ export interface DistributedValidator { partial_deposit_data?: Array> /** pre-generated signed validator builder registration to be sent to builder network. */ - builder_registration: BuilderRegistration + builder_registration?: BuilderRegistration } /** @@ -205,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/verification/common.ts b/src/verification/common.ts index 426ea4a..d0949df 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -31,6 +31,15 @@ export const clusterConfigOrDefinitionHash = ( ): 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) @@ -298,7 +307,7 @@ export const verifyBuilderRegistration = ( if ( validator.distributed_public_key !== - validator.builder_registration.message.pubkey + validator.builder_registration?.message.pubkey ) { return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) } } @@ -328,14 +337,14 @@ export const verifyNodeSignatures = (clusterLock: ClusterLock): boolean => { const lockHashWithout0x = hexWithout0x(clusterLock.lock_hash) // node(ENR) signatures - for (let i = 0; i < nodeSignatures.length; i++) { + 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[i].slice(2, 66), - s: nodeSignatures[i].slice(66, 130), + r: (nodeSignatures as string[])[i].slice(2, 66), + s: (nodeSignatures as string[])[i].slice(66, 130), } const nodeSignatureVerification = ec @@ -382,6 +391,7 @@ export const isValidClusterLock = async ( if (definitionType == null) { return false } + const isValidDefinitionData = verifyDefinitionSignatures( clusterLock.cluster_definition, definitionType, @@ -390,12 +400,15 @@ export const isValidClusterLock = async ( return false } + if ( clusterConfigOrDefinitionHash(clusterLock.cluster_definition, false) !== clusterLock.cluster_definition.definition_hash ) { return false } + + if (clusterLockHash(clusterLock) !== clusterLock.lock_hash) { return false } diff --git a/src/verification/v1.7.0.ts b/src/verification/v1.7.0.ts index ae194a7..d7183aa 100644 --- a/src/verification/v1.7.0.ts +++ b/src/verification/v1.7.0.ts @@ -162,15 +162,15 @@ export const hashClusterLockV1X7 = (cluster: ClusterLock): string => { builder_registration: { message: { fee_recipient: fromHexString( - dVaidator.builder_registration.message.fee_recipient, + dVaidator.builder_registration?.message.fee_recipient as string, ), - gas_limit: dVaidator.builder_registration.message.gas_limit, - timestamp: dVaidator.builder_registration.message.timestamp, + gas_limit: dVaidator.builder_registration?.message.gas_limit as number, + timestamp: dVaidator.builder_registration?.message.timestamp as number, pubkey: fromHexString( - dVaidator.builder_registration.message.pubkey, + dVaidator.builder_registration?.message.pubkey as string, ), }, - signature: fromHexString(dVaidator.builder_registration.signature), + signature: fromHexString(dVaidator.builder_registration?.signature as string), }, } }, @@ -233,7 +233,7 @@ export const verifyDVV1X7 = (clusterLock: ClusterLock): boolean => { pubKeys.push(fromHexString(distributedPublicKey)) builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg) blsSignatures.push( - fromHexString(validator.builder_registration.signature), + fromHexString(validator.builder_registration?.signature as string), ) } diff --git a/src/verification/v1.8.0.ts b/src/verification/v1.8.0.ts index 5a38ad8..250e9ef 100644 --- a/src/verification/v1.8.0.ts +++ b/src/verification/v1.8.0.ts @@ -171,13 +171,13 @@ export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { builder_registration: { message: { fee_recipient: fromHexString( - dVaidator.builder_registration.message.fee_recipient, + dVaidator.builder_registration?.message.fee_recipient as string, ), - gas_limit: dVaidator.builder_registration.message.gas_limit, - timestamp: dVaidator.builder_registration.message.timestamp, - pubkey: fromHexString(dVaidator.builder_registration.message.pubkey), + gas_limit: dVaidator.builder_registration?.message.gas_limit as number, + timestamp: dVaidator.builder_registration?.message.timestamp as number, + pubkey: fromHexString(dVaidator.builder_registration?.message.pubkey as string), }, - signature: fromHexString(dVaidator.builder_registration.signature), + signature: fromHexString(dVaidator.builder_registration?.signature as string), }, } }) @@ -240,7 +240,7 @@ export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => { pubKeys.push(fromHexString(distributedPublicKey)) builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg) blsSignatures.push( - fromHexString(validator.builder_registration.signature), + fromHexString(validator.builder_registration?.signature as string), ) } diff --git a/test/fixtures.ts b/test/fixtures.ts index 4bcf2b2..4fcca23 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,3 +1,97 @@ + +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 = { @@ -94,8 +188,6 @@ export const clusterLockV1X7 = { amount: '32000000000', signature: '0xae016c6c42daa8d1517d0e10370cf7882b28149635f734c5f3d83f781cd61f5df6d5203ec11bd0ca9d9e51c6030b66330476a93a65de6151d110e0f6482591f53678d863e55392e9cfb55fecac537edac51979790bcde38250a141348f116d46', - deposit_data_root: - 'fbada6c7c4cba867780eead34c1462339795fe9b417db466ce2f9d4822e8a4bb', }, builder_registration: { message: { @@ -142,130 +234,130 @@ export const clusterConfigV1X8 = { '8000000000', '16000000000', '8000000000' -], + ], } export const clusterLockV1X8 = { cluster_definition: { - name: 'test cluster', - creator: { - address: '0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c', - config_signature: '0x03b41a12847064090333026a10bc0c6f9c51400e67b414fe74aa7df91388583d6bea930d525478e25d85aa49f3c649723e4158895fadd0e787fe8579d43c18cb00' + name: 'test cluster', + creator: { + address: '0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c', + config_signature: '0x03b41a12847064090333026a10bc0c6f9c51400e67b414fe74aa7df91388583d6bea930d525478e25d85aa49f3c649723e4158895fadd0e787fe8579d43c18cb00' + }, + operators: [ + { + address: '0x5050A4F4b3f9338C3472dcC01A87C76A144b3c9c', + enr: 'enr:-HW4QIHPUOMb34YoizKGhz7nsDNQ7hCaiuwyscmeaOQ04awdH05gDnGrZhxDfzcfHssCDeB-esi99A2RoZia6UaYBCuAgmlkgnY0iXNlY3AyNTZrMaECTUts0TYQMsqb0q652QCqTUXZ6tgKyUIzdMRRpyVNB2Y', + config_signature: '0xffafd355831aa993e5a019419403d61533649edc546b4f497bc305d7620dcb787756f9748be1ea76f7236692faeff7c1d2e7b06bf89894d07518de2d4ff45b4d00', + enr_signature: '0x20b5b4ba720053c6ea35a710cdd9d81440ae3a69c204edb06184ea2328ff3a290bd00c256d71f6f4daed2f995931b38c3f6bd0b17796f4e121278073e049086800' }, - 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' - } - ] + address: '0x3325a78425F17a7E487Eb5666b2bFd93aBb06c70', + enr: 'enr:-HW4QDztNDqgEPAgJoHkcF4LfXyjXUo1r_xYoNv48H0PFItwYx-OnviqgfHxEz51RDOGvUMiTpXyo0HBjK5ZZ8YxS9WAgmlkgnY0iXNlY3AyNTZrMaECUx_mBoE0UD0nIxMyJ8hnrI-myDxTfppEw8W9vcsf4zc', + config_signature: '0x2053ba17731221d4ed919de72010b559a924143f74998c94b71e95cb1fdbe3a05ad0cbdf61cf174ef3509ce86bc03633f5215065d71f93bd15e1e506db71420e00', + enr_signature: '0x9aa50b499754e19b7e30e12d6b2d63abc916edc7810aae9f3427f7d2a3cc33ad10f84d638ccb73817cd6a6eee311a52d45ea24f0d0f5452dc845ef24749e71ca00' }, { - 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' - } - ] + 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' + '0xf4317dc1f01738f84b2624866e8b4e85e92394fabb49218ef8a6dfe7ee4fdaab015742379328b173204504332a5e15450d5a127bbe8b8a2209cd9fa12b85cf4501', + '0x9e4726f7cce4cfad963eb04aaeec677fa7d1010d66640867d0ee11c75fad45dd6ad8fad9ad4a3c042bd1ab298a5598896b9de08acfde476f9aa65c48e3def7f901', + '0x54a89155ef4a6e319c0411f29963554fe551abce6d8463661cc5449a67243d053292f0190432cdcbcfc6e651815b093d55b4adbfc8c82f85ee1e1af798d9bae400' ] } diff --git a/test/methods.test.ts b/test/methods.test.ts index 2e6443f..723573a 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 { clusterConfigV1X7, clusterConfigV1X8, clusterLockV1X7, clusterLockV1X8 } from './fixtures.js' +import { clusterConfigV1X7, clusterConfigV1X8, clusterLockV1X6, clusterLockV1X7, clusterLockV1X8 } from './fixtures.js' import { SDK_VERSION } from '../src/constants' import { Base } from '../src/base' import { validatePayload } from '../src/ajv' @@ -184,7 +184,7 @@ describe('Cluster Client without a signer', () => { expect(clusterLock.lock_hash).toEqual(clusterLockV1X7.lock_hash) }) - test.each([{ version: 'v1.7.0', clusterLock: clusterLockV1X7 }, { version: 'v1.8.0', clusterLock: clusterLockV1X8 }])( + 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) diff --git a/test/sdk-package-test/cluster.test.ts b/test/sdk-package-test/cluster.test.ts index 6ec4a8c..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 { clusterConfigV1X7, clusterLockV1X7, clusterLockV1X8, enr } from './fixtures' +import { clusterConfigV1X7, clusterLockV1X6, clusterLockV1X7, clusterLockV1X8, enr } from './../fixtures' import { client, updateClusterDef, @@ -192,7 +192,7 @@ describe('Poll Cluster Lock', () => { ) }) - test.each([{ version: 'v1.7.0', clusterLock: clusterLockV1X7 }, { version: 'v1.8.0', clusterLock: clusterLockV1X8 }])( + 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) diff --git a/test/sdk-package-test/fixtures.ts b/test/sdk-package-test/fixtures.ts deleted file mode 100644 index be95cd1..0000000 --- a/test/sdk-package-test/fixtures.ts +++ /dev/null @@ -1,273 +0,0 @@ -export const enr = - 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak' - -// 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', - 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', - ], -} - -// v1.8.0 -export const clusterConfigV1X8 = { - name: 'testSDK', - operators: [ - { address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81' }, - { address: '0x33807D6F1DCe44b9C599fFE03640762A6F08C496' }, - { address: '0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f' }, - { address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC' }, - ], - validators: [ - { - fee_recipient_address: '0x3CD4958e76C317abcEA19faDd076348808424F99', - 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' - ] -} From 8a20911dbee55f3e774f58ce51402872c9322177 Mon Sep 17 00:00:00 2001 From: HananINouman Date: Thu, 14 Mar 2024 16:51:30 +0300 Subject: [PATCH 11/12] fix lint errors --- src/verification/common.ts | 3 --- test/fixtures.ts | 5 +---- test/methods.test.ts | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/verification/common.ts b/src/verification/common.ts index d0949df..130c10f 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -31,7 +31,6 @@ export const clusterConfigOrDefinitionHash = ( ): string => { let definitionType, val - if (semver.eq(cluster.version, 'v1.6.0')) { definitionType = clusterDefinitionContainerTypeV1X6(configOnly) val = hashClusterDefinitionV1X6(cluster, configOnly) @@ -400,7 +399,6 @@ export const isValidClusterLock = async ( return false } - if ( clusterConfigOrDefinitionHash(clusterLock.cluster_definition, false) !== clusterLock.cluster_definition.definition_hash @@ -408,7 +406,6 @@ export const isValidClusterLock = async ( return false } - if (clusterLockHash(clusterLock) !== clusterLock.lock_hash) { return false } diff --git a/test/fixtures.ts b/test/fixtures.ts index 4fcca23..fd815c5 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,9 +1,7 @@ - export const enr = 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak' - -//v1.6.0 +// v1.6.0 export const clusterLockV1X6 = { cluster_definition: { name: 'test v.1.6', @@ -91,7 +89,6 @@ export const clusterLockV1X6 = { '0x6d2b38d098143c8f0bc5076f4e9b6081cbba040a5aea6649e6223e7a4131241b', } - // v1.7.0 export const clusterConfigV1X7 = { diff --git a/test/methods.test.ts b/test/methods.test.ts index 723573a..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 { clusterConfigV1X7, clusterConfigV1X8, clusterLockV1X6, clusterLockV1X7, clusterLockV1X8 } 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' From dd3d62005ed04c7fa60c6f7f8212f7f41c8c99ba Mon Sep 17 00:00:00 2001 From: HananINouman Date: Mon, 18 Mar 2024 11:43:29 +0300 Subject: [PATCH 12/12] format cleaning --- package.json | 2 +- src/verification/common.ts | 17 +- src/verification/v1.6.0.ts | 14 +- src/verification/v1.7.0.ts | 24 +- src/verification/v1.8.0.ts | 18 +- test/sdk-package-test/yarn.lock | 492 +++++++++++++++++++------------- 6 files changed, 333 insertions(+), 234 deletions(-) diff --git a/package.json b/package.json index ff39aa7..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" diff --git a/src/verification/common.ts b/src/verification/common.ts index 130c10f..7e452cb 100644 --- a/src/verification/common.ts +++ b/src/verification/common.ts @@ -11,7 +11,7 @@ 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, type DefinitionFlow, GENESIS_VALIDATOR_ROOT, signCreatorConfigHashPayload, signEnrPayload, signOperatorConfigHashPayload } from '../constants.js' +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' @@ -84,7 +84,7 @@ export const clusterLockHash = (clusterLock: ClusterLock): string => { // Lock verification -// cluster-definition signatures verificatin +// cluster-definition signatures verification const getPOSTConfigHashSigner = ( signature: string, @@ -145,7 +145,7 @@ const verifyDefinitionSignatures = ( clusterDefinition: ClusterDefintion, definitionType: DefinitionFlow, ): boolean => { - if (definitionType === 'Charon-Command') { + if (definitionType === DefinitionFlow.Charon) { return true } else { const configSigner = getPOSTConfigHashSigner( @@ -157,7 +157,7 @@ const verifyDefinitionSignatures = ( if (configSigner !== clusterDefinition.creator.address.toLowerCase()) { return false } - if (definitionType === 'LP-Solo') { + if (definitionType === DefinitionFlow.Solo) { return true } return clusterDefinition.operators.every((operator) => { @@ -193,10 +193,10 @@ 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 signingRootDefaultValue = signingRootType.defaultValue() + signingRootDefaultValue.objectRoot = sszObjectRoot + signingRootDefaultValue.domain = domain + return Buffer.from(signingRootType.hashTreeRoot(signingRootDefaultValue).buffer) } const computeDepositMsgRoot = (msg: Partial): Buffer => { @@ -298,7 +298,6 @@ export const verifyBuilderRegistration = ( validator: DistributedValidator, feeRecipientAddress: string, forkVersion: string, - ): { isValidBuilderRegistration: boolean, builderRegistrationMsg: Uint8Array } => { const builderDomain = computeDomain( fromHexString(DOMAIN_APPLICATION_BUILDER), diff --git a/src/verification/v1.6.0.ts b/src/verification/v1.6.0.ts index 95ad644..5400b14 100644 --- a/src/verification/v1.6.0.ts +++ b/src/verification/v1.6.0.ts @@ -146,18 +146,18 @@ export const hashClusterLockV1X6 = (cluster: ClusterLock): string => { cluster.cluster_definition, false, ) - val.distributed_validators = cluster.distributed_validators.map(dVaidator => { + val.distributed_validators = cluster.distributed_validators.map(dValidator => { return { - distributed_public_key: fromHexString(dVaidator.distributed_public_key), - public_shares: dVaidator.public_shares.map(publicShare => + distributed_public_key: fromHexString(dValidator.distributed_public_key), + public_shares: dValidator.public_shares.map(publicShare => fromHexString(publicShare), ), - pubkey: fromHexString(dVaidator.deposit_data?.pubkey as string), + pubkey: fromHexString(dValidator.deposit_data?.pubkey as string), withdrawal_credentials: fromHexString( - dVaidator.deposit_data?.withdrawal_credentials as string, + dValidator.deposit_data?.withdrawal_credentials as string, ), - amount: parseInt(dVaidator.deposit_data?.amount as string), - signature: fromHexString(dVaidator.deposit_data?.signature as string), + amount: parseInt(dValidator.deposit_data?.amount as string), + signature: fromHexString(dValidator.deposit_data?.signature as string), } }) diff --git a/src/verification/v1.7.0.ts b/src/verification/v1.7.0.ts index d7183aa..8e87a4f 100644 --- a/src/verification/v1.7.0.ts +++ b/src/verification/v1.7.0.ts @@ -145,32 +145,32 @@ export const hashClusterLockV1X7 = (cluster: ClusterLock): string => { false, ) val.distributed_validators = cluster.distributed_validators.map( - (dVaidator) => { + (dValidator) => { return { - distributed_public_key: fromHexString(dVaidator.distributed_public_key), - public_shares: dVaidator.public_shares.map((publicShare) => + distributed_public_key: fromHexString(dValidator.distributed_public_key), + public_shares: dValidator.public_shares.map((publicShare) => fromHexString(publicShare), ), deposit_data: { - pubkey: fromHexString(dVaidator.deposit_data?.pubkey as string), + pubkey: fromHexString(dValidator.deposit_data?.pubkey as string), withdrawal_credentials: fromHexString( - dVaidator.deposit_data?.withdrawal_credentials as string, + dValidator.deposit_data?.withdrawal_credentials as string, ), - amount: parseInt(dVaidator.deposit_data?.amount as string), - signature: fromHexString(dVaidator.deposit_data?.signature as string), + amount: parseInt(dValidator.deposit_data?.amount as string), + signature: fromHexString(dValidator.deposit_data?.signature as string), }, builder_registration: { message: { fee_recipient: fromHexString( - dVaidator.builder_registration?.message.fee_recipient as string, + dValidator.builder_registration?.message.fee_recipient as string, ), - gas_limit: dVaidator.builder_registration?.message.gas_limit as number, - timestamp: dVaidator.builder_registration?.message.timestamp as number, + gas_limit: dValidator.builder_registration?.message.gas_limit as number, + timestamp: dValidator.builder_registration?.message.timestamp as number, pubkey: fromHexString( - dVaidator.builder_registration?.message.pubkey as string, + dValidator.builder_registration?.message.pubkey as string, ), }, - signature: fromHexString(dVaidator.builder_registration?.signature as string), + signature: fromHexString(dValidator.builder_registration?.signature as string), }, } }, diff --git a/src/verification/v1.8.0.ts b/src/verification/v1.8.0.ts index 250e9ef..75b5a75 100644 --- a/src/verification/v1.8.0.ts +++ b/src/verification/v1.8.0.ts @@ -151,14 +151,14 @@ export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { cluster.cluster_definition, false, ) - val.distributed_validators = cluster.distributed_validators.map(dVaidator => { + val.distributed_validators = cluster.distributed_validators.map(dValidator => { return { - distributed_public_key: fromHexString(dVaidator.distributed_public_key), - public_shares: dVaidator.public_shares.map(publicShare => + distributed_public_key: fromHexString(dValidator.distributed_public_key), + public_shares: dValidator.public_shares.map(publicShare => fromHexString(publicShare), ), // should be fixed - partial_deposit_data: (dVaidator.partial_deposit_data as DepositData[]).map(depositData => { + partial_deposit_data: (dValidator.partial_deposit_data as DepositData[]).map(depositData => { return { pubkey: fromHexString(depositData.pubkey), withdrawal_credentials: fromHexString( @@ -171,13 +171,13 @@ export const hashClusterLockV1X8 = (cluster: ClusterLock): string => { builder_registration: { message: { fee_recipient: fromHexString( - dVaidator.builder_registration?.message.fee_recipient as string, + dValidator.builder_registration?.message.fee_recipient as string, ), - gas_limit: dVaidator.builder_registration?.message.gas_limit as number, - timestamp: dVaidator.builder_registration?.message.timestamp as number, - pubkey: fromHexString(dVaidator.builder_registration?.message.pubkey 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(dVaidator.builder_registration?.signature as string), + signature: fromHexString(dValidator.builder_registration?.signature as string), }, } }) diff --git a/test/sdk-package-test/yarn.lock b/test/sdk-package-test/yarn.lock index 78c313a..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" @@ -839,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" @@ -1150,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" @@ -1212,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" @@ -1229,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": @@ -1259,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" @@ -1282,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" @@ -1301,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" @@ -1315,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": @@ -1336,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": @@ -1620,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== @@ -1954,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" @@ -2216,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" @@ -2277,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== @@ -2388,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" @@ -2455,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" @@ -2473,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" @@ -2494,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" @@ -2533,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== @@ -2978,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== @@ -3014,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" @@ -3185,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== @@ -3202,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== @@ -3222,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" @@ -3512,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" @@ -3596,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" @@ -3608,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== @@ -3649,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== @@ -4736,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" @@ -4856,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" @@ -5327,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" @@ -5572,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" @@ -5635,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" @@ -5677,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" @@ -5839,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" @@ -5934,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" @@ -6039,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" @@ -6112,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== @@ -6121,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== @@ -6132,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== @@ -6144,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== @@ -6164,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" @@ -6306,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== @@ -6391,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"