@obolnetwork/obol-sdk 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +6 -3
  2. package/dist/cjs/package.json +11 -6
  3. package/dist/cjs/src/ajv.js +27 -0
  4. package/dist/cjs/src/constants.js +8 -4
  5. package/dist/cjs/src/index.js +10 -9
  6. package/dist/cjs/src/schema.js +8 -0
  7. package/dist/cjs/src/utils.js +3 -3
  8. package/dist/cjs/src/verification/common.js +19 -7
  9. package/dist/cjs/src/verification/termsAndConditions.js +1 -1
  10. package/dist/cjs/src/verification/v1.6.0.js +1 -1
  11. package/dist/cjs/src/verification/v1.7.0.js +3 -3
  12. package/dist/cjs/src/verification/v1.8.0.js +3 -3
  13. package/dist/cjs/test/fixtures.js +27 -33
  14. package/dist/cjs/test/methods.test.js +54 -27
  15. package/dist/esm/package.json +11 -6
  16. package/dist/esm/src/ajv.js +27 -0
  17. package/dist/esm/src/base.js +1 -1
  18. package/dist/esm/src/constants.js +7 -3
  19. package/dist/esm/src/index.js +11 -10
  20. package/dist/esm/src/schema.js +8 -0
  21. package/dist/esm/src/utils.js +3 -3
  22. package/dist/esm/src/verification/common.js +27 -15
  23. package/dist/esm/src/verification/sszTypes.js +1 -1
  24. package/dist/esm/src/verification/termsAndConditions.js +1 -1
  25. package/dist/esm/src/verification/v1.6.0.js +5 -5
  26. package/dist/esm/src/verification/v1.7.0.js +8 -8
  27. package/dist/esm/src/verification/v1.8.0.js +8 -8
  28. package/dist/esm/test/fixtures.js +27 -33
  29. package/dist/esm/test/methods.test.js +55 -28
  30. package/dist/types/src/constants.d.ts +3 -1
  31. package/dist/types/src/schema.d.ts +8 -0
  32. package/dist/types/src/types.d.ts +18 -18
  33. package/package.json +12 -7
  34. package/src/ajv.ts +38 -7
  35. package/src/base.ts +22 -18
  36. package/src/constants.ts +42 -36
  37. package/src/errors.ts +4 -4
  38. package/src/index.ts +85 -75
  39. package/src/schema.ts +10 -2
  40. package/src/services.ts +6 -6
  41. package/src/types.ts +65 -65
  42. package/src/utils.ts +17 -17
  43. package/src/verification/common.ts +374 -333
  44. package/src/verification/sszTypes.ts +60 -51
  45. package/src/verification/termsAndConditions.ts +16 -14
  46. package/src/verification/v1.6.0.ts +214 -184
  47. package/src/verification/v1.7.0.ts +268 -233
  48. package/src/verification/v1.8.0.ts +266 -225
@@ -1,32 +1,64 @@
1
- import { type UintNumberByteLen, UintNumberType } from '@chainsafe/ssz/lib/type/uint'
2
- import { strToUint8Array } from '../utils'
3
- import { builderRegistrationContainer, type creatorAddressWrapperType, type creatorContainerType, depositDataContainer, newCreatorContainerType, newOperatorContainerType, type operatorAddressWrapperType, type operatorContainerType, validatorsContainerType } from './sszTypes'
4
- import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString } from '@chainsafe/ssz'
5
- import { type ValueOfFields } from '@chainsafe/ssz/lib/view/container'
6
- import { type ClusterDefinition, type ClusterLock, type DepositData } from '../types'
7
- import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from './common'
8
- import { aggregateSignatures, verifyAggregate, verifyMultiple } from '@chainsafe/bls'
1
+ import {
2
+ type UintNumberByteLen,
3
+ UintNumberType,
4
+ } from '@chainsafe/ssz/lib/type/uint';
5
+ import { strToUint8Array } from '../utils';
6
+ import {
7
+ builderRegistrationContainer,
8
+ type creatorAddressWrapperType,
9
+ type creatorContainerType,
10
+ depositDataContainer,
11
+ newCreatorContainerType,
12
+ newOperatorContainerType,
13
+ type operatorAddressWrapperType,
14
+ type operatorContainerType,
15
+ validatorsContainerType,
16
+ } from './sszTypes';
17
+ import {
18
+ ByteListType,
19
+ ByteVectorType,
20
+ ContainerType,
21
+ ListBasicType,
22
+ ListCompositeType,
23
+ fromHexString,
24
+ } from '@chainsafe/ssz';
25
+ import { type ValueOfFields } from '@chainsafe/ssz/lib/view/container';
26
+ import {
27
+ type ClusterDefinition,
28
+ type ClusterLock,
29
+ type DepositData,
30
+ } from '../types';
31
+ import {
32
+ verifyBuilderRegistration,
33
+ verifyDepositData,
34
+ verifyNodeSignatures,
35
+ } from './common';
36
+ import {
37
+ aggregateSignatures,
38
+ verifyAggregate,
39
+ verifyMultiple,
40
+ } from '@chainsafe/bls';
9
41
 
10
- // cluster defintion
42
+ // cluster definition
11
43
  type DefinitionFieldsV1X8 = {
12
- uuid: ByteListType
13
- name: ByteListType
14
- version: ByteListType
15
- timestamp: ByteListType
16
- num_validators: UintNumberType
17
- threshold: UintNumberType
18
- dkg_algorithm: ByteListType
19
- fork_version: ByteVectorType
20
- operators: ListCompositeType<
21
- typeof operatorContainerType | typeof operatorAddressWrapperType
22
- >
23
- creator: typeof creatorContainerType | typeof creatorAddressWrapperType
24
- validators: ListCompositeType<typeof validatorsContainerType>
25
- deposit_amounts: ListBasicType<UintNumberType>
26
- config_hash?: ByteVectorType
27
- }
44
+ uuid: ByteListType;
45
+ name: ByteListType;
46
+ version: ByteListType;
47
+ timestamp: ByteListType;
48
+ num_validators: UintNumberType;
49
+ threshold: UintNumberType;
50
+ dkg_algorithm: ByteListType;
51
+ fork_version: ByteVectorType;
52
+ operators: ListCompositeType<
53
+ typeof operatorContainerType | typeof operatorAddressWrapperType
54
+ >;
55
+ creator: typeof creatorContainerType | typeof creatorAddressWrapperType;
56
+ validators: ListCompositeType<typeof validatorsContainerType>;
57
+ deposit_amounts: ListBasicType<UintNumberType>;
58
+ config_hash?: ByteVectorType;
59
+ };
28
60
 
29
- type DefinitionContainerTypeV1X8 = ContainerType<DefinitionFieldsV1X8>
61
+ type DefinitionContainerTypeV1X8 = ContainerType<DefinitionFieldsV1X8>;
30
62
 
31
63
  /**
32
64
  * Returns the containerized cluster definition
@@ -34,248 +66,257 @@ type DefinitionContainerTypeV1X8 = ContainerType<DefinitionFieldsV1X8>
34
66
  * @returns SSZ Containerized type of cluster input
35
67
  */
36
68
  export const clusterDefinitionContainerTypeV1X8 = (
37
- configOnly: boolean,
69
+ configOnly: boolean,
38
70
  ): DefinitionContainerTypeV1X8 => {
39
- let returnedContainerType: any = {
40
- uuid: new ByteListType(64),
41
- name: new ByteListType(256),
42
- version: new ByteListType(16),
43
- timestamp: new ByteListType(32),
44
- num_validators: new UintNumberType(8 as UintNumberByteLen),
45
- threshold: new UintNumberType(8 as UintNumberByteLen),
46
- dkg_algorithm: new ByteListType(32),
47
- fork_version: new ByteVectorType(4),
48
- operators: new ListCompositeType(newOperatorContainerType(configOnly), 256),
49
- creator: newCreatorContainerType(configOnly),
50
- validators: new ListCompositeType(validatorsContainerType, 65536),
51
- deposit_amounts: new ListBasicType(
52
- new UintNumberType(8 as UintNumberByteLen),
53
- 256,
54
- ),
55
- }
71
+ let returnedContainerType: any = {
72
+ uuid: new ByteListType(64),
73
+ name: new ByteListType(256),
74
+ version: new ByteListType(16),
75
+ timestamp: new ByteListType(32),
76
+ num_validators: new UintNumberType(8 as UintNumberByteLen),
77
+ threshold: new UintNumberType(8 as UintNumberByteLen),
78
+ dkg_algorithm: new ByteListType(32),
79
+ fork_version: new ByteVectorType(4),
80
+ operators: new ListCompositeType(newOperatorContainerType(configOnly), 256),
81
+ creator: newCreatorContainerType(configOnly),
82
+ validators: new ListCompositeType(validatorsContainerType, 65536),
83
+ deposit_amounts: new ListBasicType(
84
+ new UintNumberType(8 as UintNumberByteLen),
85
+ 256,
86
+ ),
87
+ };
56
88
 
57
- if (!configOnly) {
58
- returnedContainerType = {
59
- ...returnedContainerType,
60
- config_hash: new ByteVectorType(32),
61
- }
62
- }
89
+ if (!configOnly) {
90
+ returnedContainerType = {
91
+ ...returnedContainerType,
92
+ config_hash: new ByteVectorType(32),
93
+ };
94
+ }
63
95
 
64
- return new ContainerType(returnedContainerType)
65
- }
96
+ return new ContainerType(returnedContainerType);
97
+ };
66
98
 
67
99
  export const hashClusterDefinitionV1X8 = (
68
- cluster: ClusterDefinition,
69
- configOnly: boolean,
100
+ cluster: ClusterDefinition,
101
+ configOnly: boolean,
70
102
  ): ValueOfFields<DefinitionFieldsV1X8> => {
71
- const definitionType = clusterDefinitionContainerTypeV1X8(configOnly)
103
+ const definitionType = clusterDefinitionContainerTypeV1X8(configOnly);
72
104
 
73
- const val = definitionType.defaultValue()
105
+ const val = definitionType.defaultValue();
74
106
 
75
- // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276
76
- val.uuid = strToUint8Array(cluster.uuid)
77
- val.name = strToUint8Array(cluster.name)
78
- val.version = strToUint8Array(cluster.version)
79
- val.timestamp = strToUint8Array(cluster.timestamp)
80
- val.num_validators = cluster.num_validators
81
- val.threshold = cluster.threshold
82
- val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm)
83
- val.fork_version = fromHexString(cluster.fork_version)
84
- val.operators = cluster.operators.map(operator => {
85
- return configOnly
86
- ? { address: fromHexString(operator.address) }
87
- : {
88
- address: fromHexString(operator.address),
89
- enr: strToUint8Array(operator.enr as string),
90
- config_signature: fromHexString(operator.config_signature as string),
91
- enr_signature: fromHexString(operator.enr_signature as string),
92
- }
93
- })
94
- val.creator = configOnly
95
- ? { address: fromHexString(cluster.creator.address) }
96
- : {
97
- address: fromHexString(cluster.creator.address),
98
- config_signature: fromHexString(cluster.creator.config_signature as string),
99
- }
100
- val.validators = cluster.validators.map((validator) => {
101
- return {
102
- fee_recipient_address: fromHexString(validator.fee_recipient_address),
103
- withdrawal_address: fromHexString(validator.withdrawal_address),
104
- }
105
- })
106
- val.deposit_amounts = (cluster.deposit_amounts as string[]).map((amount: string) => {
107
- return parseInt(amount)
108
- })
107
+ // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276
108
+ val.uuid = strToUint8Array(cluster.uuid);
109
+ val.name = strToUint8Array(cluster.name);
110
+ val.version = strToUint8Array(cluster.version);
111
+ val.timestamp = strToUint8Array(cluster.timestamp);
112
+ val.num_validators = cluster.num_validators;
113
+ val.threshold = cluster.threshold;
114
+ val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm);
115
+ val.fork_version = fromHexString(cluster.fork_version);
116
+ val.operators = cluster.operators.map(operator => {
117
+ return configOnly
118
+ ? { address: fromHexString(operator.address) }
119
+ : {
120
+ address: fromHexString(operator.address),
121
+ enr: strToUint8Array(operator.enr as string),
122
+ config_signature: fromHexString(operator.config_signature as string),
123
+ enr_signature: fromHexString(operator.enr_signature as string),
124
+ };
125
+ });
126
+ val.creator = configOnly
127
+ ? { address: fromHexString(cluster.creator.address) }
128
+ : {
129
+ address: fromHexString(cluster.creator.address),
130
+ config_signature: fromHexString(
131
+ cluster.creator.config_signature as string,
132
+ ),
133
+ };
134
+ val.validators = cluster.validators.map(validator => {
135
+ return {
136
+ fee_recipient_address: fromHexString(validator.fee_recipient_address),
137
+ withdrawal_address: fromHexString(validator.withdrawal_address),
138
+ };
139
+ });
140
+ val.deposit_amounts = (cluster.deposit_amounts as string[]).map(
141
+ (amount: string) => {
142
+ return parseInt(amount);
143
+ },
144
+ );
109
145
 
110
- if (!configOnly) {
111
- val.config_hash = fromHexString(cluster.config_hash)
112
- }
113
- return val
114
- }
146
+ if (!configOnly) {
147
+ val.config_hash = fromHexString(cluster.config_hash);
148
+ }
149
+ return val;
150
+ };
115
151
 
116
152
  // cluster lock
117
153
 
118
154
  const dvContainerTypeV1X8 = new ContainerType({
119
- distributed_public_key: new ByteVectorType(48),
120
- public_shares: new ListCompositeType(new ByteVectorType(48), 256),
121
- partial_deposit_data: new ListCompositeType(depositDataContainer, 256),
122
- builder_registration: builderRegistrationContainer,
123
- })
155
+ distributed_public_key: new ByteVectorType(48),
156
+ public_shares: new ListCompositeType(new ByteVectorType(48), 256),
157
+ partial_deposit_data: new ListCompositeType(depositDataContainer, 256),
158
+ builder_registration: builderRegistrationContainer,
159
+ });
124
160
 
125
161
  type LockContainerTypeV1X8 = ContainerType<{
126
- cluster_definition: DefinitionContainerTypeV1X8
127
- distributed_validators: ListCompositeType<typeof dvContainerTypeV1X8>
128
- }>
162
+ cluster_definition: DefinitionContainerTypeV1X8;
163
+ distributed_validators: ListCompositeType<typeof dvContainerTypeV1X8>;
164
+ }>;
129
165
 
130
166
  /**
131
167
  * @returns SSZ Containerized type of cluster lock
132
168
  */
133
169
  const clusterLockContainerTypeV1X8 = (): LockContainerTypeV1X8 => {
134
- return new ContainerType({
135
- cluster_definition: clusterDefinitionContainerTypeV1X8(false),
136
- distributed_validators: new ListCompositeType(dvContainerTypeV1X8, 65536),
137
- })
138
- }
170
+ return new ContainerType({
171
+ cluster_definition: clusterDefinitionContainerTypeV1X8(false),
172
+ distributed_validators: new ListCompositeType(dvContainerTypeV1X8, 65536),
173
+ });
174
+ };
139
175
 
140
176
  /**
141
177
  * @param cluster The published cluster lock
142
178
  * @returns The lock hash in of the corresponding cluster
143
179
  */
144
180
  export const hashClusterLockV1X8 = (cluster: ClusterLock): string => {
145
- const lockType = clusterLockContainerTypeV1X8()
181
+ const lockType = clusterLockContainerTypeV1X8();
146
182
 
147
- const val = lockType.defaultValue()
183
+ const val = lockType.defaultValue();
148
184
 
149
- // Check if we can replace with definition_hash
150
- val.cluster_definition = hashClusterDefinitionV1X8(
151
- cluster.cluster_definition,
152
- false,
153
- )
154
- val.distributed_validators = cluster.distributed_validators.map(dValidator => {
155
- return {
156
- distributed_public_key: fromHexString(dValidator.distributed_public_key),
157
- public_shares: dValidator.public_shares.map(publicShare =>
158
- fromHexString(publicShare),
185
+ // Check if we can replace with definition_hash
186
+ val.cluster_definition = hashClusterDefinitionV1X8(
187
+ cluster.cluster_definition,
188
+ false,
189
+ );
190
+ val.distributed_validators = cluster.distributed_validators.map(
191
+ dValidator => {
192
+ return {
193
+ distributed_public_key: fromHexString(
194
+ dValidator.distributed_public_key,
195
+ ),
196
+ public_shares: dValidator.public_shares.map(publicShare =>
197
+ fromHexString(publicShare),
198
+ ),
199
+ // should be fixed
200
+ partial_deposit_data: (
201
+ dValidator.partial_deposit_data as DepositData[]
202
+ ).map(depositData => {
203
+ return {
204
+ pubkey: fromHexString(depositData.pubkey),
205
+ withdrawal_credentials: fromHexString(
206
+ depositData.withdrawal_credentials,
207
+ ),
208
+ amount: parseInt(depositData.amount),
209
+ signature: fromHexString(depositData.signature),
210
+ };
211
+ }),
212
+ builder_registration: {
213
+ message: {
214
+ fee_recipient: fromHexString(
215
+ dValidator.builder_registration?.message.fee_recipient as string,
216
+ ),
217
+ gas_limit: dValidator.builder_registration?.message
218
+ .gas_limit as number,
219
+ timestamp: dValidator.builder_registration?.message
220
+ .timestamp as number,
221
+ pubkey: fromHexString(
222
+ dValidator.builder_registration?.message.pubkey as string,
159
223
  ),
160
- // should be fixed
161
- partial_deposit_data: (dValidator.partial_deposit_data as DepositData[]).map(depositData => {
162
- return {
163
- pubkey: fromHexString(depositData.pubkey),
164
- withdrawal_credentials: fromHexString(
165
- depositData.withdrawal_credentials,
166
- ),
167
- amount: parseInt(depositData.amount),
168
- signature: fromHexString(depositData.signature),
169
- }
170
- }),
171
- builder_registration: {
172
- message: {
173
- fee_recipient: fromHexString(
174
- dValidator.builder_registration?.message.fee_recipient as string,
175
- ),
176
- gas_limit: dValidator.builder_registration?.message.gas_limit as number,
177
- timestamp: dValidator.builder_registration?.message.timestamp as number,
178
- pubkey: fromHexString(dValidator.builder_registration?.message.pubkey as string),
179
- },
180
- signature: fromHexString(dValidator.builder_registration?.signature as string),
181
- },
182
- }
183
- })
224
+ },
225
+ signature: fromHexString(
226
+ dValidator.builder_registration?.signature as string,
227
+ ),
228
+ },
229
+ };
230
+ },
231
+ );
184
232
 
185
- return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex')
186
- }
233
+ return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex');
234
+ };
187
235
 
188
236
  // DV verification
189
237
  export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => {
190
- const validators = clusterLock.distributed_validators
191
- const pubShares = []
192
- const pubKeys = []
193
- const builderRegistrationAndDepositDataMessages = []
194
- const blsSignatures = []
238
+ const validators = clusterLock.distributed_validators;
239
+ const pubShares = [];
240
+ const pubKeys = [];
241
+ const builderRegistrationAndDepositDataMessages = [];
242
+ const blsSignatures = [];
195
243
 
196
- for (let i = 0; i < validators.length; i++) {
197
- const validator = validators[i]
198
- const validatorPublicShares = validator.public_shares
199
- const distributedPublicKey = validator.distributed_public_key
244
+ for (let i = 0; i < validators.length; i++) {
245
+ const validator = validators[i];
246
+ const validatorPublicShares = validator.public_shares;
247
+ const distributedPublicKey = validator.distributed_public_key;
200
248
 
201
- // Needed in signature_aggregate verification
202
- for (const element of validatorPublicShares) {
203
- pubShares.push(fromHexString(element))
204
- }
205
-
206
- // Deposit Data Verification
207
- for (let j = 0; j < (validator.partial_deposit_data as DepositData[]).length; j++) {
208
- const depositData = (validator.partial_deposit_data as DepositData[])[j]
209
- const { isValidDepositData, depositDataMsg } = verifyDepositData(
210
- distributedPublicKey,
211
- depositData as Partial<DepositData>,
212
- clusterLock.cluster_definition.validators[i].withdrawal_address,
213
- clusterLock.cluster_definition.fork_version
214
- )
249
+ // Needed in signature_aggregate verification
250
+ for (const element of validatorPublicShares) {
251
+ pubShares.push(fromHexString(element));
252
+ }
215
253
 
216
- if (
217
- !isValidDepositData
218
- ) {
219
- return false
220
- }
254
+ // Deposit Data Verification
255
+ for (const element of validator.partial_deposit_data as DepositData[]) {
256
+ const depositData = element;
257
+ const { isValidDepositData, depositDataMsg } = verifyDepositData(
258
+ distributedPublicKey,
259
+ depositData as Partial<DepositData>,
260
+ clusterLock.cluster_definition.validators[i].withdrawal_address,
261
+ clusterLock.cluster_definition.fork_version,
262
+ );
221
263
 
222
- pubKeys.push(fromHexString(distributedPublicKey))
223
- builderRegistrationAndDepositDataMessages.push(depositDataMsg)
224
- blsSignatures.push(fromHexString(depositData?.signature))
225
- }
264
+ if (!isValidDepositData) {
265
+ return false;
266
+ }
226
267
 
227
- // Builder Registration Verification
228
- const { isValidBuilderRegistration, builderRegistrationMsg } = verifyBuilderRegistration(
229
- validator,
230
- clusterLock.cluster_definition.validators[i].fee_recipient_address,
231
- clusterLock.cluster_definition.fork_version
232
- )
268
+ pubKeys.push(fromHexString(distributedPublicKey));
269
+ builderRegistrationAndDepositDataMessages.push(depositDataMsg);
270
+ blsSignatures.push(fromHexString(depositData?.signature));
271
+ }
233
272
 
234
- if (
235
- !isValidBuilderRegistration
236
- ) {
237
- return false
238
- }
273
+ // Builder Registration Verification
274
+ const { isValidBuilderRegistration, builderRegistrationMsg } =
275
+ verifyBuilderRegistration(
276
+ validator,
277
+ clusterLock.cluster_definition.validators[i].fee_recipient_address,
278
+ clusterLock.cluster_definition.fork_version,
279
+ );
239
280
 
240
- pubKeys.push(fromHexString(distributedPublicKey))
241
- builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg)
242
- blsSignatures.push(
243
- fromHexString(validator.builder_registration?.signature as string),
244
- )
281
+ if (!isValidBuilderRegistration) {
282
+ return false;
245
283
  }
246
284
 
247
- // BLS signatures verification
248
- const aggregateBLSSignature = aggregateSignatures(blsSignatures)
285
+ pubKeys.push(fromHexString(distributedPublicKey));
286
+ builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg);
287
+ blsSignatures.push(
288
+ fromHexString(validator.builder_registration?.signature as string),
289
+ );
290
+ }
249
291
 
250
- if (
251
- !verifyMultiple(
252
- pubKeys,
253
- builderRegistrationAndDepositDataMessages,
254
- aggregateBLSSignature,
255
- )
256
- ) {
257
- return false
258
- }
292
+ // BLS signatures verification
293
+ const aggregateBLSSignature = aggregateSignatures(blsSignatures);
259
294
 
260
- // Node Signatures verification
261
- if (
262
- !verifyNodeSignatures(
263
- clusterLock
264
- )
265
- ) {
266
- return false
267
- }
295
+ if (
296
+ !verifyMultiple(
297
+ pubKeys,
298
+ builderRegistrationAndDepositDataMessages,
299
+ aggregateBLSSignature,
300
+ )
301
+ ) {
302
+ return false;
303
+ }
268
304
 
269
- // signature_aggregate verification
270
- if (
271
- !verifyAggregate(
272
- pubShares,
273
- fromHexString(clusterLock.lock_hash),
274
- fromHexString(clusterLock.signature_aggregate),
275
- )
276
- ) {
277
- return false
278
- }
305
+ // Node Signatures verification
306
+ if (!verifyNodeSignatures(clusterLock)) {
307
+ return false;
308
+ }
309
+
310
+ // signature_aggregate verification
311
+ if (
312
+ !verifyAggregate(
313
+ pubShares,
314
+ fromHexString(clusterLock.lock_hash),
315
+ fromHexString(clusterLock.signature_aggregate),
316
+ )
317
+ ) {
318
+ return false;
319
+ }
279
320
 
280
- return true
281
- }
321
+ return true;
322
+ };