@obolnetwork/obol-sdk 2.2.1 → 2.2.3

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.
package/README.md CHANGED
@@ -17,6 +17,11 @@ If you're integrating this SDK with a **backend** (e.g., in Node.js), and you st
17
17
  - The private key is securely stored (e.g., in an `.env` file).
18
18
  - Never commit or push your `.env` file containing the private key to version control.
19
19
 
20
+ ## ⚡️ Integration with Safe Wallet
21
+
22
+ When integrating the Obol SDK with a **Safe Wallet**, you will need to provide the `RPC_MAINNET` or `RPC_HOLESKY` or `RPC_GNOSIS` or `RPC_SEPOLIA` environment variable, pointing to the correct network's RPC URL. This is required to interact with Safe kit.
23
+
24
+
20
25
  ## Contributing
21
26
 
22
27
  Please review the following guidelines:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
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
  */
@@ -69,7 +69,7 @@ const isContractAvailable = (contractAddress, provider, bytecode) => __awaiter(v
69
69
  exports.isContractAvailable = isContractAvailable;
70
70
  const getProvider = (chainId) => {
71
71
  const rpcUrl = constants_1.PROVIDER_MAP[chainId];
72
- if (!rpcUrl) {
72
+ if (!rpcUrl || rpcUrl === 'undefined') {
73
73
  throw new Error(`No provider configured for ${types_1.FORK_NAMES[chainId]}`);
74
74
  }
75
75
  return new ethers_1.ethers.JsonRpcProvider(rpcUrl);
@@ -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
  };
@@ -219,10 +242,15 @@ const computeDomain = (domainType, lockForkVersion, genesisValidatorsRoot = (0,
219
242
  const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion) => {
220
243
  const depositDomain = computeDomain((0, ssz_1.fromHexString)(constants_js_1.DOMAIN_DEPOSIT), forkVersion);
221
244
  const eth1AddressWithdrawalPrefix = '0x01';
245
+ const compoundingWithdrawalPrefix = '0x02';
222
246
  if (eth1AddressWithdrawalPrefix +
223
247
  '0'.repeat(22) +
224
248
  withdrawalAddress.toLowerCase().slice(2) !==
225
- depositData.withdrawal_credentials) {
249
+ depositData.withdrawal_credentials &&
250
+ compoundingWithdrawalPrefix +
251
+ '0'.repeat(22) +
252
+ withdrawalAddress.toLowerCase().slice(2) !==
253
+ depositData.withdrawal_credentials) {
226
254
  return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) };
227
255
  }
228
256
  if (distributedPublicKey !== depositData.pubkey) {
@@ -294,6 +322,9 @@ const verifyLockData = (clusterLock) => __awaiter(void 0, void 0, void 0, functi
294
322
  if (semver.eq(clusterLock.cluster_definition.version, 'v1.8.0')) {
295
323
  return (0, v1_8_0_js_1.verifyDVV1X8)(clusterLock);
296
324
  }
325
+ if (semver.eq(clusterLock.cluster_definition.version, 'v1.10.0')) {
326
+ return (0, v1_10_0_js_1.verifyDVV1X10)(clusterLock);
327
+ }
297
328
  return false;
298
329
  });
299
330
  const isValidClusterLock = (clusterLock) => __awaiter(void 0, void 0, void 0, function* () {
@@ -0,0 +1,142 @@
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
+ };
31
+ if (!configOnly) {
32
+ returnedContainerType = Object.assign(Object.assign({}, returnedContainerType), { config_hash: new ssz_1.ByteVectorType(32) });
33
+ }
34
+ return new ssz_1.ContainerType(returnedContainerType);
35
+ };
36
+ exports.clusterDefinitionContainerTypeV1X10 = clusterDefinitionContainerTypeV1X10;
37
+ const hashClusterDefinitionV1X10 = (cluster, configOnly) => {
38
+ const definitionType = (0, exports.clusterDefinitionContainerTypeV1X10)(configOnly);
39
+ const val = definitionType.defaultValue();
40
+ // order should be same as charon https://github.com/ObolNetwork/charon/blob/main/cluster/ssz.go#L276
41
+ val.uuid = (0, utils_1.strToUint8Array)(cluster.uuid);
42
+ val.name = (0, utils_1.strToUint8Array)(cluster.name);
43
+ val.version = (0, utils_1.strToUint8Array)(cluster.version);
44
+ val.timestamp = (0, utils_1.strToUint8Array)(cluster.timestamp);
45
+ val.num_validators = cluster.num_validators;
46
+ val.threshold = cluster.threshold;
47
+ val.dkg_algorithm = (0, utils_1.strToUint8Array)(cluster.dkg_algorithm);
48
+ val.fork_version = (0, ssz_1.fromHexString)(cluster.fork_version);
49
+ val.operators = cluster.operators.map(operator => {
50
+ return configOnly
51
+ ? { address: (0, ssz_1.fromHexString)(operator.address) }
52
+ : {
53
+ address: (0, ssz_1.fromHexString)(operator.address),
54
+ enr: (0, utils_1.strToUint8Array)(operator.enr),
55
+ config_signature: (0, ssz_1.fromHexString)(operator.config_signature),
56
+ enr_signature: (0, ssz_1.fromHexString)(operator.enr_signature),
57
+ };
58
+ });
59
+ val.creator = configOnly
60
+ ? { address: (0, ssz_1.fromHexString)(cluster.creator.address) }
61
+ : {
62
+ address: (0, ssz_1.fromHexString)(cluster.creator.address),
63
+ config_signature: (0, ssz_1.fromHexString)(cluster.creator.config_signature),
64
+ };
65
+ val.validators = cluster.validators.map(validator => {
66
+ return {
67
+ fee_recipient_address: (0, ssz_1.fromHexString)(validator.fee_recipient_address),
68
+ withdrawal_address: (0, ssz_1.fromHexString)(validator.withdrawal_address),
69
+ };
70
+ });
71
+ if (cluster.deposit_amounts) {
72
+ val.deposit_amounts = cluster.deposit_amounts.map((amount) => {
73
+ return parseInt(amount);
74
+ });
75
+ }
76
+ if (cluster.consensus_protocol) {
77
+ val.consensus_protocol = (0, utils_1.strToUint8Array)(cluster.consensus_protocol);
78
+ }
79
+ if (cluster.target_gas_limit) {
80
+ val.target_gas_limit = cluster.target_gas_limit;
81
+ }
82
+ if (!configOnly) {
83
+ val.config_hash = (0, ssz_1.fromHexString)(cluster.config_hash);
84
+ }
85
+ return val;
86
+ };
87
+ exports.hashClusterDefinitionV1X10 = hashClusterDefinitionV1X10;
88
+ // cluster lock
89
+ const dvContainerTypeV1X10 = new ssz_1.ContainerType({
90
+ distributed_public_key: new ssz_1.ByteVectorType(48),
91
+ public_shares: new ssz_1.ListCompositeType(new ssz_1.ByteVectorType(48), 256),
92
+ partial_deposit_data: new ssz_1.ListCompositeType(sszTypes_1.depositDataContainer, 256),
93
+ builder_registration: sszTypes_1.builderRegistrationContainer,
94
+ });
95
+ /**
96
+ * @returns SSZ Containerized type of cluster lock
97
+ */
98
+ const clusterLockContainerTypeV1X10 = () => {
99
+ return new ssz_1.ContainerType({
100
+ cluster_definition: (0, exports.clusterDefinitionContainerTypeV1X10)(false),
101
+ distributed_validators: new ssz_1.ListCompositeType(dvContainerTypeV1X10, 65536),
102
+ });
103
+ };
104
+ /**
105
+ * @param cluster The published cluster lock
106
+ * @returns The lock hash in of the corresponding cluster
107
+ */
108
+ const hashClusterLockV1X10 = (cluster) => {
109
+ const lockType = clusterLockContainerTypeV1X10();
110
+ const val = lockType.defaultValue();
111
+ // Check if we can replace with definition_hash
112
+ val.cluster_definition = (0, exports.hashClusterDefinitionV1X10)(cluster.cluster_definition, false);
113
+ val.distributed_validators = cluster.distributed_validators.map(dValidator => {
114
+ var _a, _b, _c, _d, _e;
115
+ return {
116
+ distributed_public_key: (0, ssz_1.fromHexString)(dValidator.distributed_public_key),
117
+ public_shares: dValidator.public_shares.map(publicShare => (0, ssz_1.fromHexString)(publicShare)),
118
+ // should be fixed
119
+ partial_deposit_data: dValidator.partial_deposit_data.map(depositData => {
120
+ return {
121
+ pubkey: (0, ssz_1.fromHexString)(depositData.pubkey),
122
+ withdrawal_credentials: (0, ssz_1.fromHexString)(depositData.withdrawal_credentials),
123
+ amount: parseInt(depositData.amount),
124
+ signature: (0, ssz_1.fromHexString)(depositData.signature),
125
+ };
126
+ }),
127
+ builder_registration: {
128
+ message: {
129
+ fee_recipient: (0, ssz_1.fromHexString)((_a = dValidator.builder_registration) === null || _a === void 0 ? void 0 : _a.message.fee_recipient),
130
+ gas_limit: (_b = dValidator.builder_registration) === null || _b === void 0 ? void 0 : _b.message.gas_limit,
131
+ timestamp: (_c = dValidator.builder_registration) === null || _c === void 0 ? void 0 : _c.message.timestamp,
132
+ pubkey: (0, ssz_1.fromHexString)((_d = dValidator.builder_registration) === null || _d === void 0 ? void 0 : _d.message.pubkey),
133
+ },
134
+ signature: (0, ssz_1.fromHexString)((_e = dValidator.builder_registration) === null || _e === void 0 ? void 0 : _e.signature),
135
+ },
136
+ };
137
+ });
138
+ return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex');
139
+ };
140
+ exports.hashClusterLockV1X10 = hashClusterLockV1X10;
141
+ // DV verification
142
+ exports.verifyDVV1X10 = v1_8_0_1.verifyDVV1X8;