@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 +5 -0
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/index.js +1 -0
- package/dist/cjs/src/utils.js +1 -1
- package/dist/cjs/src/verification/common.js +32 -1
- package/dist/cjs/src/verification/v1.10.0.js +142 -0
- package/dist/cjs/test/fixtures.js +420 -1
- package/dist/cjs/test/methods.test.js +1 -0
- package/dist/esm/package.json +1 -1
- package/dist/esm/src/index.js +1 -0
- package/dist/esm/src/utils.js +1 -1
- package/dist/esm/src/verification/common.js +32 -1
- package/dist/esm/src/verification/v1.10.0.js +136 -0
- package/dist/esm/test/fixtures.js +419 -0
- package/dist/esm/test/methods.test.js +2 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/types.d.ts +4 -0
- package/dist/types/src/verification/v1.10.0.d.ts +37 -0
- package/dist/types/test/fixtures.d.ts +53 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/types.ts +6 -0
- package/src/utils.ts +1 -1
- package/src/verification/common.ts +41 -1
- package/src/verification/v1.10.0.ts +238 -0
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:
|
package/dist/cjs/package.json
CHANGED
package/dist/cjs/src/index.js
CHANGED
|
@@ -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
|
*/
|
package/dist/cjs/src/utils.js
CHANGED
|
@@ -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;
|