@obolnetwork/obol-sdk 1.0.12 → 1.0.13

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
@@ -35,73 +35,69 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.isValidClusterLock = exports.signingRoot = void 0;
39
- const semver = __importStar(require("semver"));
40
- const bls_1 = require("@chainsafe/bls");
41
- const discv5_1 = require("@chainsafe/discv5");
38
+ exports.isValidClusterLock = exports.signingRoot = exports.verifyNodeSignatures = exports.verifyBuilderRegistration = exports.verifyDepositData = exports.clusterLockHash = exports.clusterConfigOrDefinitionHash = void 0;
42
39
  const ssz_1 = require("@chainsafe/ssz");
43
- const uint_js_1 = require("@chainsafe/ssz/lib/type/uint.js");
44
- const eth_sig_util_1 = require("@metamask/eth-sig-util");
45
40
  const elliptic_1 = __importDefault(require("elliptic"));
41
+ const bls_1 = require("@chainsafe/bls");
42
+ const types_js_1 = require("../types.js");
43
+ const semver = __importStar(require("semver"));
44
+ const v1_6_0_js_1 = require("./v1.6.0.js");
45
+ const v1_7_0_js_1 = require("./v1.7.0.js");
46
46
  const ethers_1 = require("ethers");
47
- const types_js_1 = require("./types.js");
48
- const hash_js_1 = require("./hash.js");
49
- const constants_js_1 = require("./constants.js");
50
- const utils_js_1 = require("./utils.js");
51
- const builderRegistrationMessageType = new ssz_1.ContainerType({
52
- fee_recipient: new ssz_1.ByteVectorType(20),
53
- gas_limit: new uint_js_1.UintNumberType(8),
54
- timestamp: new uint_js_1.UintNumberType(8),
55
- pubkey: new ssz_1.ByteVectorType(48),
56
- });
57
- //For domain computation that is used in deposit data and builder registration verification for dv
58
- const forkDataType = new ssz_1.ContainerType({
59
- currentVersion: new ssz_1.ByteVectorType(4),
60
- genesisValidatorsRoot: new ssz_1.ByteVectorType(32),
61
- });
62
- const depositMessageType = new ssz_1.ContainerType({
63
- pubkey: new ssz_1.ByteVectorType(48),
64
- withdrawal_credentials: new ssz_1.ByteVectorType(32),
65
- amount: new uint_js_1.UintNumberType(8),
66
- });
67
- const signingRootType = new ssz_1.ContainerType({
68
- objectRoot: new ssz_1.ByteVectorType(32),
69
- domain: new ssz_1.ByteVectorType(32),
70
- });
71
- const definitionFlow = (clusterDefinition) => {
72
- if (clusterDefinition.creator.address &&
73
- clusterDefinition.creator.config_signature &&
74
- clusterDefinition.operators.every(operator => {
75
- return (operator.address &&
76
- operator.config_signature &&
77
- operator.enr &&
78
- operator.enr_signature);
79
- })) {
80
- return constants_js_1.DefinitionFlow.Group;
47
+ const constants_js_1 = require("../constants.js");
48
+ const eth_sig_util_1 = require("@metamask/eth-sig-util");
49
+ const sszTypes_js_1 = require("./sszTypes.js");
50
+ const utils_js_1 = require("../utils.js");
51
+ const discv5_1 = require("@chainsafe/discv5");
52
+ const v1_8_0_js_1 = require("./v1.8.0.js");
53
+ // cluster-definition hash
54
+ /**
55
+ * @param cluster The cluster configuration or the cluster definition
56
+ * @param configOnly a boolean to indicate config hash or definition hash
57
+ * @returns The config hash or the definition hash in of the corresponding cluster
58
+ */
59
+ const clusterConfigOrDefinitionHash = (cluster, configOnly) => {
60
+ let definitionType, val;
61
+ if (semver.eq(cluster.version, 'v1.6.0')) {
62
+ definitionType = (0, v1_6_0_js_1.clusterDefinitionContainerTypeV1X6)(configOnly);
63
+ val = (0, v1_6_0_js_1.hashClusterDefinitionV1X6)(cluster, configOnly);
64
+ return ('0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex'));
65
+ }
66
+ if (semver.eq(cluster.version, 'v1.7.0')) {
67
+ definitionType = (0, v1_7_0_js_1.clusterDefinitionContainerTypeV1X7)(configOnly);
68
+ val = (0, v1_7_0_js_1.hashClusterDefinitionV1X7)(cluster, configOnly);
69
+ return ('0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex'));
70
+ }
71
+ if (semver.eq(cluster.version, 'v1.8.0')) {
72
+ definitionType = (0, v1_8_0_js_1.clusterDefinitionContainerTypeV1X8)(configOnly);
73
+ val = (0, v1_8_0_js_1.hashClusterDefinitionV1X8)(cluster, configOnly);
74
+ return ('0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex'));
81
75
  }
82
- else if (clusterDefinition.creator.address &&
83
- clusterDefinition.creator.config_signature &&
84
- clusterDefinition.operators.every(operator => {
85
- return (!operator.address &&
86
- !operator.config_signature &&
87
- operator.enr &&
88
- !operator.enr_signature);
89
- })) {
90
- return constants_js_1.DefinitionFlow.Solo;
76
+ throw new Error('unsupported version');
77
+ };
78
+ exports.clusterConfigOrDefinitionHash = clusterConfigOrDefinitionHash;
79
+ // cluster-lock hash
80
+ /**
81
+ * Returns the SSZ cluster lock hash of the given cluster lock object
82
+ * @param cluster The cluster lock whose lock hash needs to be calculated
83
+ * @returns The cluster lock hash in of the corresponding cluster lock
84
+ */
85
+ const clusterLockHash = (clusterLock) => {
86
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.6.0')) {
87
+ return (0, v1_6_0_js_1.hashClusterLockV1X6)(clusterLock);
88
+ }
89
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.7.0')) {
90
+ return (0, v1_7_0_js_1.hashClusterLockV1X7)(clusterLock);
91
91
  }
92
- else if (!clusterDefinition.creator.address &&
93
- !clusterDefinition.creator.config_signature &&
94
- clusterDefinition.operators.every(operator => {
95
- return (!operator.address &&
96
- !operator.config_signature &&
97
- operator.enr &&
98
- !operator.enr_signature);
99
- })) {
100
- return constants_js_1.DefinitionFlow.Charon;
92
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) {
93
+ return (0, v1_8_0_js_1.hashClusterLockV1X8)(clusterLock);
101
94
  }
102
- return null;
95
+ // other versions
96
+ throw new Error('unsupported version');
103
97
  };
104
- //cluster-definition signatures verificatin
98
+ exports.clusterLockHash = clusterLockHash;
99
+ // Lock verification
100
+ // cluster-definition signatures verification
105
101
  const getPOSTConfigHashSigner = (signature, configHash, chainId) => {
106
102
  try {
107
103
  const sig = ethers_1.ethers.Signature.from(signature);
@@ -136,7 +132,7 @@ const getEnrSigner = (signature, payload, chainId) => {
136
132
  }
137
133
  };
138
134
  const verifyDefinitionSignatures = (clusterDefinition, definitionType) => {
139
- if (definitionType === 'Charon-Command') {
135
+ if (definitionType === constants_js_1.DefinitionFlow.Charon) {
140
136
  return true;
141
137
  }
142
138
  else {
@@ -144,10 +140,10 @@ const verifyDefinitionSignatures = (clusterDefinition, definitionType) => {
144
140
  if (configSigner !== clusterDefinition.creator.address.toLowerCase()) {
145
141
  return false;
146
142
  }
147
- if (definitionType === 'LP-Solo') {
143
+ if (definitionType === constants_js_1.DefinitionFlow.Solo) {
148
144
  return true;
149
145
  }
150
- return clusterDefinition.operators.every(operator => {
146
+ return clusterDefinition.operators.every((operator) => {
151
147
  const configSigner = getPUTConfigHashSigner(operator.config_signature, clusterDefinition.config_hash, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
152
148
  const enrSigner = getEnrSigner(operator.enr_signature, operator.enr, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
153
149
  if (configSigner !== operator.address.toLowerCase() ||
@@ -158,36 +154,35 @@ const verifyDefinitionSignatures = (clusterDefinition, definitionType) => {
158
154
  });
159
155
  }
160
156
  };
161
- //cluster-lock data verification
157
+ // cluster-lock data verification
162
158
  const computeSigningRoot = (sszObjectRoot, domain) => {
163
- const val1 = signingRootType.defaultValue();
164
- val1.objectRoot = sszObjectRoot;
165
- val1.domain = domain;
166
- return Buffer.from(signingRootType.hashTreeRoot(val1).buffer);
159
+ const signingRootDefaultValue = sszTypes_js_1.signingRootType.defaultValue();
160
+ signingRootDefaultValue.objectRoot = sszObjectRoot;
161
+ signingRootDefaultValue.domain = domain;
162
+ return Buffer.from(sszTypes_js_1.signingRootType.hashTreeRoot(signingRootDefaultValue).buffer);
167
163
  };
168
164
  const computeDepositMsgRoot = (msg) => {
169
- const depositMsgVal = depositMessageType.defaultValue();
165
+ const depositMsgVal = sszTypes_js_1.depositMessageType.defaultValue();
170
166
  depositMsgVal.pubkey = (0, ssz_1.fromHexString)(msg.pubkey);
171
167
  depositMsgVal.withdrawal_credentials = (0, ssz_1.fromHexString)(msg.withdrawal_credentials);
172
168
  depositMsgVal.amount = parseInt(msg.amount);
173
- return Buffer.from(depositMessageType.hashTreeRoot(depositMsgVal).buffer);
169
+ return Buffer.from(sszTypes_js_1.depositMessageType.hashTreeRoot(depositMsgVal).buffer);
174
170
  };
175
171
  const computeForkDataRoot = (currentVersion, genesisValidatorsRoot) => {
176
- const forkDataVal = forkDataType.defaultValue();
172
+ const forkDataVal = sszTypes_js_1.forkDataType.defaultValue();
177
173
  forkDataVal.currentVersion = currentVersion;
178
174
  forkDataVal.genesisValidatorsRoot = genesisValidatorsRoot;
179
- return Buffer.from(forkDataType.hashTreeRoot(forkDataVal).buffer);
175
+ return Buffer.from(sszTypes_js_1.forkDataType.hashTreeRoot(forkDataVal).buffer);
180
176
  };
181
177
  const computebuilderRegistrationMsgRoot = (msg) => {
182
- const builderRegistrationMsgVal = builderRegistrationMessageType.defaultValue();
178
+ const builderRegistrationMsgVal = sszTypes_js_1.builderRegistrationMessageType.defaultValue();
183
179
  builderRegistrationMsgVal.fee_recipient = (0, ssz_1.fromHexString)(msg.fee_recipient);
184
180
  builderRegistrationMsgVal.gas_limit = msg.gas_limit;
185
181
  builderRegistrationMsgVal.timestamp = msg.timestamp;
186
182
  builderRegistrationMsgVal.pubkey = (0, ssz_1.fromHexString)(msg.pubkey);
187
- return Buffer.from(builderRegistrationMessageType.hashTreeRoot(builderRegistrationMsgVal)
183
+ return Buffer.from(sszTypes_js_1.builderRegistrationMessageType.hashTreeRoot(builderRegistrationMsgVal)
188
184
  .buffer);
189
185
  };
190
- // DV data verification
191
186
  const computeDomain = (domainType, lockForkVersion, genesisValidatorsRoot = (0, ssz_1.fromHexString)(constants_js_1.GENESIS_VALIDATOR_ROOT)) => {
192
187
  const forkVersion = (0, ssz_1.fromHexString)(lockForkVersion.substring(2, lockForkVersion.length));
193
188
  const forkDataRoot = computeForkDataRoot(forkVersion, genesisValidatorsRoot);
@@ -196,121 +191,99 @@ const computeDomain = (domainType, lockForkVersion, genesisValidatorsRoot = (0,
196
191
  domain.set(forkDataRoot.subarray(0, 28), 4);
197
192
  return domain;
198
193
  };
199
- const verifyDepositData = (validator, withdrawalAddress) => {
194
+ /**
195
+ * Verify deposit data withdrawal credintials and signature
196
+ * @param {string} forkVersion - fork version in definition file.
197
+ * @param {DistributedValidatorDto} validator - distributed validator.
198
+ * @param {string} withdrawalAddress - withdrawal address in definition file.
199
+ * @returns {boolean} - return if deposit data is valid.
200
+ */
201
+ const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion) => {
202
+ const depositDomain = computeDomain((0, ssz_1.fromHexString)(constants_js_1.DOMAIN_DEPOSIT), forkVersion);
200
203
  const eth1AddressWithdrawalPrefix = '0x01';
201
204
  if (eth1AddressWithdrawalPrefix +
202
205
  '0'.repeat(22) +
203
206
  withdrawalAddress.toLowerCase().slice(2) !==
204
- validator.deposit_data.withdrawal_credentials) {
205
- return false;
207
+ depositData.withdrawal_credentials) {
208
+ return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) };
206
209
  }
207
- if (validator.distributed_public_key !== validator.deposit_data.pubkey) {
208
- return false;
210
+ if (distributedPublicKey !== depositData.pubkey) {
211
+ return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) };
209
212
  }
210
- return true;
213
+ const depositMessageBuffer = computeDepositMsgRoot(depositData);
214
+ const depositDataMessage = (0, exports.signingRoot)(depositDomain, depositMessageBuffer);
215
+ return { isValidDepositData: true, depositDataMsg: depositDataMessage };
211
216
  };
212
- const verifyBuilderRegistration = (validator, feeRecipientAddress) => {
217
+ exports.verifyDepositData = verifyDepositData;
218
+ const verifyBuilderRegistration = (validator, feeRecipientAddress, forkVersion) => {
219
+ var _a;
220
+ const builderDomain = computeDomain((0, ssz_1.fromHexString)(constants_js_1.DOMAIN_APPLICATION_BUILDER), forkVersion);
213
221
  if (validator.distributed_public_key !==
214
- validator.builder_registration.message.pubkey) {
215
- return false;
222
+ ((_a = validator.builder_registration) === null || _a === void 0 ? void 0 : _a.message.pubkey)) {
223
+ return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) };
216
224
  }
217
225
  if (feeRecipientAddress.toLowerCase() !==
218
226
  validator.builder_registration.message.fee_recipient.toLowerCase()) {
219
- return false;
227
+ return { isValidBuilderRegistration: false, builderRegistrationMsg: new Uint8Array(0) };
228
+ }
229
+ const builderRegistrationMessageBuffer = computebuilderRegistrationMsgRoot(validator.builder_registration.message);
230
+ const builderRegistrationMessage = (0, exports.signingRoot)(builderDomain, builderRegistrationMessageBuffer);
231
+ return { isValidBuilderRegistration: true, builderRegistrationMsg: builderRegistrationMessage };
232
+ };
233
+ exports.verifyBuilderRegistration = verifyBuilderRegistration;
234
+ const verifyNodeSignatures = (clusterLock) => {
235
+ const ec = new elliptic_1.default.ec('secp256k1');
236
+ const nodeSignatures = clusterLock.node_signatures;
237
+ const lockHashWithout0x = (0, utils_js_1.hexWithout0x)(clusterLock.lock_hash);
238
+ // node(ENR) signatures
239
+ for (let i = 0; i < nodeSignatures.length; i++) {
240
+ const pubkey = discv5_1.ENR.decodeTxt(clusterLock.cluster_definition.operators[i].enr).publicKey.toString('hex');
241
+ const ENRsignature = {
242
+ r: nodeSignatures[i].slice(2, 66),
243
+ s: nodeSignatures[i].slice(66, 130),
244
+ };
245
+ const nodeSignatureVerification = ec
246
+ .keyFromPublic(pubkey, 'hex')
247
+ .verify(lockHashWithout0x, ENRsignature);
248
+ if (!nodeSignatureVerification) {
249
+ return false;
250
+ }
220
251
  }
221
252
  return true;
222
253
  };
254
+ exports.verifyNodeSignatures = verifyNodeSignatures;
223
255
  const signingRoot = (domain, messageBuffer) => {
224
256
  return computeSigningRoot(messageBuffer, domain);
225
257
  };
226
258
  exports.signingRoot = signingRoot;
227
259
  const verifyLockData = (clusterLock) => __awaiter(void 0, void 0, void 0, function* () {
228
- const ec = new elliptic_1.default.ec('secp256k1');
229
- const validators = clusterLock.distributed_validators;
230
- const nodeSignatures = clusterLock.node_signatures;
231
- const depositDomain = computeDomain((0, ssz_1.fromHexString)(constants_js_1.DOMAIN_DEPOSIT), clusterLock.cluster_definition.fork_version);
232
- const builderDomain = computeDomain((0, ssz_1.fromHexString)(constants_js_1.DOMAIN_APPLICATION_BUILDER), clusterLock.cluster_definition.fork_version);
233
- const pubShares = [];
234
- const pubKeys = [];
235
- const builderRegistrationAndDepositDataMessages = [];
236
- const blsSignatures = [];
237
260
  yield (0, bls_1.init)('herumi');
238
- for (let i = 0; i < validators.length; i++) {
239
- const validator = validators[i];
240
- const validatorPublicShares = validator['public_shares'];
241
- for (const element of validatorPublicShares) {
242
- pubShares.push((0, ssz_1.fromHexString)(element));
243
- }
244
- //Deposit data signature
245
- if (semver.gte(clusterLock.cluster_definition.version, 'v1.6.0')) {
246
- if (!verifyDepositData(validator, clusterLock.cluster_definition.validators[i].withdrawal_address)) {
247
- return false;
248
- }
249
- const depositMessageBuffer = computeDepositMsgRoot(validator.deposit_data);
250
- const depositDataMessage = (0, exports.signingRoot)(depositDomain, depositMessageBuffer);
251
- pubKeys.push((0, ssz_1.fromHexString)(validator.distributed_public_key));
252
- builderRegistrationAndDepositDataMessages.push(depositDataMessage);
253
- blsSignatures.push((0, ssz_1.fromHexString)(validator.deposit_data.signature));
254
- }
255
- //Builder registration signature
256
- if (semver.gte(clusterLock.cluster_definition.version, 'v1.7.0')) {
257
- if (!verifyBuilderRegistration(validator, clusterLock.cluster_definition.validators[i].fee_recipient_address)) {
258
- return false;
259
- }
260
- const builderRegistrationMessageBuffer = computebuilderRegistrationMsgRoot(validator.builder_registration.message);
261
- const builderRegistrationMessage = (0, exports.signingRoot)(builderDomain, builderRegistrationMessageBuffer);
262
- pubKeys.push((0, ssz_1.fromHexString)(validator.distributed_public_key));
263
- builderRegistrationAndDepositDataMessages.push(builderRegistrationMessage);
264
- blsSignatures.push((0, ssz_1.fromHexString)(validator.builder_registration.signature));
265
- }
261
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.6.0')) {
262
+ return (0, v1_6_0_js_1.verifyDVV1X6)(clusterLock);
266
263
  }
267
- if (blsSignatures.length &&
268
- pubKeys.length &&
269
- builderRegistrationAndDepositDataMessages.length) {
270
- // verify all deposit data and builder registration bls signatures
271
- const aggregateBLSSignature = (0, bls_1.aggregateSignatures)(blsSignatures);
272
- if (!(0, bls_1.verifyMultiple)(pubKeys, builderRegistrationAndDepositDataMessages, aggregateBLSSignature)) {
273
- return false;
274
- }
264
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.7.0')) {
265
+ return (0, v1_7_0_js_1.verifyDVV1X7)(clusterLock);
275
266
  }
276
- if (semver.gte(clusterLock.cluster_definition.version, 'v1.7.0')) {
277
- const lockHashWithout0x = (0, utils_js_1.hexWithout0x)(clusterLock.lock_hash);
278
- //node(ENR) signatures
279
- for (let i = 0; i < nodeSignatures.length; i++) {
280
- const pubkey = discv5_1.ENR.decodeTxt(clusterLock.cluster_definition.operators[i].enr).publicKey.toString('hex');
281
- const ENRsignature = {
282
- r: nodeSignatures[i].slice(2, 66),
283
- s: nodeSignatures[i].slice(66, 130),
284
- };
285
- const nodeSignatureVerification = ec
286
- .keyFromPublic(pubkey, 'hex')
287
- .verify(lockHashWithout0x, ENRsignature);
288
- if (!nodeSignatureVerification) {
289
- return false;
290
- }
291
- }
267
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) {
268
+ return (0, v1_8_0_js_1.verifyDVV1X8)(clusterLock);
292
269
  }
293
- //signature aggregate
294
- if (!(0, bls_1.verifyAggregate)(pubShares, (0, ssz_1.fromHexString)(clusterLock.lock_hash), (0, ssz_1.fromHexString)(clusterLock.signature_aggregate))) {
295
- return false;
296
- }
297
- return true;
270
+ return false;
298
271
  });
299
272
  const isValidClusterLock = (clusterLock) => __awaiter(void 0, void 0, void 0, function* () {
300
273
  try {
301
- const definitionType = definitionFlow(clusterLock.cluster_definition);
302
- if (!definitionType) {
274
+ const definitionType = (0, utils_js_1.definitionFlow)(clusterLock.cluster_definition);
275
+ if (definitionType == null) {
303
276
  return false;
304
277
  }
305
278
  const isValidDefinitionData = verifyDefinitionSignatures(clusterLock.cluster_definition, definitionType);
306
279
  if (!isValidDefinitionData) {
307
280
  return false;
308
281
  }
309
- if ((0, hash_js_1.clusterConfigOrDefinitionHash)(clusterLock.cluster_definition, false) !==
282
+ if ((0, exports.clusterConfigOrDefinitionHash)(clusterLock.cluster_definition, false) !==
310
283
  clusterLock.cluster_definition.definition_hash) {
311
284
  return false;
312
285
  }
313
- if ((0, hash_js_1.clusterLockHash)(clusterLock) !== clusterLock.lock_hash) {
286
+ if ((0, exports.clusterLockHash)(clusterLock) !== clusterLock.lock_hash) {
314
287
  return false;
315
288
  }
316
289
  const isValidLockData = yield verifyLockData(clusterLock);
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.signingRootType = exports.depositMessageType = exports.forkDataType = exports.builderRegistrationMessageType = exports.builderRegistrationContainer = exports.builderRegistrationMessageContainer = exports.depositDataContainer = exports.newOperatorContainerType = exports.newCreatorContainerType = exports.validatorsContainerType = exports.creatorContainerType = exports.operatorContainerType = exports.creatorAddressWrapperType = exports.operatorAddressWrapperType = void 0;
4
+ const ssz_1 = require("@chainsafe/ssz");
5
+ exports.operatorAddressWrapperType = new ssz_1.ContainerType({
6
+ address: new ssz_1.ByteVectorType(20),
7
+ });
8
+ exports.creatorAddressWrapperType = new ssz_1.ContainerType({
9
+ address: new ssz_1.ByteVectorType(20),
10
+ });
11
+ exports.operatorContainerType = new ssz_1.ContainerType({
12
+ address: new ssz_1.ByteVectorType(20),
13
+ enr: new ssz_1.ByteListType(1024), // This needs to be dynamic, since ENRs do not have a fixed length.
14
+ config_signature: new ssz_1.ByteVectorType(65),
15
+ enr_signature: new ssz_1.ByteVectorType(65),
16
+ });
17
+ exports.creatorContainerType = new ssz_1.ContainerType({
18
+ address: new ssz_1.ByteVectorType(20),
19
+ config_signature: new ssz_1.ByteVectorType(65),
20
+ });
21
+ exports.validatorsContainerType = new ssz_1.ContainerType({
22
+ fee_recipient_address: new ssz_1.ByteVectorType(20),
23
+ withdrawal_address: new ssz_1.ByteVectorType(20),
24
+ });
25
+ const newCreatorContainerType = (configOnly) => {
26
+ return configOnly ? exports.creatorAddressWrapperType : exports.creatorContainerType;
27
+ };
28
+ exports.newCreatorContainerType = newCreatorContainerType;
29
+ const newOperatorContainerType = (configOnly) => {
30
+ return configOnly ? exports.operatorAddressWrapperType : exports.operatorContainerType;
31
+ };
32
+ exports.newOperatorContainerType = newOperatorContainerType;
33
+ // Lock
34
+ exports.depositDataContainer = new ssz_1.ContainerType({
35
+ pubkey: new ssz_1.ByteVectorType(48),
36
+ withdrawal_credentials: new ssz_1.ByteVectorType(32),
37
+ amount: new ssz_1.UintNumberType(8),
38
+ signature: new ssz_1.ByteVectorType(96),
39
+ });
40
+ exports.builderRegistrationMessageContainer = new ssz_1.ContainerType({
41
+ fee_recipient: new ssz_1.ByteVectorType(20),
42
+ gas_limit: new ssz_1.UintNumberType(8),
43
+ timestamp: new ssz_1.UintNumberType(8),
44
+ pubkey: new ssz_1.ByteVectorType(48),
45
+ });
46
+ exports.builderRegistrationContainer = new ssz_1.ContainerType({
47
+ message: exports.builderRegistrationMessageContainer,
48
+ signature: new ssz_1.ByteVectorType(96),
49
+ });
50
+ exports.builderRegistrationMessageType = new ssz_1.ContainerType({
51
+ fee_recipient: new ssz_1.ByteVectorType(20),
52
+ gas_limit: new ssz_1.UintNumberType(8),
53
+ timestamp: new ssz_1.UintNumberType(8),
54
+ pubkey: new ssz_1.ByteVectorType(48),
55
+ });
56
+ // For domain computation that is used in deposit data and builder registration verification for dv
57
+ exports.forkDataType = new ssz_1.ContainerType({
58
+ currentVersion: new ssz_1.ByteVectorType(4),
59
+ genesisValidatorsRoot: new ssz_1.ByteVectorType(32),
60
+ });
61
+ exports.depositMessageType = new ssz_1.ContainerType({
62
+ pubkey: new ssz_1.ByteVectorType(48),
63
+ withdrawal_credentials: new ssz_1.ByteVectorType(32),
64
+ amount: new ssz_1.UintNumberType(8),
65
+ });
66
+ exports.signingRootType = new ssz_1.ContainerType({
67
+ objectRoot: new ssz_1.ByteVectorType(32),
68
+ domain: new ssz_1.ByteVectorType(32),
69
+ });
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyDVV1X6 = exports.hashClusterLockV1X6 = exports.hashClusterDefinitionV1X6 = exports.clusterDefinitionContainerTypeV1X6 = void 0;
4
+ const uint_1 = require("@chainsafe/ssz/lib/type/uint");
5
+ const utils_1 = require("../utils");
6
+ const sszTypes_1 = require("./sszTypes");
7
+ const ssz_1 = require("@chainsafe/ssz");
8
+ const common_1 = require("./common");
9
+ const bls_1 = require("@chainsafe/bls");
10
+ /**
11
+ * Returns the containerized cluster definition
12
+ * @param cluster ClusterDefinition to calculate the type from
13
+ * @returns SSZ Containerized type of cluster input
14
+ */
15
+ const clusterDefinitionContainerTypeV1X6 = (configOnly) => {
16
+ let returnedContainerType = {
17
+ uuid: new ssz_1.ByteListType(64),
18
+ name: new ssz_1.ByteListType(256),
19
+ version: new ssz_1.ByteListType(16),
20
+ timestamp: new ssz_1.ByteListType(32),
21
+ num_validators: new uint_1.UintNumberType(8),
22
+ threshold: new uint_1.UintNumberType(8),
23
+ dkg_algorithm: new ssz_1.ByteListType(32),
24
+ fork_version: new ssz_1.ByteVectorType(4),
25
+ operators: new ssz_1.ListCompositeType((0, sszTypes_1.newOperatorContainerType)(configOnly), 256),
26
+ creator: (0, sszTypes_1.newCreatorContainerType)(configOnly),
27
+ validators: new ssz_1.ListCompositeType(sszTypes_1.validatorsContainerType, 65536),
28
+ };
29
+ if (!configOnly) {
30
+ returnedContainerType = Object.assign(Object.assign({}, returnedContainerType), { config_hash: new ssz_1.ByteVectorType(32) });
31
+ }
32
+ return new ssz_1.ContainerType(returnedContainerType);
33
+ };
34
+ exports.clusterDefinitionContainerTypeV1X6 = clusterDefinitionContainerTypeV1X6;
35
+ const hashClusterDefinitionV1X6 = (cluster, configOnly) => {
36
+ const definitionType = (0, exports.clusterDefinitionContainerTypeV1X6)(configOnly);
37
+ const val = definitionType.defaultValue();
38
+ // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276
39
+ val.uuid = (0, utils_1.strToUint8Array)(cluster.uuid);
40
+ val.name = (0, utils_1.strToUint8Array)(cluster.name);
41
+ val.version = (0, utils_1.strToUint8Array)(cluster.version);
42
+ val.timestamp = (0, utils_1.strToUint8Array)(cluster.timestamp);
43
+ val.num_validators = cluster.num_validators;
44
+ val.threshold = cluster.threshold;
45
+ val.dkg_algorithm = (0, utils_1.strToUint8Array)(cluster.dkg_algorithm);
46
+ val.fork_version = (0, ssz_1.fromHexString)(cluster.fork_version);
47
+ val.operators = cluster.operators.map(operator => {
48
+ return configOnly
49
+ ? { address: (0, ssz_1.fromHexString)(operator.address) }
50
+ : {
51
+ address: (0, ssz_1.fromHexString)(operator.address),
52
+ enr: (0, utils_1.strToUint8Array)(operator.enr),
53
+ config_signature: (0, ssz_1.fromHexString)(operator.config_signature),
54
+ enr_signature: (0, ssz_1.fromHexString)(operator.enr_signature),
55
+ };
56
+ });
57
+ val.creator = configOnly
58
+ ? { address: (0, ssz_1.fromHexString)(cluster.creator.address) }
59
+ : {
60
+ address: (0, ssz_1.fromHexString)(cluster.creator.address),
61
+ config_signature: (0, ssz_1.fromHexString)(cluster.creator.config_signature),
62
+ };
63
+ val.validators = cluster.validators.map((validator) => {
64
+ return {
65
+ fee_recipient_address: (0, ssz_1.fromHexString)(validator.fee_recipient_address),
66
+ withdrawal_address: (0, ssz_1.fromHexString)(validator.withdrawal_address),
67
+ };
68
+ });
69
+ if (!configOnly) {
70
+ val.config_hash = (0, ssz_1.fromHexString)(cluster.config_hash);
71
+ }
72
+ return val;
73
+ };
74
+ exports.hashClusterDefinitionV1X6 = hashClusterDefinitionV1X6;
75
+ // cluster lock
76
+ const dvContainerTypeV1X6 = new ssz_1.ContainerType({
77
+ distributed_public_key: new ssz_1.ByteVectorType(48),
78
+ public_shares: new ssz_1.ListCompositeType(new ssz_1.ByteVectorType(48), 256),
79
+ pubkey: new ssz_1.ByteVectorType(48),
80
+ withdrawal_credentials: new ssz_1.ByteVectorType(32),
81
+ amount: new uint_1.UintNumberType(8),
82
+ signature: new ssz_1.ByteVectorType(96),
83
+ });
84
+ /**
85
+ * @returns SSZ Containerized type of cluster lock
86
+ */
87
+ const clusterLockContainerTypeV1X6 = () => {
88
+ return new ssz_1.ContainerType({
89
+ cluster_definition: (0, exports.clusterDefinitionContainerTypeV1X6)(false),
90
+ distributed_validators: new ssz_1.ListCompositeType(dvContainerTypeV1X6, 65536),
91
+ });
92
+ };
93
+ /**
94
+ * @param cluster The published cluster lock
95
+ * @returns The lock hash in of the corresponding cluster
96
+ */
97
+ const hashClusterLockV1X6 = (cluster) => {
98
+ const lockType = clusterLockContainerTypeV1X6();
99
+ const val = lockType.defaultValue();
100
+ // Check if we can replace with definition_hash
101
+ val.cluster_definition = (0, exports.hashClusterDefinitionV1X6)(cluster.cluster_definition, false);
102
+ val.distributed_validators = cluster.distributed_validators.map(dValidator => {
103
+ var _a, _b, _c, _d;
104
+ return {
105
+ distributed_public_key: (0, ssz_1.fromHexString)(dValidator.distributed_public_key),
106
+ public_shares: dValidator.public_shares.map(publicShare => (0, ssz_1.fromHexString)(publicShare)),
107
+ pubkey: (0, ssz_1.fromHexString)((_a = dValidator.deposit_data) === null || _a === void 0 ? void 0 : _a.pubkey),
108
+ withdrawal_credentials: (0, ssz_1.fromHexString)((_b = dValidator.deposit_data) === null || _b === void 0 ? void 0 : _b.withdrawal_credentials),
109
+ amount: parseInt((_c = dValidator.deposit_data) === null || _c === void 0 ? void 0 : _c.amount),
110
+ signature: (0, ssz_1.fromHexString)((_d = dValidator.deposit_data) === null || _d === void 0 ? void 0 : _d.signature),
111
+ };
112
+ });
113
+ return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex');
114
+ };
115
+ exports.hashClusterLockV1X6 = hashClusterLockV1X6;
116
+ // DV verification
117
+ const verifyDVV1X6 = (clusterLock) => {
118
+ var _a;
119
+ const validators = clusterLock.distributed_validators;
120
+ const pubShares = [];
121
+ const pubKeys = [];
122
+ const builderRegistrationAndDepositDataMessages = [];
123
+ const blsSignatures = [];
124
+ for (let i = 0; i < validators.length; i++) {
125
+ const validator = validators[i];
126
+ const validatorPublicShares = validator.public_shares;
127
+ const distributedPublicKey = validator.distributed_public_key;
128
+ // Needed in signature_aggregate verification
129
+ for (const element of validatorPublicShares) {
130
+ pubShares.push((0, ssz_1.fromHexString)(element));
131
+ }
132
+ const { isValidDepositData, depositDataMsg } = (0, common_1.verifyDepositData)(distributedPublicKey, validator.deposit_data, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version);
133
+ if (!isValidDepositData) {
134
+ return false;
135
+ }
136
+ pubKeys.push((0, ssz_1.fromHexString)(validator.distributed_public_key));
137
+ builderRegistrationAndDepositDataMessages.push(depositDataMsg);
138
+ blsSignatures.push((0, ssz_1.fromHexString)((_a = validator.deposit_data) === null || _a === void 0 ? void 0 : _a.signature));
139
+ }
140
+ const aggregateBLSSignature = (0, bls_1.aggregateSignatures)(blsSignatures);
141
+ if (!(0, bls_1.verifyMultiple)(pubKeys, builderRegistrationAndDepositDataMessages, aggregateBLSSignature)) {
142
+ return false;
143
+ }
144
+ if (!(0, bls_1.verifyAggregate)(pubShares, (0, ssz_1.fromHexString)(clusterLock.lock_hash), (0, ssz_1.fromHexString)(clusterLock.signature_aggregate))) {
145
+ return false;
146
+ }
147
+ return true;
148
+ };
149
+ exports.verifyDVV1X6 = verifyDVV1X6;