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