@obolnetwork/obol-sdk 2.2.2 → 2.2.4

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "description": "A package for creating Distributed Validators using the Obol API.",
5
5
  "bugs": {
6
6
  "url": "https://github.com/obolnetwork/obol-sdk/issues"
@@ -37,6 +37,7 @@ const utils_js_1 = require("./utils.js");
37
37
  __exportStar(require("./types.js"), exports);
38
38
  __exportStar(require("./services.js"), exports);
39
39
  __exportStar(require("./verification/signature-validator.js"), exports);
40
+ __exportStar(require("./verification/common.js"), exports);
40
41
  /**
41
42
  * Obol sdk Client can be used for creating, managing and activating distributed validators.
42
43
  */
@@ -49,6 +49,7 @@ const utils_js_1 = require("../utils.js");
49
49
  const discv5_1 = require("@chainsafe/discv5");
50
50
  const v1_8_0_js_1 = require("./v1.8.0.js");
51
51
  const signature_validator_js_1 = require("./signature-validator.js");
52
+ const v1_10_0_js_1 = require("./v1.10.0.js");
52
53
  // cluster-definition hash
53
54
  /**
54
55
  * @param cluster The cluster configuration or the cluster definition
@@ -75,6 +76,13 @@ const clusterConfigOrDefinitionHash = (cluster, configOnly) => {
75
76
  return ('0x' +
76
77
  Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex'));
77
78
  }
79
+ if (semver.eq(cluster.version, 'v1.10.0')) {
80
+ definitionType = (0, v1_10_0_js_1.clusterDefinitionContainerTypeV1X10)(configOnly);
81
+ val = (0, v1_10_0_js_1.hashClusterDefinitionV1X10)(cluster, configOnly);
82
+ const x = '0x' +
83
+ Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex');
84
+ return x;
85
+ }
78
86
  throw new Error('unsupported version');
79
87
  };
80
88
  exports.clusterConfigOrDefinitionHash = clusterConfigOrDefinitionHash;
@@ -102,6 +110,21 @@ const clusterLockHash = (clusterLock) => {
102
110
  }
103
111
  return (0, v1_8_0_js_1.hashClusterLockV1X8)(clusterLock);
104
112
  }
113
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.10.0')) {
114
+ // if (
115
+ // clusterLock.cluster_definition.deposit_amounts === null &&
116
+ // clusterLock.distributed_validators.some(
117
+ // distributedValidator =>
118
+ // distributedValidator.partial_deposit_data?.length !== 1 ||
119
+ // distributedValidator.partial_deposit_data[0].amount !== '32000000000',
120
+ // )
121
+ // ) {
122
+ // throw new Error(
123
+ // 'mismatch between deposit_amounts and partial_deposit_data fields',
124
+ // );
125
+ // }
126
+ return (0, v1_10_0_js_1.hashClusterLockV1X10)(clusterLock);
127
+ }
105
128
  // other versions
106
129
  throw new Error('unsupported version');
107
130
  };
@@ -216,13 +239,13 @@ const computeDomain = (domainType, lockForkVersion, genesisValidatorsRoot = (0,
216
239
  * @param {string} withdrawalAddress - withdrawal address in definition file.
217
240
  * @returns {boolean} - return if deposit data is valid.
218
241
  */
219
- const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion) => {
242
+ const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion, compounding) => {
220
243
  const depositDomain = computeDomain((0, ssz_1.fromHexString)(constants_js_1.DOMAIN_DEPOSIT), forkVersion);
221
- const eth1AddressWithdrawalPrefix = '0x01';
222
- if (eth1AddressWithdrawalPrefix +
244
+ const withdrawalPrefix = compounding ? '0x02' : '0x01';
245
+ const expectedWithdrawalCredentials = withdrawalPrefix +
223
246
  '0'.repeat(22) +
224
- withdrawalAddress.toLowerCase().slice(2) !==
225
- depositData.withdrawal_credentials) {
247
+ withdrawalAddress.toLowerCase().slice(2);
248
+ if (expectedWithdrawalCredentials !== depositData.withdrawal_credentials) {
226
249
  return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) };
227
250
  }
228
251
  if (distributedPublicKey !== depositData.pubkey) {
@@ -294,6 +317,9 @@ const verifyLockData = (clusterLock) => __awaiter(void 0, void 0, void 0, functi
294
317
  if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) {
295
318
  return (0, v1_8_0_js_1.verifyDVV1X8)(clusterLock);
296
319
  }
320
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.10.0')) {
321
+ return (0, v1_10_0_js_1.verifyDVV1X10)(clusterLock);
322
+ }
297
323
  return false;
298
324
  });
299
325
  const isValidClusterLock = (clusterLock) => __awaiter(void 0, void 0, void 0, function* () {
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyDVV1X10 = exports.hashClusterLockV1X10 = exports.hashClusterDefinitionV1X10 = exports.clusterDefinitionContainerTypeV1X10 = 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 v1_8_0_1 = require("./v1.8.0");
9
+ /**
10
+ * Returns the containerized cluster definition
11
+ * @param cluster ClusterDefinition to calculate the type from
12
+ * @returns SSZ Containerized type of cluster input
13
+ */
14
+ const clusterDefinitionContainerTypeV1X10 = (configOnly) => {
15
+ let returnedContainerType = {
16
+ uuid: new ssz_1.ByteListType(64),
17
+ name: new ssz_1.ByteListType(256),
18
+ version: new ssz_1.ByteListType(16),
19
+ timestamp: new ssz_1.ByteListType(32),
20
+ num_validators: new uint_1.UintNumberType(8),
21
+ threshold: new uint_1.UintNumberType(8),
22
+ dkg_algorithm: new ssz_1.ByteListType(32),
23
+ fork_version: new ssz_1.ByteVectorType(4),
24
+ operators: new ssz_1.ListCompositeType((0, sszTypes_1.newOperatorContainerType)(configOnly), 256),
25
+ creator: (0, sszTypes_1.newCreatorContainerType)(configOnly),
26
+ validators: new ssz_1.ListCompositeType(sszTypes_1.validatorsContainerType, 65536),
27
+ deposit_amounts: new ssz_1.ListBasicType(new uint_1.UintNumberType(8), 256),
28
+ consensus_protocol: new ssz_1.ByteListType(256),
29
+ target_gas_limit: new uint_1.UintNumberType(8),
30
+ compounding: new ssz_1.BooleanType(),
31
+ };
32
+ if (!configOnly) {
33
+ returnedContainerType = Object.assign(Object.assign({}, returnedContainerType), { config_hash: new ssz_1.ByteVectorType(32) });
34
+ }
35
+ return new ssz_1.ContainerType(returnedContainerType);
36
+ };
37
+ exports.clusterDefinitionContainerTypeV1X10 = clusterDefinitionContainerTypeV1X10;
38
+ const hashClusterDefinitionV1X10 = (cluster, configOnly) => {
39
+ const definitionType = (0, exports.clusterDefinitionContainerTypeV1X10)(configOnly);
40
+ const val = definitionType.defaultValue();
41
+ // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276
42
+ val.uuid = (0, utils_1.strToUint8Array)(cluster.uuid);
43
+ val.name = (0, utils_1.strToUint8Array)(cluster.name);
44
+ val.version = (0, utils_1.strToUint8Array)(cluster.version);
45
+ val.timestamp = (0, utils_1.strToUint8Array)(cluster.timestamp);
46
+ val.num_validators = cluster.num_validators;
47
+ val.threshold = cluster.threshold;
48
+ val.dkg_algorithm = (0, utils_1.strToUint8Array)(cluster.dkg_algorithm);
49
+ val.fork_version = (0, ssz_1.fromHexString)(cluster.fork_version);
50
+ val.operators = cluster.operators.map(operator => {
51
+ return configOnly
52
+ ? { address: (0, ssz_1.fromHexString)(operator.address) }
53
+ : {
54
+ address: (0, ssz_1.fromHexString)(operator.address),
55
+ enr: (0, utils_1.strToUint8Array)(operator.enr),
56
+ config_signature: (0, ssz_1.fromHexString)(operator.config_signature),
57
+ enr_signature: (0, ssz_1.fromHexString)(operator.enr_signature),
58
+ };
59
+ });
60
+ val.creator = configOnly
61
+ ? { address: (0, ssz_1.fromHexString)(cluster.creator.address) }
62
+ : {
63
+ address: (0, ssz_1.fromHexString)(cluster.creator.address),
64
+ config_signature: (0, ssz_1.fromHexString)(cluster.creator.config_signature),
65
+ };
66
+ val.validators = cluster.validators.map(validator => {
67
+ return {
68
+ fee_recipient_address: (0, ssz_1.fromHexString)(validator.fee_recipient_address),
69
+ withdrawal_address: (0, ssz_1.fromHexString)(validator.withdrawal_address),
70
+ };
71
+ });
72
+ if (cluster.deposit_amounts) {
73
+ val.deposit_amounts = cluster.deposit_amounts.map((amount) => {
74
+ return parseInt(amount);
75
+ });
76
+ }
77
+ if (cluster.consensus_protocol) {
78
+ val.consensus_protocol = (0, utils_1.strToUint8Array)(cluster.consensus_protocol);
79
+ }
80
+ if (cluster.target_gas_limit) {
81
+ val.target_gas_limit = cluster.target_gas_limit;
82
+ }
83
+ if (cluster.compounding) {
84
+ val.compounding = cluster.compounding;
85
+ }
86
+ if (!configOnly) {
87
+ val.config_hash = (0, ssz_1.fromHexString)(cluster.config_hash);
88
+ }
89
+ return val;
90
+ };
91
+ exports.hashClusterDefinitionV1X10 = hashClusterDefinitionV1X10;
92
+ // cluster lock
93
+ const dvContainerTypeV1X10 = new ssz_1.ContainerType({
94
+ distributed_public_key: new ssz_1.ByteVectorType(48),
95
+ public_shares: new ssz_1.ListCompositeType(new ssz_1.ByteVectorType(48), 256),
96
+ partial_deposit_data: new ssz_1.ListCompositeType(sszTypes_1.depositDataContainer, 256),
97
+ builder_registration: sszTypes_1.builderRegistrationContainer,
98
+ });
99
+ /**
100
+ * @returns SSZ Containerized type of cluster lock
101
+ */
102
+ const clusterLockContainerTypeV1X10 = () => {
103
+ return new ssz_1.ContainerType({
104
+ cluster_definition: (0, exports.clusterDefinitionContainerTypeV1X10)(false),
105
+ distributed_validators: new ssz_1.ListCompositeType(dvContainerTypeV1X10, 65536),
106
+ });
107
+ };
108
+ /**
109
+ * @param cluster The published cluster lock
110
+ * @returns The lock hash in of the corresponding cluster
111
+ */
112
+ const hashClusterLockV1X10 = (cluster) => {
113
+ const lockType = clusterLockContainerTypeV1X10();
114
+ const val = lockType.defaultValue();
115
+ // Check if we can replace with definition_hash
116
+ val.cluster_definition = (0, exports.hashClusterDefinitionV1X10)(cluster.cluster_definition, false);
117
+ val.distributed_validators = cluster.distributed_validators.map(dValidator => {
118
+ var _a, _b, _c, _d, _e;
119
+ return {
120
+ distributed_public_key: (0, ssz_1.fromHexString)(dValidator.distributed_public_key),
121
+ public_shares: dValidator.public_shares.map(publicShare => (0, ssz_1.fromHexString)(publicShare)),
122
+ // should be fixed
123
+ partial_deposit_data: dValidator.partial_deposit_data.map(depositData => {
124
+ return {
125
+ pubkey: (0, ssz_1.fromHexString)(depositData.pubkey),
126
+ withdrawal_credentials: (0, ssz_1.fromHexString)(depositData.withdrawal_credentials),
127
+ amount: parseInt(depositData.amount),
128
+ signature: (0, ssz_1.fromHexString)(depositData.signature),
129
+ };
130
+ }),
131
+ builder_registration: {
132
+ message: {
133
+ fee_recipient: (0, ssz_1.fromHexString)((_a = dValidator.builder_registration) === null || _a === void 0 ? void 0 : _a.message.fee_recipient),
134
+ gas_limit: (_b = dValidator.builder_registration) === null || _b === void 0 ? void 0 : _b.message.gas_limit,
135
+ timestamp: (_c = dValidator.builder_registration) === null || _c === void 0 ? void 0 : _c.message.timestamp,
136
+ pubkey: (0, ssz_1.fromHexString)((_d = dValidator.builder_registration) === null || _d === void 0 ? void 0 : _d.message.pubkey),
137
+ },
138
+ signature: (0, ssz_1.fromHexString)((_e = dValidator.builder_registration) === null || _e === void 0 ? void 0 : _e.signature),
139
+ },
140
+ };
141
+ });
142
+ return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex');
143
+ };
144
+ exports.hashClusterLockV1X10 = hashClusterLockV1X10;
145
+ // DV verification
146
+ exports.verifyDVV1X10 = v1_8_0_1.verifyDVV1X8;
@@ -150,7 +150,7 @@ const verifyDVV1X8 = (clusterLock) => {
150
150
  // Deposit Data Verification
151
151
  for (const element of validator.partial_deposit_data) {
152
152
  const depositData = element;
153
- const { isValidDepositData, depositDataMsg } = (0, common_1.verifyDepositData)(distributedPublicKey, depositData, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version);
153
+ const { isValidDepositData, depositDataMsg } = (0, common_1.verifyDepositData)(distributedPublicKey, depositData, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version, clusterLock.cluster_definition.compounding);
154
154
  if (!isValidDepositData) {
155
155
  return false;
156
156
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.clusterLockWithSafe = exports.nullDepositAmountsClusterLockV1X8 = exports.clusterLockV1X8 = exports.clusterConfigV1X8 = exports.clusterLockV1X7 = exports.clusterConfigV1X7 = exports.clusterLockV1X6 = exports.enr = void 0;
3
+ exports.clusterLockWithCompoundingWithdrawals = exports.clusterLockV1X10 = exports.clusterLockWithSafe = exports.nullDepositAmountsClusterLockV1X8 = exports.clusterLockV1X8 = exports.clusterConfigV1X8 = exports.clusterLockV1X7 = exports.clusterConfigV1X7 = exports.clusterLockV1X6 = exports.enr = void 0;
4
4
  exports.enr = 'enr:-HW4QLlrtMjFLGkFT1bwdGbvZQlH8hLi0M2g44JAxEYP3BZmYpcsy9Q56HPPD87fMucjvLv4-obEFacpsg0ehRilbHeAgmlkgnY0iXNlY3AyNTZrMaEDRaa5o2aSgqyFq_ERZcQTztrOij1mFtXX1bJuVI6ieak';
5
5
  // v1.6.0
6
6
  exports.clusterLockV1X6 = {
@@ -510,3 +510,267 @@ exports.clusterLockWithSafe = {
510
510
  '0x4067921a5257efe4ceb103f2129faaa7a502781157b3b54e5efca559c558c2b43b89f30962e87df88fbf62250049a31888fcd62735d54b7553e5dc75c3b6ae0901',
511
511
  ],
512
512
  };
513
+ exports.clusterLockV1X10 = {
514
+ cluster_definition: {
515
+ name: 'test',
516
+ creator: {
517
+ address: '',
518
+ config_signature: '',
519
+ },
520
+ operators: [
521
+ {
522
+ address: '',
523
+ enr: 'enr:-HW4QCi1pQaw0sSi6DIY7cR4u7mRjcimz2-3XlTsOUcE_HZAMjlVi0h-KwdjJg8644Zwx6gAe78hV1acRvVUkm0p2auAgmlkgnY0iXNlY3AyNTZrMaEDscvrSedZsyX51TFM1U4641ruU8bkci9mjsz3YA7TZig',
524
+ config_signature: '',
525
+ enr_signature: '',
526
+ },
527
+ {
528
+ address: '',
529
+ enr: 'enr:-HW4QAKHz3KMrMlSFBoUlWNUTIb7_ZfHesv2axtp8wembBFISVA8oUMEeLJFrrQhaftWof73TwaBJvSGWuQY-0h6aNWAgmlkgnY0iXNlY3AyNTZrMaECwse5ClGbpdyD6NIKvIQACZEpJf7ueY2dqwTgQrQkC9I',
530
+ config_signature: '',
531
+ enr_signature: '',
532
+ },
533
+ {
534
+ address: '',
535
+ enr: 'enr:-HW4QIH7JGgINCHlrhJBTc9LMYsVSIH3Wj-NbXeFwWJBphviWbEK4Z17HlTTmHlKKPeTNwnY3sub4oJuveY4dhUWMgOAgmlkgnY0iXNlY3AyNTZrMaEDaC9-4JUFqpvm42dCHKjB2UdR5G_F4WGBu6B8_BrEdHw',
536
+ config_signature: '',
537
+ enr_signature: '',
538
+ },
539
+ {
540
+ address: '',
541
+ enr: 'enr:-HW4QEESZRcjsz_WYXH-i4GIlbs6QydDkfM5FYqoTxpKY4ctX2DbHGNL1R2c560wIyX2BvPQkRzFMao74d31KIeluBmAgmlkgnY0iXNlY3AyNTZrMaECjGDrMWJT1PnNizXTbUQI9kIi-1iMNCaaPmu2aRpP31A',
542
+ config_signature: '',
543
+ enr_signature: '',
544
+ },
545
+ ],
546
+ uuid: 'BB338EAD-08C1-BEAD-D9C6-8568D844D7AE',
547
+ version: 'v1.10.0',
548
+ timestamp: '2025-02-24T11:02:27+01:00',
549
+ num_validators: 2,
550
+ threshold: 3,
551
+ validators: [
552
+ {
553
+ fee_recipient_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
554
+ withdrawal_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
555
+ },
556
+ {
557
+ fee_recipient_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
558
+ withdrawal_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
559
+ },
560
+ ],
561
+ dkg_algorithm: 'default',
562
+ fork_version: '0x01017000',
563
+ deposit_amounts: null,
564
+ consensus_protocol: '',
565
+ target_gas_limit: 36000000,
566
+ compounding: false,
567
+ config_hash: '0xc10f8bf3fb5054c6f3bfde8ce88fe8b29ba2e74fab01ae70033bfc14dc7c6552',
568
+ definition_hash: '0xac37a1e1ab6df855060495c82d0b882315b9275b9ef76987a7834372101f8b00',
569
+ },
570
+ distributed_validators: [
571
+ {
572
+ distributed_public_key: '0xab8ca3ff2a9748d001e95f347c9754c78b218fe8e062b8dd60519d451b2776d9f55dc3150ff49ecc22c78c459f4618c5',
573
+ public_shares: [
574
+ '0x814e8a30c079eb63babb05e82eef3ebd2419019ddfb1e5ccf9d717fa22c6a2f2b8e1afb9b9c127cfd2186eed59b5ce85',
575
+ '0x8471aadd68d2eaf06013ad1965d58bee7bc51aa6fb13b6629097119100c4a13ec7cb2f79c84d56ef17f18494b0458b06',
576
+ '0xb6a92217b7827da24e6612480c0b333388e45ce9e106f8451447833f3b97905dd10b694662a68dae82919da9271ee511',
577
+ '0x8e1c34c8df8958b4be21c055f17257c47b7a1acca7c10becd4423e453ee230e27347355d63f98aa551b413a56522fce0',
578
+ ],
579
+ builder_registration: {
580
+ message: {
581
+ fee_recipient: '0x0d941218c10b055f0907fe1bbe486ccdaa7e332a',
582
+ gas_limit: 36000000,
583
+ timestamp: 1696000704,
584
+ pubkey: '0xab8ca3ff2a9748d001e95f347c9754c78b218fe8e062b8dd60519d451b2776d9f55dc3150ff49ecc22c78c459f4618c5',
585
+ },
586
+ signature: '0x827111972c310bb778e30e5abb71b99de6036901a951c4b31fed24464b005e0db4b748acc517487e7598106ec34d5eaf0b667433bec57c551c51832a463f852ff70a738596f4add097be8e2d254d4d38259b17bb48f0f463f23de05a22245803',
587
+ },
588
+ partial_deposit_data: [
589
+ {
590
+ pubkey: '0xab8ca3ff2a9748d001e95f347c9754c78b218fe8e062b8dd60519d451b2776d9f55dc3150ff49ecc22c78c459f4618c5',
591
+ withdrawal_credentials: '0x0100000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
592
+ amount: '1000000000',
593
+ signature: '0xb63799adec3016e9535845327c319e1a6b17fcf8841ef65de68cb427a91e8e82285c3b0bc45272ab5e898d5d906c3592048a7766f338883a71d5b4bdd697ad2b5d13269a7e7679b6ff5bc8fdabee2f86f1c4f21572e36790f0be784eb82d1c71',
594
+ },
595
+ {
596
+ pubkey: '0xab8ca3ff2a9748d001e95f347c9754c78b218fe8e062b8dd60519d451b2776d9f55dc3150ff49ecc22c78c459f4618c5',
597
+ withdrawal_credentials: '0x0100000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
598
+ amount: '32000000000',
599
+ signature: '0x802f962fa91c361149a60269afa42856ddf97ca507995a703904237458619bd42a9b926b2a0843a50ef9d2707dd4bf59140cec8aa26d301efc720b4f0a7ade32385c808af7afc1f22b5d0a2db0c0f39b29d7e031c8a6b8baea291764e4277354',
600
+ },
601
+ ],
602
+ },
603
+ {
604
+ distributed_public_key: '0x87d41d8acd0d6a334f3cf3ffff324b4513df67d655f5d7c6992ec09faecaad857e7f7ec02fb77809b50b7d27649dda7c',
605
+ public_shares: [
606
+ '0xb16475989aa084029a73179efc489b4f786ebbbdbc949af11041fdb55dd3680424283efc9aa679eea8d6dafccca0ebc7',
607
+ '0xab62feb0624d5c08441343b5b290d9a75d171375dbacc2f2a1d995f6ba3f8881bad14d38e540b229e096310dafce752f',
608
+ '0xa9dd8b82fb6244dbae9a903afdbd1a525772624a8799b358129c28a64355a1c0a5733b1cb094564bc33edcf28e53eacc',
609
+ '0xb47806d895fa3df69eb4155b7d22444d52bca4eb1c537272d3a477faa1982e662ec7aebd914e6d6ab6014a16b966a83a',
610
+ ],
611
+ builder_registration: {
612
+ message: {
613
+ fee_recipient: '0x0d941218c10b055f0907fe1bbe486ccdaa7e332a',
614
+ gas_limit: 36000000,
615
+ timestamp: 1696000704,
616
+ pubkey: '0x87d41d8acd0d6a334f3cf3ffff324b4513df67d655f5d7c6992ec09faecaad857e7f7ec02fb77809b50b7d27649dda7c',
617
+ },
618
+ signature: '0x93d8f818e0e12dcf688c58eba36943dacf575bf30b81a631a62dc5ea45a0f808e013aa3dfec1462bf6670b744900265d107a075f17c91e20fbe3f6f46f278536c823b864c00b78e6bae490a67bfab48edae2c7be47c598ca79e66dbbd316a52a',
619
+ },
620
+ partial_deposit_data: [
621
+ {
622
+ pubkey: '0x87d41d8acd0d6a334f3cf3ffff324b4513df67d655f5d7c6992ec09faecaad857e7f7ec02fb77809b50b7d27649dda7c',
623
+ withdrawal_credentials: '0x0100000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
624
+ amount: '1000000000',
625
+ signature: '0xa3330521d24e30b2b2b98cc64b4c8599ac59dab8f1498f39e71d6deade29671731a0fba68f3f25e04374f8e89531f6ed025b478c270f0e7bfed9a3d80a13656af859d7132a53467a080c0d2b166026fe48eafa95943eccde7fb509c1d218da2e',
626
+ },
627
+ {
628
+ pubkey: '0x87d41d8acd0d6a334f3cf3ffff324b4513df67d655f5d7c6992ec09faecaad857e7f7ec02fb77809b50b7d27649dda7c',
629
+ withdrawal_credentials: '0x0100000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
630
+ amount: '32000000000',
631
+ signature: '0xa1fb379892a13b791a2b6391b14e8bc0ba60f366e349b8de73f108ea997f1eee2d537053b37eb2aba325efee4eaf121512ba869e00e6612afce571ae2b10de0a16826514a33254209b4b8e51bc6f9d05faa2bba95b3ad16a0b14433674653296',
632
+ },
633
+ ],
634
+ },
635
+ ],
636
+ signature_aggregate: '0xa3547b36e4b0953a172815122678b0ce73e09fab7df7e6ce0ffa31924e0f7097e7686affb54816397e160de21b6d3139135e1073f51652e7db5276fce5c0efea2e20c77a7c85bb414c56320cd2adb68a83417e4b453cf04650fc747fa1b766f7',
637
+ lock_hash: '0xcd689de27f3e954b38e44faca15edaf9a484573df696f4363fbff19cdd84a7db',
638
+ node_signatures: [
639
+ '0x3c68ed8e1a13a154e04e8f8824c745ae7df8f408f282448fe514ded85ec12f281dbe50d1612f73737bccf163309f396c7f05971b55b6e3be81df2e17f27ce6b701',
640
+ '0x06d12eb7f6faaf68d0aad60cbd0e877319a6bf8e7bbdba10570de2dd7513938b1650bf267e2aa1d113416c3a21021e1ff63b3697ff199bb59757cafbbb8625ea01',
641
+ '0xaa6d244a1caa5e35f77c1f68c291e7f9714248c1aaf6deddbabdefcb184e14432431477352fa21a0a5f7992ae7392b454600f8cbb8a12bbab0512581f386d3d300',
642
+ '0x932e769d2294a2c7071970458e5f696443fed01c5cb84985cad3c86b2e4fbf67781bc1668a64421fd09228abcd86992a5aa1196a2874026f1a72d184e32f6e9c01',
643
+ ],
644
+ };
645
+ exports.clusterLockWithCompoundingWithdrawals = {
646
+ cluster_definition: {
647
+ name: 'test',
648
+ creator: {
649
+ address: '',
650
+ config_signature: '',
651
+ },
652
+ operators: [
653
+ {
654
+ address: '',
655
+ enr: 'enr:-HW4QNcZSicYpnE6PLTNao0kmv5FFTdR-iYh-SdeLlwromZ1DeY7drKAf1mrRoVM1AAVDkkqLxOZXPkDR85A-PdJg9CAgmlkgnY0iXNlY3AyNTZrMaECcdGTKboadTFffnKs9OxuqeZ4oEIUUJ-G1QXkKGHDkNk',
656
+ config_signature: '',
657
+ enr_signature: '',
658
+ },
659
+ {
660
+ address: '',
661
+ enr: 'enr:-HW4QDfvVp6bCS09-yA3NDJ91JdSbgh5wNTE82V1kv5EAebkKCFoXMEE_YY0qIS0_EEH54Hw-4Pc94enfwhpdOdpyAqAgmlkgnY0iXNlY3AyNTZrMaEDgOW8OThKXxluyWiWyLaP-1q_fsyDU0OhSBjO8MyEw3Y',
662
+ config_signature: '',
663
+ enr_signature: '',
664
+ },
665
+ {
666
+ address: '',
667
+ enr: 'enr:-HW4QGOen2twSnIzDuR834D7lPf3aGAw_CdTT9aebhfpKuvMKkIMlUOaYBYhMlaHke1JU_rNGZRr2ixaPpyTAbZRNDyAgmlkgnY0iXNlY3AyNTZrMaECkhQs3kw6C5geIyIAunFqLcyONz7-pWJA9dprq918YUw',
668
+ config_signature: '',
669
+ enr_signature: '',
670
+ },
671
+ {
672
+ address: '',
673
+ enr: 'enr:-HW4QLa2GPP1d34upL70ltxuiAEG_ayAHSwBbLpkFPLV2exoTRyUNBBFiNGe-kwqBvtuU2u2Zq8pUi2oeB3gHRbna7SAgmlkgnY0iXNlY3AyNTZrMaECow8eskA89PSk3pzMwA9BCyFYOrr6UxFGSfi6JQU5HkM',
674
+ config_signature: '',
675
+ enr_signature: '',
676
+ },
677
+ ],
678
+ uuid: '0CB6B203-39FF-3E52-898D-CC50D122694D',
679
+ version: 'v1.10.0',
680
+ timestamp: '2025-02-24T14:29:52+01:00',
681
+ num_validators: 2,
682
+ threshold: 3,
683
+ validators: [
684
+ {
685
+ fee_recipient_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
686
+ withdrawal_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
687
+ },
688
+ {
689
+ fee_recipient_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
690
+ withdrawal_address: '0x0D941218c10b055f0907FE1BbE486ccdAa7e332A',
691
+ },
692
+ ],
693
+ dkg_algorithm: 'default',
694
+ fork_version: '0x01017000',
695
+ deposit_amounts: null,
696
+ consensus_protocol: '',
697
+ target_gas_limit: 36000000,
698
+ compounding: true,
699
+ config_hash: '0x5f779ea58ebfe7b14181b05b281a6526c046eb42d2d03a06ac7d83e52e903ef2',
700
+ definition_hash: '0xd74c102137a44caed014b53edbd069fc5efef37226e0a7f2afbd4a529cec93df',
701
+ },
702
+ distributed_validators: [
703
+ {
704
+ distributed_public_key: '0x85e740354cef367a5216087cbb40a3bb061b6f11969b23e3c3d07828d924f577a39d74775be3a1a56b0d1e385631b160',
705
+ public_shares: [
706
+ '0x96b9d96c2bbc4ebd0650eedf4a4b1d9c4547b72f0585111b7930880795cbfdfc6d69fb02b105092058e830e1859927ba',
707
+ '0xa77071a78064201d4b1f8f3a7f3c71ccae40698385b6e4a344918d11f0523d5f62fc8fe1df0ac153cd5dc6cf9989cdce',
708
+ '0xa9119a315ea2c4729a4cf304f11fa079cb619e347b5150a3430d0bcaf7188510de81bfa4c953467cd6df077d56397726',
709
+ '0xadf3022df7f3f0e048a930bd2f89bf703191e159a20fd7eefa88f4af7487936d317fbd84f673d4f9803a321c20efb614',
710
+ ],
711
+ builder_registration: {
712
+ message: {
713
+ fee_recipient: '0x0d941218c10b055f0907fe1bbe486ccdaa7e332a',
714
+ gas_limit: 36000000,
715
+ timestamp: 1696000704,
716
+ pubkey: '0x85e740354cef367a5216087cbb40a3bb061b6f11969b23e3c3d07828d924f577a39d74775be3a1a56b0d1e385631b160',
717
+ },
718
+ signature: '0x8b81aaf5508ada3fe80d64bd262cb3e647ac8739f22f51cfcd9f2bbe1ea708f2e7a7429da6ae1dc05329becd6283ba6e18535ec254ba16854473683e8cb02cf602f7260ba4bd580079f9451a4ed673be3a40720d48468335a82b1706c595547e',
719
+ },
720
+ partial_deposit_data: [
721
+ {
722
+ pubkey: '0x85e740354cef367a5216087cbb40a3bb061b6f11969b23e3c3d07828d924f577a39d74775be3a1a56b0d1e385631b160',
723
+ withdrawal_credentials: '0x0200000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
724
+ amount: '1000000000',
725
+ signature: '0x805e452eeb66fb1e73fd66178713073bb1b1fe643b6036d0a68f475508dbc2d2b652758902f2daee73ff713c80e10b5808b8d4cf5c88c831ccffcdd4c5a4f866c82fc56b378211dfd291fe8e85213fb9c90e2d1fbbdea9997fdfa932b296d27c',
726
+ },
727
+ {
728
+ pubkey: '0x85e740354cef367a5216087cbb40a3bb061b6f11969b23e3c3d07828d924f577a39d74775be3a1a56b0d1e385631b160',
729
+ withdrawal_credentials: '0x0200000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
730
+ amount: '32000000000',
731
+ signature: '0xb19b91e7c2f11b6a86c252826000c7ef396619d54fe7772cea32c9cc4d2a10214da71b488262e3680e38de79b61aa37b075c1b7bfcf8ec62bb1d19867c434cb59e565c7c861f6412c3e525b7eab740446e1aa98a3d5a637842455b4f07eff6eb',
732
+ },
733
+ ],
734
+ },
735
+ {
736
+ distributed_public_key: '0xad9d4bee633c3107ce5c35cab6304137d5c43f1a0ce929c7f7983b51579cbc6a9b6813e05f5b74682a077c74ec6dd53d',
737
+ public_shares: [
738
+ '0xad574bb713e7b0aa2181b4ea2962834fe3a051e0ca8325b36f8615a99870f252aed701968cb010814dfe1b8c0450a269',
739
+ '0xa58556a322d1acf5ea553a3a0ba5184729589a564bd7bc787b81328b5cd033d421ee98386df623eb176acf98a3fa9bd1',
740
+ '0x95e732e087c43bd316e062d2bb2332efc34de59309d8b6da5ad747f4d842182af9539182a30ed314f8b7ae653d730d65',
741
+ '0xb6067ce37489114b24b59c4cf77fa0653e86bfb184c82935b14ec414c78ee75a43a583bd688ed04f0de2d1281608c87b',
742
+ ],
743
+ builder_registration: {
744
+ message: {
745
+ fee_recipient: '0x0d941218c10b055f0907fe1bbe486ccdaa7e332a',
746
+ gas_limit: 36000000,
747
+ timestamp: 1696000704,
748
+ pubkey: '0xad9d4bee633c3107ce5c35cab6304137d5c43f1a0ce929c7f7983b51579cbc6a9b6813e05f5b74682a077c74ec6dd53d',
749
+ },
750
+ signature: '0x8e2d2f19eb23a93d19fdfbe5e72763d20ea8dd558a01035c8145c3931d705cae6850185be62d6ccd6b94c3faa29914b902032f34483a5c55ba3653bf026193cc0c6076b0031b011fce78faa96234fd17ebe67b972e6f6233a7760cb17451d63d',
751
+ },
752
+ partial_deposit_data: [
753
+ {
754
+ pubkey: '0xad9d4bee633c3107ce5c35cab6304137d5c43f1a0ce929c7f7983b51579cbc6a9b6813e05f5b74682a077c74ec6dd53d',
755
+ withdrawal_credentials: '0x0200000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
756
+ amount: '1000000000',
757
+ signature: '0x90dbbc981e441292441ed2ec1aaed7c8e1d1afc976ea2c5051bb880f3368b75debfcb3fe6a96935838a693ea2ebfadea05c468ced6bc0f2f0b82f2e87a3febda10935691318548c32bbb059a005b6d8fb41b2552c4ede024f789b011377956c7',
758
+ },
759
+ {
760
+ pubkey: '0xad9d4bee633c3107ce5c35cab6304137d5c43f1a0ce929c7f7983b51579cbc6a9b6813e05f5b74682a077c74ec6dd53d',
761
+ withdrawal_credentials: '0x0200000000000000000000000d941218c10b055f0907fe1bbe486ccdaa7e332a',
762
+ amount: '32000000000',
763
+ signature: '0xafd1ade11b8b4c6da2a2b7136604c42c0edb1f37de81c5614adc8ce8da034a6a720ebe1970bf3467c12ffcbcb6fc8514149b6a04c3f13cc2e9d8c99096047af47543c1f3622c15e3400d6929386097b9af9fe5f5b372b0da60dab6edb269d216',
764
+ },
765
+ ],
766
+ },
767
+ ],
768
+ signature_aggregate: '0x8984f35f20e2f8733a5de37ed4d5405548b96f678b8c7a75a348bffbc6c9d795d56456f03e1ba4a207bcca5697a2490e129716fc0344452aa92472ad9fcbd6d7bb5de00eb9a2d41e3b76ab04026b68f3c50723b242da666d804e0b0e42958baf',
769
+ lock_hash: '0x5207f99c483863cb494332bb2c91e9f5260c00d6f49f27036426e5f83ff71b41',
770
+ node_signatures: [
771
+ '0x72eded28a88ef170df2a8b9361fe0ea1f991ba2444e336bd627e3c49179bd4bb7cf1dc7b27574cc08301fb16542135871ee3ea9662b4d177a528bf3df6e8959a00',
772
+ '0xee7051251d28f64fc9972326d0ce53e08a0b07f8959e97bdd2cd177c117bb12d3ced1ba8ac6c5b103b66703263ae17f5914e935eb3efa33ed7c7bf4ae98bab8400',
773
+ '0x57ebc828eb5a27a206f8dbbf6305fad50746c2bb3d882b2651d985661557fba434feba3a3fc5e7247bf3cf8521df6914621e81cb069909d68b5d3e6303f6115b00',
774
+ '0x3e2548c3c35df90bd7af34f9cc439e7ec4e4fa5619f74ca393bde8e05942dfde0c2e5d95249f478533fe11581b794e5de55446452e4dd1648c33b319a987461701',
775
+ ],
776
+ };
@@ -210,6 +210,11 @@ describe('Cluster Client without a signer', () => {
210
210
  version: 'Cluster with safe address v1.8.0',
211
211
  clusterLock: fixtures_js_1.clusterLockWithSafe,
212
212
  },
213
+ { version: 'v1.10.0', clusterLock: fixtures_js_1.clusterLockV1X10 },
214
+ {
215
+ version: 'v1.10.0 with compunding withdrawals',
216
+ clusterLock: fixtures_js_1.clusterLockWithCompoundingWithdrawals,
217
+ },
213
218
  ])("$version: 'should return true on verified cluster lock'", ({ clusterLock }) => __awaiter(void 0, void 0, void 0, function* () {
214
219
  const isValidLock = yield (0, index_1.validateClusterLock)(clusterLock);
215
220
  expect(isValidLock).toEqual(true);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "description": "A package for creating Distributed Validators using the Obol API.",
5
5
  "bugs": {
6
6
  "url": "https://github.com/obolnetwork/obol-sdk/issues"
@@ -20,6 +20,7 @@ import { isContractAvailable } from './utils.js';
20
20
  export * from './types.js';
21
21
  export * from './services.js';
22
22
  export * from './verification/signature-validator.js';
23
+ export * from './verification/common.js';
23
24
  /**
24
25
  * Obol sdk Client can be used for creating, managing and activating distributed validators.
25
26
  */
@@ -20,6 +20,7 @@ import { definitionFlow, hexWithout0x } from '../utils.js';
20
20
  import { ENR } from '@chainsafe/discv5';
21
21
  import { clusterDefinitionContainerTypeV1X8, hashClusterDefinitionV1X8, hashClusterLockV1X8, verifyDVV1X8, } from './v1.8.0.js';
22
22
  import { validateAddressSignature } from './signature-validator.js';
23
+ import { clusterDefinitionContainerTypeV1X10, hashClusterDefinitionV1X10, hashClusterLockV1X10, verifyDVV1X10, } from './v1.10.0.js';
23
24
  // cluster-definition hash
24
25
  /**
25
26
  * @param cluster The cluster configuration or the cluster definition
@@ -46,6 +47,13 @@ export const clusterConfigOrDefinitionHash = (cluster, configOnly) => {
46
47
  return ('0x' +
47
48
  Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex'));
48
49
  }
50
+ if (semver.eq(cluster.version, 'v1.10.0')) {
51
+ definitionType = clusterDefinitionContainerTypeV1X10(configOnly);
52
+ val = hashClusterDefinitionV1X10(cluster, configOnly);
53
+ const x = '0x' +
54
+ Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex');
55
+ return x;
56
+ }
49
57
  throw new Error('unsupported version');
50
58
  };
51
59
  // cluster-lock hash
@@ -72,6 +80,21 @@ export const clusterLockHash = (clusterLock) => {
72
80
  }
73
81
  return hashClusterLockV1X8(clusterLock);
74
82
  }
83
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.10.0')) {
84
+ // if (
85
+ // clusterLock.cluster_definition.deposit_amounts === null &&
86
+ // clusterLock.distributed_validators.some(
87
+ // distributedValidator =>
88
+ // distributedValidator.partial_deposit_data?.length !== 1 ||
89
+ // distributedValidator.partial_deposit_data[0].amount !== '32000000000',
90
+ // )
91
+ // ) {
92
+ // throw new Error(
93
+ // 'mismatch between deposit_amounts and partial_deposit_data fields',
94
+ // );
95
+ // }
96
+ return hashClusterLockV1X10(clusterLock);
97
+ }
75
98
  // other versions
76
99
  throw new Error('unsupported version');
77
100
  };
@@ -185,13 +208,13 @@ const computeDomain = (domainType, lockForkVersion, genesisValidatorsRoot = from
185
208
  * @param {string} withdrawalAddress - withdrawal address in definition file.
186
209
  * @returns {boolean} - return if deposit data is valid.
187
210
  */
188
- export const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion) => {
211
+ export const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion, compounding) => {
189
212
  const depositDomain = computeDomain(fromHexString(DOMAIN_DEPOSIT), forkVersion);
190
- const eth1AddressWithdrawalPrefix = '0x01';
191
- if (eth1AddressWithdrawalPrefix +
213
+ const withdrawalPrefix = compounding ? '0x02' : '0x01';
214
+ const expectedWithdrawalCredentials = withdrawalPrefix +
192
215
  '0'.repeat(22) +
193
- withdrawalAddress.toLowerCase().slice(2) !==
194
- depositData.withdrawal_credentials) {
216
+ withdrawalAddress.toLowerCase().slice(2);
217
+ if (expectedWithdrawalCredentials !== depositData.withdrawal_credentials) {
195
218
  return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) };
196
219
  }
197
220
  if (distributedPublicKey !== depositData.pubkey) {
@@ -259,6 +282,9 @@ const verifyLockData = (clusterLock) => __awaiter(void 0, void 0, void 0, functi
259
282
  if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) {
260
283
  return verifyDVV1X8(clusterLock);
261
284
  }
285
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.10.0')) {
286
+ return verifyDVV1X10(clusterLock);
287
+ }
262
288
  return false;
263
289
  });
264
290
  export const isValidClusterLock = (clusterLock) => __awaiter(void 0, void 0, void 0, function* () {