@obolnetwork/obol-sdk 1.0.12 → 1.0.14

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 (70) hide show
  1. package/LICENCE +21 -0
  2. package/README.md +33 -3
  3. package/dist/cjs/package.json +128 -0
  4. package/dist/cjs/src/ajv.js +2 -1
  5. package/dist/cjs/src/base.js +2 -2
  6. package/dist/cjs/src/constants.js +38 -13
  7. package/dist/cjs/src/errors.js +1 -1
  8. package/dist/cjs/src/index.js +24 -21
  9. package/dist/cjs/src/schema.js +24 -36
  10. package/dist/cjs/src/services.js +2 -2
  11. package/dist/cjs/src/types.js +0 -1
  12. package/dist/cjs/src/utils.js +36 -1
  13. package/dist/cjs/src/{verify.js → verification/common.js} +128 -155
  14. package/dist/cjs/src/verification/sszTypes.js +69 -0
  15. package/dist/cjs/src/verification/v1.6.0.js +149 -0
  16. package/dist/cjs/src/verification/v1.7.0.js +173 -0
  17. package/dist/cjs/src/verification/v1.8.0.js +183 -0
  18. package/dist/cjs/test/fixtures.js +281 -63
  19. package/dist/cjs/test/methods.test.js +58 -35
  20. package/dist/esm/package.json +128 -0
  21. package/dist/esm/src/ajv.js +2 -1
  22. package/dist/esm/src/base.js +2 -2
  23. package/dist/esm/src/constants.js +14 -12
  24. package/dist/esm/src/errors.js +1 -1
  25. package/dist/esm/src/index.js +27 -24
  26. package/dist/esm/src/schema.js +24 -36
  27. package/dist/esm/src/services.js +1 -1
  28. package/dist/esm/src/types.js +0 -1
  29. package/dist/esm/src/utils.js +34 -0
  30. package/dist/esm/src/{verify.js → verification/common.js} +114 -146
  31. package/dist/esm/src/verification/sszTypes.js +64 -0
  32. package/dist/esm/src/verification/v1.6.0.js +142 -0
  33. package/dist/esm/src/verification/v1.7.0.js +166 -0
  34. package/dist/esm/src/verification/v1.8.0.js +176 -0
  35. package/dist/esm/test/fixtures.js +280 -62
  36. package/dist/esm/test/methods.test.js +59 -36
  37. package/dist/types/src/ajv.d.ts +1 -1
  38. package/dist/types/src/base.d.ts +3 -3
  39. package/dist/types/src/constants.d.ts +8 -10
  40. package/dist/types/src/index.d.ts +16 -16
  41. package/dist/types/src/services.d.ts +1 -1
  42. package/dist/types/src/types.d.ts +33 -27
  43. package/dist/types/src/utils.d.ts +3 -0
  44. package/dist/types/src/verification/common.d.ts +32 -0
  45. package/dist/types/src/verification/sszTypes.d.ts +63 -0
  46. package/dist/types/src/verification/v1.6.0.d.ts +34 -0
  47. package/dist/types/src/verification/v1.7.0.d.ts +34 -0
  48. package/dist/types/src/verification/v1.8.0.d.ts +35 -0
  49. package/dist/types/test/fixtures.d.ts +104 -2
  50. package/package.json +42 -8
  51. package/src/ajv.ts +15 -10
  52. package/src/base.ts +25 -21
  53. package/src/constants.ts +80 -78
  54. package/src/errors.ts +6 -9
  55. package/src/index.ts +118 -81
  56. package/src/schema.ts +24 -36
  57. package/src/services.ts +15 -13
  58. package/src/types.ts +72 -74
  59. package/src/utils.ts +53 -4
  60. package/src/verification/common.ts +420 -0
  61. package/src/verification/sszTypes.ts +79 -0
  62. package/src/verification/v1.6.0.ts +226 -0
  63. package/src/verification/v1.7.0.ts +274 -0
  64. package/src/verification/v1.8.0.ts +281 -0
  65. package/dist/cjs/src/hash.js +0 -172
  66. package/dist/esm/src/hash.js +0 -165
  67. package/dist/types/src/hash.d.ts +0 -56
  68. package/dist/types/src/verify.d.ts +0 -4
  69. package/src/hash.ts +0 -250
  70. package/src/verify.ts +0 -479
@@ -0,0 +1,166 @@
1
+ import { UintNumberType } from '@chainsafe/ssz/lib/type/uint';
2
+ import { strToUint8Array } from '../utils';
3
+ import { builderRegistrationContainer, depositDataContainer, newCreatorContainerType, newOperatorContainerType, validatorsContainerType } from './sszTypes';
4
+ import { ByteListType, ByteVectorType, ContainerType, ListCompositeType, fromHexString } from '@chainsafe/ssz';
5
+ import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from './common';
6
+ import { aggregateSignatures, verifyAggregate, verifyMultiple } from '@chainsafe/bls';
7
+ /**
8
+ * Returns the containerized cluster definition
9
+ * @param cluster ClusterDefinition to calculate the type from
10
+ * @returns SSZ Containerized type of cluster input
11
+ */
12
+ export const clusterDefinitionContainerTypeV1X7 = (configOnly) => {
13
+ let returnedContainerType = {
14
+ uuid: new ByteListType(64),
15
+ name: new ByteListType(256),
16
+ version: new ByteListType(16),
17
+ timestamp: new ByteListType(32),
18
+ num_validators: new UintNumberType(8),
19
+ threshold: new UintNumberType(8),
20
+ dkg_algorithm: new ByteListType(32),
21
+ fork_version: new ByteVectorType(4),
22
+ operators: new ListCompositeType(newOperatorContainerType(configOnly), 256),
23
+ creator: newCreatorContainerType(configOnly),
24
+ validators: new ListCompositeType(validatorsContainerType, 65536),
25
+ };
26
+ if (!configOnly) {
27
+ returnedContainerType = Object.assign(Object.assign({}, returnedContainerType), { config_hash: new ByteVectorType(32) });
28
+ }
29
+ return new ContainerType(returnedContainerType);
30
+ };
31
+ export const hashClusterDefinitionV1X7 = (cluster, configOnly) => {
32
+ const definitionType = clusterDefinitionContainerTypeV1X7(configOnly);
33
+ const val = definitionType.defaultValue();
34
+ // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276
35
+ val.uuid = strToUint8Array(cluster.uuid);
36
+ val.name = strToUint8Array(cluster.name);
37
+ val.version = strToUint8Array(cluster.version);
38
+ val.timestamp = strToUint8Array(cluster.timestamp);
39
+ val.num_validators = cluster.num_validators;
40
+ val.threshold = cluster.threshold;
41
+ val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm);
42
+ val.fork_version = fromHexString(cluster.fork_version);
43
+ val.operators = cluster.operators.map(operator => {
44
+ return configOnly
45
+ ? { address: fromHexString(operator.address) }
46
+ : {
47
+ address: fromHexString(operator.address),
48
+ enr: strToUint8Array(operator.enr),
49
+ config_signature: fromHexString(operator.config_signature),
50
+ enr_signature: fromHexString(operator.enr_signature),
51
+ };
52
+ });
53
+ val.creator = configOnly
54
+ ? { address: fromHexString(cluster.creator.address) }
55
+ : {
56
+ address: fromHexString(cluster.creator.address),
57
+ config_signature: fromHexString(cluster.creator.config_signature),
58
+ };
59
+ val.validators = cluster.validators.map((validator) => {
60
+ return {
61
+ fee_recipient_address: fromHexString(validator.fee_recipient_address),
62
+ withdrawal_address: fromHexString(validator.withdrawal_address),
63
+ };
64
+ });
65
+ if (!configOnly) {
66
+ val.config_hash = fromHexString(cluster.config_hash);
67
+ }
68
+ return val;
69
+ };
70
+ // cluster lock
71
+ const dvContainerTypeV1X7 = new ContainerType({
72
+ distributed_public_key: new ByteVectorType(48),
73
+ public_shares: new ListCompositeType(new ByteVectorType(48), 256),
74
+ deposit_data: depositDataContainer,
75
+ builder_registration: builderRegistrationContainer,
76
+ });
77
+ /**
78
+ * @returns SSZ Containerized type of cluster lock
79
+ */
80
+ const clusterLockContainerTypeV1X7 = () => {
81
+ return new ContainerType({
82
+ cluster_definition: clusterDefinitionContainerTypeV1X7(false),
83
+ distributed_validators: new ListCompositeType(dvContainerTypeV1X7, 65536),
84
+ });
85
+ };
86
+ /**
87
+ * @param cluster The published cluster lock
88
+ * @returns The lock hash in of the corresponding cluster
89
+ */
90
+ export const hashClusterLockV1X7 = (cluster) => {
91
+ const lockType = clusterLockContainerTypeV1X7();
92
+ const val = lockType.defaultValue();
93
+ // Check if we can replace with definition_hash
94
+ val.cluster_definition = hashClusterDefinitionV1X7(cluster.cluster_definition, false);
95
+ val.distributed_validators = cluster.distributed_validators.map((dValidator) => {
96
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
97
+ return {
98
+ distributed_public_key: fromHexString(dValidator.distributed_public_key),
99
+ public_shares: dValidator.public_shares.map((publicShare) => fromHexString(publicShare)),
100
+ deposit_data: {
101
+ pubkey: fromHexString((_a = dValidator.deposit_data) === null || _a === void 0 ? void 0 : _a.pubkey),
102
+ withdrawal_credentials: fromHexString((_b = dValidator.deposit_data) === null || _b === void 0 ? void 0 : _b.withdrawal_credentials),
103
+ amount: parseInt((_c = dValidator.deposit_data) === null || _c === void 0 ? void 0 : _c.amount),
104
+ signature: fromHexString((_d = dValidator.deposit_data) === null || _d === void 0 ? void 0 : _d.signature),
105
+ },
106
+ builder_registration: {
107
+ message: {
108
+ fee_recipient: fromHexString((_e = dValidator.builder_registration) === null || _e === void 0 ? void 0 : _e.message.fee_recipient),
109
+ gas_limit: (_f = dValidator.builder_registration) === null || _f === void 0 ? void 0 : _f.message.gas_limit,
110
+ timestamp: (_g = dValidator.builder_registration) === null || _g === void 0 ? void 0 : _g.message.timestamp,
111
+ pubkey: fromHexString((_h = dValidator.builder_registration) === null || _h === void 0 ? void 0 : _h.message.pubkey),
112
+ },
113
+ signature: fromHexString((_j = dValidator.builder_registration) === null || _j === void 0 ? void 0 : _j.signature),
114
+ },
115
+ };
116
+ });
117
+ return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex');
118
+ };
119
+ // DV verification
120
+ export const verifyDVV1X7 = (clusterLock) => {
121
+ var _a, _b;
122
+ const validators = clusterLock.distributed_validators;
123
+ const pubShares = [];
124
+ const pubKeys = [];
125
+ const builderRegistrationAndDepositDataMessages = [];
126
+ const blsSignatures = [];
127
+ for (let i = 0; i < validators.length; i++) {
128
+ const validator = validators[i];
129
+ const validatorPublicShares = validator.public_shares;
130
+ const distributedPublicKey = validator.distributed_public_key;
131
+ // Needed in signature_aggregate verification
132
+ for (const element of validatorPublicShares) {
133
+ pubShares.push(fromHexString(element));
134
+ }
135
+ // Deposit Data Verification
136
+ const { isValidDepositData, depositDataMsg } = verifyDepositData(distributedPublicKey, validator.deposit_data, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version);
137
+ if (!isValidDepositData) {
138
+ return false;
139
+ }
140
+ pubKeys.push(fromHexString(distributedPublicKey));
141
+ builderRegistrationAndDepositDataMessages.push(depositDataMsg);
142
+ blsSignatures.push(fromHexString((_a = validator.deposit_data) === null || _a === void 0 ? void 0 : _a.signature));
143
+ // Builder Registration Verification
144
+ const { isValidBuilderRegistration, builderRegistrationMsg } = verifyBuilderRegistration(validator, clusterLock.cluster_definition.validators[i].fee_recipient_address, clusterLock.cluster_definition.fork_version);
145
+ if (!isValidBuilderRegistration) {
146
+ return false;
147
+ }
148
+ pubKeys.push(fromHexString(distributedPublicKey));
149
+ builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg);
150
+ blsSignatures.push(fromHexString((_b = validator.builder_registration) === null || _b === void 0 ? void 0 : _b.signature));
151
+ }
152
+ // BLS signatures verification
153
+ const aggregateBLSSignature = aggregateSignatures(blsSignatures);
154
+ if (!verifyMultiple(pubKeys, builderRegistrationAndDepositDataMessages, aggregateBLSSignature)) {
155
+ return false;
156
+ }
157
+ // Node Signatures verification
158
+ if (!verifyNodeSignatures(clusterLock)) {
159
+ return false;
160
+ }
161
+ // signature_aggregate verification
162
+ if (!verifyAggregate(pubShares, fromHexString(clusterLock.lock_hash), fromHexString(clusterLock.signature_aggregate))) {
163
+ return false;
164
+ }
165
+ return true;
166
+ };
@@ -0,0 +1,176 @@
1
+ import { UintNumberType } from '@chainsafe/ssz/lib/type/uint';
2
+ import { strToUint8Array } from '../utils';
3
+ import { builderRegistrationContainer, depositDataContainer, newCreatorContainerType, newOperatorContainerType, validatorsContainerType } from './sszTypes';
4
+ import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString } from '@chainsafe/ssz';
5
+ import { verifyBuilderRegistration, verifyDepositData, verifyNodeSignatures } from './common';
6
+ import { aggregateSignatures, verifyAggregate, verifyMultiple } from '@chainsafe/bls';
7
+ /**
8
+ * Returns the containerized cluster definition
9
+ * @param cluster ClusterDefinition to calculate the type from
10
+ * @returns SSZ Containerized type of cluster input
11
+ */
12
+ export const clusterDefinitionContainerTypeV1X8 = (configOnly) => {
13
+ let returnedContainerType = {
14
+ uuid: new ByteListType(64),
15
+ name: new ByteListType(256),
16
+ version: new ByteListType(16),
17
+ timestamp: new ByteListType(32),
18
+ num_validators: new UintNumberType(8),
19
+ threshold: new UintNumberType(8),
20
+ dkg_algorithm: new ByteListType(32),
21
+ fork_version: new ByteVectorType(4),
22
+ operators: new ListCompositeType(newOperatorContainerType(configOnly), 256),
23
+ creator: newCreatorContainerType(configOnly),
24
+ validators: new ListCompositeType(validatorsContainerType, 65536),
25
+ deposit_amounts: new ListBasicType(new UintNumberType(8), 256),
26
+ };
27
+ if (!configOnly) {
28
+ returnedContainerType = Object.assign(Object.assign({}, returnedContainerType), { config_hash: new ByteVectorType(32) });
29
+ }
30
+ return new ContainerType(returnedContainerType);
31
+ };
32
+ export const hashClusterDefinitionV1X8 = (cluster, configOnly) => {
33
+ const definitionType = clusterDefinitionContainerTypeV1X8(configOnly);
34
+ const val = definitionType.defaultValue();
35
+ // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276
36
+ val.uuid = strToUint8Array(cluster.uuid);
37
+ val.name = strToUint8Array(cluster.name);
38
+ val.version = strToUint8Array(cluster.version);
39
+ val.timestamp = strToUint8Array(cluster.timestamp);
40
+ val.num_validators = cluster.num_validators;
41
+ val.threshold = cluster.threshold;
42
+ val.dkg_algorithm = strToUint8Array(cluster.dkg_algorithm);
43
+ val.fork_version = fromHexString(cluster.fork_version);
44
+ val.operators = cluster.operators.map(operator => {
45
+ return configOnly
46
+ ? { address: fromHexString(operator.address) }
47
+ : {
48
+ address: fromHexString(operator.address),
49
+ enr: strToUint8Array(operator.enr),
50
+ config_signature: fromHexString(operator.config_signature),
51
+ enr_signature: fromHexString(operator.enr_signature),
52
+ };
53
+ });
54
+ val.creator = configOnly
55
+ ? { address: fromHexString(cluster.creator.address) }
56
+ : {
57
+ address: fromHexString(cluster.creator.address),
58
+ config_signature: fromHexString(cluster.creator.config_signature),
59
+ };
60
+ val.validators = cluster.validators.map((validator) => {
61
+ return {
62
+ fee_recipient_address: fromHexString(validator.fee_recipient_address),
63
+ withdrawal_address: fromHexString(validator.withdrawal_address),
64
+ };
65
+ });
66
+ val.deposit_amounts = cluster.deposit_amounts.map((amount) => {
67
+ return parseInt(amount);
68
+ });
69
+ if (!configOnly) {
70
+ val.config_hash = fromHexString(cluster.config_hash);
71
+ }
72
+ return val;
73
+ };
74
+ // cluster lock
75
+ const dvContainerTypeV1X8 = new ContainerType({
76
+ distributed_public_key: new ByteVectorType(48),
77
+ public_shares: new ListCompositeType(new ByteVectorType(48), 256),
78
+ partial_deposit_data: new ListCompositeType(depositDataContainer, 256),
79
+ builder_registration: builderRegistrationContainer,
80
+ });
81
+ /**
82
+ * @returns SSZ Containerized type of cluster lock
83
+ */
84
+ const clusterLockContainerTypeV1X8 = () => {
85
+ return new ContainerType({
86
+ cluster_definition: clusterDefinitionContainerTypeV1X8(false),
87
+ distributed_validators: new ListCompositeType(dvContainerTypeV1X8, 65536),
88
+ });
89
+ };
90
+ /**
91
+ * @param cluster The published cluster lock
92
+ * @returns The lock hash in of the corresponding cluster
93
+ */
94
+ export const hashClusterLockV1X8 = (cluster) => {
95
+ const lockType = clusterLockContainerTypeV1X8();
96
+ const val = lockType.defaultValue();
97
+ // Check if we can replace with definition_hash
98
+ val.cluster_definition = hashClusterDefinitionV1X8(cluster.cluster_definition, false);
99
+ val.distributed_validators = cluster.distributed_validators.map(dValidator => {
100
+ var _a, _b, _c, _d, _e;
101
+ return {
102
+ distributed_public_key: fromHexString(dValidator.distributed_public_key),
103
+ public_shares: dValidator.public_shares.map(publicShare => fromHexString(publicShare)),
104
+ // should be fixed
105
+ partial_deposit_data: dValidator.partial_deposit_data.map(depositData => {
106
+ return {
107
+ pubkey: fromHexString(depositData.pubkey),
108
+ withdrawal_credentials: fromHexString(depositData.withdrawal_credentials),
109
+ amount: parseInt(depositData.amount),
110
+ signature: fromHexString(depositData.signature),
111
+ };
112
+ }),
113
+ builder_registration: {
114
+ message: {
115
+ fee_recipient: fromHexString((_a = dValidator.builder_registration) === null || _a === void 0 ? void 0 : _a.message.fee_recipient),
116
+ gas_limit: (_b = dValidator.builder_registration) === null || _b === void 0 ? void 0 : _b.message.gas_limit,
117
+ timestamp: (_c = dValidator.builder_registration) === null || _c === void 0 ? void 0 : _c.message.timestamp,
118
+ pubkey: fromHexString((_d = dValidator.builder_registration) === null || _d === void 0 ? void 0 : _d.message.pubkey),
119
+ },
120
+ signature: fromHexString((_e = dValidator.builder_registration) === null || _e === void 0 ? void 0 : _e.signature),
121
+ },
122
+ };
123
+ });
124
+ return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex');
125
+ };
126
+ // DV verification
127
+ export const verifyDVV1X8 = (clusterLock) => {
128
+ var _a;
129
+ const validators = clusterLock.distributed_validators;
130
+ const pubShares = [];
131
+ const pubKeys = [];
132
+ const builderRegistrationAndDepositDataMessages = [];
133
+ const blsSignatures = [];
134
+ for (let i = 0; i < validators.length; i++) {
135
+ const validator = validators[i];
136
+ const validatorPublicShares = validator.public_shares;
137
+ const distributedPublicKey = validator.distributed_public_key;
138
+ // Needed in signature_aggregate verification
139
+ for (const element of validatorPublicShares) {
140
+ pubShares.push(fromHexString(element));
141
+ }
142
+ // Deposit Data Verification
143
+ for (let j = 0; j < validator.partial_deposit_data.length; j++) {
144
+ const depositData = validator.partial_deposit_data[i];
145
+ const { isValidDepositData, depositDataMsg } = verifyDepositData(distributedPublicKey, depositData, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version);
146
+ if (!isValidDepositData) {
147
+ return false;
148
+ }
149
+ pubKeys.push(fromHexString(distributedPublicKey));
150
+ builderRegistrationAndDepositDataMessages.push(depositDataMsg);
151
+ blsSignatures.push(fromHexString(depositData === null || depositData === void 0 ? void 0 : depositData.signature));
152
+ }
153
+ // Builder Registration Verification
154
+ const { isValidBuilderRegistration, builderRegistrationMsg } = verifyBuilderRegistration(validator, clusterLock.cluster_definition.validators[i].fee_recipient_address, clusterLock.cluster_definition.fork_version);
155
+ if (!isValidBuilderRegistration) {
156
+ return false;
157
+ }
158
+ pubKeys.push(fromHexString(distributedPublicKey));
159
+ builderRegistrationAndDepositDataMessages.push(builderRegistrationMsg);
160
+ blsSignatures.push(fromHexString((_a = validator.builder_registration) === null || _a === void 0 ? void 0 : _a.signature));
161
+ }
162
+ // BLS signatures verification
163
+ const aggregateBLSSignature = aggregateSignatures(blsSignatures);
164
+ if (!verifyMultiple(pubKeys, builderRegistrationAndDepositDataMessages, aggregateBLSSignature)) {
165
+ return false;
166
+ }
167
+ // Node Signatures verification
168
+ if (!verifyNodeSignatures(clusterLock)) {
169
+ return false;
170
+ }
171
+ // signature_aggregate verification
172
+ if (!verifyAggregate(pubShares, fromHexString(clusterLock.lock_hash), fromHexString(clusterLock.signature_aggregate))) {
173
+ return false;
174
+ }
175
+ return true;
176
+ };