@obolnetwork/obol-sdk 1.0.9 → 1.0.12
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 +2 -1
- package/dist/cjs/src/ajv.js +17 -0
- package/dist/cjs/src/base.js +39 -0
- package/dist/cjs/src/constants.js +86 -0
- package/dist/cjs/src/errors.js +11 -0
- package/dist/cjs/src/hash.js +172 -0
- package/dist/cjs/src/index.js +158 -0
- package/dist/cjs/src/schema.js +72 -0
- package/dist/cjs/src/services.js +32 -0
- package/dist/cjs/src/types.js +18 -0
- package/dist/cjs/src/utils.js +11 -0
- package/dist/cjs/src/verify.js +326 -0
- package/dist/cjs/test/fixtures.js +101 -0
- package/dist/cjs/test/methods.test.js +128 -0
- package/dist/esm/src/ajv.js +10 -0
- package/dist/esm/src/base.js +35 -0
- package/dist/esm/src/constants.js +79 -0
- package/dist/esm/src/errors.js +7 -0
- package/dist/esm/src/hash.js +165 -0
- package/dist/esm/src/index.js +140 -0
- package/dist/esm/src/schema.js +69 -0
- package/dist/esm/src/services.js +28 -0
- package/dist/esm/src/types.js +15 -0
- package/dist/esm/src/utils.js +6 -0
- package/dist/esm/src/verify.js +295 -0
- package/dist/esm/test/fixtures.js +98 -0
- package/dist/esm/test/methods.test.js +126 -0
- package/dist/{ajv.d.ts → types/src/ajv.d.ts} +2 -3
- package/dist/{base.d.ts → types/src/base.d.ts} +13 -14
- package/dist/types/src/constants.d.ts +79 -0
- package/dist/{errors.d.ts → types/src/errors.d.ts} +4 -5
- package/dist/{hash.d.ts → types/src/hash.d.ts} +56 -64
- package/dist/{index.d.ts → types/src/index.d.ts} +64 -60
- package/dist/{schema.d.ts → types/src/schema.d.ts} +57 -58
- package/dist/types/src/services.d.ts +11 -0
- package/dist/{types.d.ts → types/src/types.d.ts} +153 -154
- package/dist/types/src/utils.d.ts +2 -0
- package/dist/types/src/verify.d.ts +4 -0
- package/dist/{fixtures.d.ts → types/test/fixtures.d.ts} +61 -62
- package/dist/types/test/methods.test.d.ts +1 -0
- package/package.json +55 -20
- package/src/ajv.ts +11 -0
- package/src/base.ts +44 -0
- package/src/constants.ts +118 -0
- package/src/errors.ts +11 -0
- package/src/hash.ts +250 -0
- package/src/index.ts +160 -0
- package/src/schema.ts +70 -0
- package/src/services.ts +20 -0
- package/src/types.ts +211 -0
- package/src/utils.ts +7 -0
- package/src/verify.ts +479 -0
- package/dist/ajv.d.ts.map +0 -1
- package/dist/base.d.ts.map +0 -1
- package/dist/cluster.test.d.ts +0 -2
- package/dist/cluster.test.d.ts.map +0 -1
- package/dist/constants.d.ts +0 -30
- package/dist/constants.d.ts.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/fixtures.d.ts.map +0 -1
- package/dist/hash.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.es.js +0 -15582
- package/dist/index.js +0 -15586
- package/dist/schema.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
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");
|
|
42
|
+
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
|
+
const elliptic_1 = __importDefault(require("elliptic"));
|
|
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;
|
|
81
|
+
}
|
|
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;
|
|
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;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
};
|
|
104
|
+
//cluster-definition signatures verificatin
|
|
105
|
+
const getPOSTConfigHashSigner = (signature, configHash, chainId) => {
|
|
106
|
+
try {
|
|
107
|
+
const sig = ethers_1.ethers.Signature.from(signature);
|
|
108
|
+
const data = (0, constants_js_1.signCreatorConfigHashPayload)({ creator_config_hash: configHash }, chainId);
|
|
109
|
+
const digest = eth_sig_util_1.TypedDataUtils.eip712Hash(data, eth_sig_util_1.SignTypedDataVersion.V4);
|
|
110
|
+
return ethers_1.ethers.recoverAddress(digest, sig).toLowerCase();
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const getPUTConfigHashSigner = (signature, configHash, chainId) => {
|
|
117
|
+
try {
|
|
118
|
+
const sig = ethers_1.ethers.Signature.from(signature);
|
|
119
|
+
const data = (0, constants_js_1.signOperatorConfigHashPayload)({ operator_config_hash: configHash }, chainId);
|
|
120
|
+
const digest = eth_sig_util_1.TypedDataUtils.eip712Hash(data, eth_sig_util_1.SignTypedDataVersion.V4);
|
|
121
|
+
return ethers_1.ethers.recoverAddress(digest, sig).toLowerCase();
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const getEnrSigner = (signature, payload, chainId) => {
|
|
128
|
+
try {
|
|
129
|
+
const sig = ethers_1.ethers.Signature.from(signature);
|
|
130
|
+
const data = (0, constants_js_1.signEnrPayload)({ enr: payload }, chainId);
|
|
131
|
+
const digest = eth_sig_util_1.TypedDataUtils.eip712Hash(data, eth_sig_util_1.SignTypedDataVersion.V4);
|
|
132
|
+
return ethers_1.ethers.recoverAddress(digest, sig).toLowerCase();
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
throw err;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const verifyDefinitionSignatures = (clusterDefinition, definitionType) => {
|
|
139
|
+
if (definitionType === 'Charon-Command') {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
const configSigner = getPOSTConfigHashSigner(clusterDefinition.creator.config_signature, clusterDefinition.config_hash, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
|
|
144
|
+
if (configSigner !== clusterDefinition.creator.address.toLowerCase()) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (definitionType === 'LP-Solo') {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return clusterDefinition.operators.every(operator => {
|
|
151
|
+
const configSigner = getPUTConfigHashSigner(operator.config_signature, clusterDefinition.config_hash, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
|
|
152
|
+
const enrSigner = getEnrSigner(operator.enr_signature, operator.enr, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
|
|
153
|
+
if (configSigner !== operator.address.toLowerCase() ||
|
|
154
|
+
enrSigner !== operator.address.toLowerCase()) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
//cluster-lock data verification
|
|
162
|
+
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);
|
|
167
|
+
};
|
|
168
|
+
const computeDepositMsgRoot = (msg) => {
|
|
169
|
+
const depositMsgVal = depositMessageType.defaultValue();
|
|
170
|
+
depositMsgVal.pubkey = (0, ssz_1.fromHexString)(msg.pubkey);
|
|
171
|
+
depositMsgVal.withdrawal_credentials = (0, ssz_1.fromHexString)(msg.withdrawal_credentials);
|
|
172
|
+
depositMsgVal.amount = parseInt(msg.amount);
|
|
173
|
+
return Buffer.from(depositMessageType.hashTreeRoot(depositMsgVal).buffer);
|
|
174
|
+
};
|
|
175
|
+
const computeForkDataRoot = (currentVersion, genesisValidatorsRoot) => {
|
|
176
|
+
const forkDataVal = forkDataType.defaultValue();
|
|
177
|
+
forkDataVal.currentVersion = currentVersion;
|
|
178
|
+
forkDataVal.genesisValidatorsRoot = genesisValidatorsRoot;
|
|
179
|
+
return Buffer.from(forkDataType.hashTreeRoot(forkDataVal).buffer);
|
|
180
|
+
};
|
|
181
|
+
const computebuilderRegistrationMsgRoot = (msg) => {
|
|
182
|
+
const builderRegistrationMsgVal = builderRegistrationMessageType.defaultValue();
|
|
183
|
+
builderRegistrationMsgVal.fee_recipient = (0, ssz_1.fromHexString)(msg.fee_recipient);
|
|
184
|
+
builderRegistrationMsgVal.gas_limit = msg.gas_limit;
|
|
185
|
+
builderRegistrationMsgVal.timestamp = msg.timestamp;
|
|
186
|
+
builderRegistrationMsgVal.pubkey = (0, ssz_1.fromHexString)(msg.pubkey);
|
|
187
|
+
return Buffer.from(builderRegistrationMessageType.hashTreeRoot(builderRegistrationMsgVal)
|
|
188
|
+
.buffer);
|
|
189
|
+
};
|
|
190
|
+
// DV data verification
|
|
191
|
+
const computeDomain = (domainType, lockForkVersion, genesisValidatorsRoot = (0, ssz_1.fromHexString)(constants_js_1.GENESIS_VALIDATOR_ROOT)) => {
|
|
192
|
+
const forkVersion = (0, ssz_1.fromHexString)(lockForkVersion.substring(2, lockForkVersion.length));
|
|
193
|
+
const forkDataRoot = computeForkDataRoot(forkVersion, genesisValidatorsRoot);
|
|
194
|
+
const domain = new Uint8Array(32);
|
|
195
|
+
domain.set(domainType);
|
|
196
|
+
domain.set(forkDataRoot.subarray(0, 28), 4);
|
|
197
|
+
return domain;
|
|
198
|
+
};
|
|
199
|
+
const verifyDepositData = (validator, withdrawalAddress) => {
|
|
200
|
+
const eth1AddressWithdrawalPrefix = '0x01';
|
|
201
|
+
if (eth1AddressWithdrawalPrefix +
|
|
202
|
+
'0'.repeat(22) +
|
|
203
|
+
withdrawalAddress.toLowerCase().slice(2) !==
|
|
204
|
+
validator.deposit_data.withdrawal_credentials) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
if (validator.distributed_public_key !== validator.deposit_data.pubkey) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
};
|
|
212
|
+
const verifyBuilderRegistration = (validator, feeRecipientAddress) => {
|
|
213
|
+
if (validator.distributed_public_key !==
|
|
214
|
+
validator.builder_registration.message.pubkey) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
if (feeRecipientAddress.toLowerCase() !==
|
|
218
|
+
validator.builder_registration.message.fee_recipient.toLowerCase()) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
return true;
|
|
222
|
+
};
|
|
223
|
+
const signingRoot = (domain, messageBuffer) => {
|
|
224
|
+
return computeSigningRoot(messageBuffer, domain);
|
|
225
|
+
};
|
|
226
|
+
exports.signingRoot = signingRoot;
|
|
227
|
+
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
|
+
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
|
+
}
|
|
266
|
+
}
|
|
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
|
+
}
|
|
275
|
+
}
|
|
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
|
+
}
|
|
292
|
+
}
|
|
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;
|
|
298
|
+
});
|
|
299
|
+
const isValidClusterLock = (clusterLock) => __awaiter(void 0, void 0, void 0, function* () {
|
|
300
|
+
try {
|
|
301
|
+
const definitionType = definitionFlow(clusterLock.cluster_definition);
|
|
302
|
+
if (!definitionType) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
const isValidDefinitionData = verifyDefinitionSignatures(clusterLock.cluster_definition, definitionType);
|
|
306
|
+
if (!isValidDefinitionData) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
if ((0, hash_js_1.clusterConfigOrDefinitionHash)(clusterLock.cluster_definition, false) !==
|
|
310
|
+
clusterLock.cluster_definition.definition_hash) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
if ((0, hash_js_1.clusterLockHash)(clusterLock) !== clusterLock.lock_hash) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
const isValidLockData = yield verifyLockData(clusterLock);
|
|
317
|
+
if (!isValidLockData) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
exports.isValidClusterLock = isValidClusterLock;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clusterConfig = exports.clusterLockV1X7 = void 0;
|
|
4
|
+
exports.clusterLockV1X7 = {
|
|
5
|
+
cluster_definition: {
|
|
6
|
+
name: "v1.7.0 group test",
|
|
7
|
+
creator: {
|
|
8
|
+
address: "0x86B8145c98e5BD25BA722645b15eD65f024a87EC",
|
|
9
|
+
config_signature: "0x269aefc773de5fbfe41001cbd160b62747a27d76a92c8a6a7eae19d0f172c4b44d445ee0992e1ba6e271740a59051bf9cd8fda4042572bde75e40e8d28f7e6561b"
|
|
10
|
+
},
|
|
11
|
+
operators: [
|
|
12
|
+
{
|
|
13
|
+
address: "0x86B8145c98e5BD25BA722645b15eD65f024a87EC",
|
|
14
|
+
enr: "enr:-Iu4QCdreXm-iHrd2Y-QgLAHeGAkQSrZNvfPL-l6IuGEuKoMHnZsg93EgIWWOtcBzKs_-skexEKvY3CmcJ8SOzMIGMiAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQL4r6dX8heIruf3OW_hfcctLtsaX8roj8E-8s0-IpH9rYN0Y3CCDhqDdWRwgg4u",
|
|
15
|
+
config_signature: "0x73bc8d23dee307a02791339300b6405573e686c22222d6e6c8fe349f52bb8c0620ea1ed476fe569ed8c8d21751893216b248eb28dd4de7aa263a234efe3129181b",
|
|
16
|
+
enr_signature: "0x1dc963f01eb794170e35a972ec8b487bdea2e3c1acbbe2fc2ab7936e7fe99e407583489a7dff3fbb08f4902e77867d795a7196a83d91b0a0eb8e50b8d96d35ba1c"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
address: "0xC35CfCd67b9C27345a54EDEcC1033F2284148c81",
|
|
20
|
+
enr: "enr:-Iu4QNbiUUUwT18LynBbVPJhNxvzQsaSpUr40mQTWscnZaqKb6vAlvV8j-eDDR3E0wjMQumGRbGm2IAb5_k4bVWJiVGAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPOiodUji0ohgJb5sNK1hgv8g6xO5_znZz3NkkBkyYyKIN0Y3CCDhqDdWRwgg4u",
|
|
21
|
+
config_signature: "0x0ab6f58c612cd0c6af395769132fccc5c0804fd40cc395ae7ab2069a7aedb2884f2fa07a91eee57e13c3407dbeeb81b2256312d14006bdb1c19d4206b66899a41c",
|
|
22
|
+
enr_signature: "0xb580f1380a62d299587357181561c8db8d67f4cc92d094b2ca3c84eddde3759567cfe60669b30ef55308a749c3c6a32f52148ac6b667cc6554f63a04c55350451b"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
address: "0x33807D6F1DCe44b9C599fFE03640762A6F08C496",
|
|
26
|
+
enr: "enr:-Iu4QJyserRukhG0Vgi2csu7GjpHYUGufNEbZ8Q7ZBrcZUb0KqpL5QzHonkh1xxHlxatTxrIcX_IS5J3SEWR_sa0ptGAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQMAUgEqczOjevyculnUIofhCj0DkgJudErM7qCYIvIkzIN0Y3CCDhqDdWRwgg4u",
|
|
27
|
+
config_signature: "0x6f4f030aedba854cc4fa626171038e0125a93b3c3017af932d5b2a159076d0e17c1641f28cb58c29039e2c33074dd729c3198253ea17cc38074274f5e13676441b",
|
|
28
|
+
enr_signature: "0xf63195e4238eac6d9deae5ec56626ac16a7a861294587c3ee144853ace76f8a2089980a2cbf17c72a8c5ac0651c6935d023db34fc0be58a91f0c70c26017597a1b"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
address: "0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f",
|
|
32
|
+
enr: "enr:-HW4QKJTwXC6Chw6zbnA3HFZi6Jo0DkIgjKy4eUBpsSOGnAeWE6ChEjEyk_6R6Qrm7jI-iqfs3_HYxiKde8vFgvHHrCAgmlkgnY0iXNlY3AyNTZrMaECfFKQH4spdZCHqrKVz1Q02xYla6J_RQECDNNYBRWdzv8",
|
|
33
|
+
config_signature: "0x8c09f7163c20cd0a2d28cb4fbfda22e93bc53bc537f6143407065922a25e40ab39f52b232ecb9241b3e1674f87a16d263181a17a80de55fb92b9659211428b581b",
|
|
34
|
+
enr_signature: "0x05d801705908933b7d1566f48f5726d36874423b1bbdd3f582e08c754220d211492b46ee434f1d1f5bd1507f80f9ca1df569354892e7d2eda87861bc2279be6e1c"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
uuid: "a1d642aa-07ed-4d48-9eda-0e70cb4bb03f",
|
|
38
|
+
version: "v1.7.0",
|
|
39
|
+
timestamp: "2023-07-18T10:36:04.505Z",
|
|
40
|
+
num_validators: 1,
|
|
41
|
+
threshold: 3,
|
|
42
|
+
validators: [
|
|
43
|
+
{
|
|
44
|
+
fee_recipient_address: "0x86B8145c98e5BD25BA722645b15eD65f024a87EC",
|
|
45
|
+
withdrawal_address: "0x86B8145c98e5BD25BA722645b15eD65f024a87EC"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
dkg_algorithm: "default",
|
|
49
|
+
fork_version: "0x00001020",
|
|
50
|
+
config_hash: "0x4c3e37cbdb2fb850150f6e112c4ea03cdc388bff059081182659b3407183b431",
|
|
51
|
+
definition_hash: "0xe7bf484f38a45c96e9a3fac60d3e39b88eeb9979fad983e06b0ec90e90aa20b3"
|
|
52
|
+
},
|
|
53
|
+
distributed_validators: [
|
|
54
|
+
{
|
|
55
|
+
distributed_public_key: "0xb61b17f3b6425eb2636bc6378de0ed8aab918c3346b59d297828e7c74643d51e80edc2b41290c568614cfb80d2b0be34",
|
|
56
|
+
public_shares: [
|
|
57
|
+
"0xab6c1448221f664c145a4a574302fd4419ccfe1178487b2fa4629ee9fc2999c43188c96a52ad795074124a7eb0f63841",
|
|
58
|
+
"0x8a2a265fbe9854b1532be335272717a5650e19ecc4d6ea54ed8d8d239200f5b860e5710f7a3b9f5d8a100782cbaf4ede",
|
|
59
|
+
"0xa8a0aaf1119afe1c2b21d7dbf18bbe107586dc49028d285886c2e7f2bcf3f1c6817fff1250f4a4a370229a0266ea9bff",
|
|
60
|
+
"0x93f62a042d304bbb316761712f5a39a9d549c71275e5d891afa3688b9224ebfa3bfd22f8b76f31d8ad88f65812b27dc3"
|
|
61
|
+
],
|
|
62
|
+
deposit_data: {
|
|
63
|
+
pubkey: "0xb61b17f3b6425eb2636bc6378de0ed8aab918c3346b59d297828e7c74643d51e80edc2b41290c568614cfb80d2b0be34",
|
|
64
|
+
withdrawal_credentials: "0x01000000000000000000000086b8145c98e5bd25ba722645b15ed65f024a87ec",
|
|
65
|
+
amount: "32000000000",
|
|
66
|
+
signature: "0xae016c6c42daa8d1517d0e10370cf7882b28149635f734c5f3d83f781cd61f5df6d5203ec11bd0ca9d9e51c6030b66330476a93a65de6151d110e0f6482591f53678d863e55392e9cfb55fecac537edac51979790bcde38250a141348f116d46",
|
|
67
|
+
deposit_data_root: 'fbada6c7c4cba867780eead34c1462339795fe9b417db466ce2f9d4822e8a4bb'
|
|
68
|
+
},
|
|
69
|
+
builder_registration: {
|
|
70
|
+
message: {
|
|
71
|
+
fee_recipient: "0x86B8145c98e5BD25BA722645b15eD65f024a87EC",
|
|
72
|
+
gas_limit: 30000000,
|
|
73
|
+
timestamp: 1616508000,
|
|
74
|
+
pubkey: "0xb61b17f3b6425eb2636bc6378de0ed8aab918c3346b59d297828e7c74643d51e80edc2b41290c568614cfb80d2b0be34"
|
|
75
|
+
},
|
|
76
|
+
signature: "0xb1de0eeb44c3b9d598d50c8d48a676e45dd63a5a3040caa34e34ab8c60d0b2f079419d8699c97e76b641326845c99ee309096de1878547e370d4b82e2e4e580650fee2e46dc7b9b3bd805b7fe6f95ba6a9e2734c3ddd23bf6b1f5597e9a3f834"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
signature_aggregate: "0x90c32196e4dda81b39faaaec283e3ec5620b7c25c1a35949d54eb53a7c1c5a3963614c0d147085d82f9c52f550556ba406c0c5c8a4cec3fec825e6663a8792a9205f1a36fdde3e8c810cfd8861963190dd9b9eadd9a803bd5765c0b93d146542",
|
|
81
|
+
lock_hash: "0xdb19ef9c0677713f55502448b7c63d58fb25c81d34a5a8ce07a19bcfb3a9c0a0",
|
|
82
|
+
node_signatures: [
|
|
83
|
+
"0xa5230ba0586b21d49e790bc99304dc2245f8222c17d456ef60b848e3b0c5541d61825b2f9c2bda87ba3952979f28f6ba2338026603de74f925d9603aa823d42f01",
|
|
84
|
+
"0xc22ac5dc3a6f98471f2f25d11fd48600f955f68cb940e9da6789ab8fc50ca1bf40c8fb3200132ad6b2c66be7e256979fe182f8f924506ad8ba2c827401038ec600",
|
|
85
|
+
"0xebd08c9ece21abd78cfe82bc32eae68ccd77fc1e96e56ce93679918c5adcb2c92564a4fa609d7649587fbfb0c581403da8553e9e62c910e5ae589625704aa02b00",
|
|
86
|
+
"0xa07fc8f89f32a5b2551cc2173b0486f86142ee2a67400d2d4a956a2b948da96b58adddf558db6ac84de62242b5e56b1a1e95d26451be3a922fe3929f2a367a7400"
|
|
87
|
+
]
|
|
88
|
+
};
|
|
89
|
+
exports.clusterConfig = {
|
|
90
|
+
name: "testSDK",
|
|
91
|
+
operators: [
|
|
92
|
+
{ address: "0xC35CfCd67b9C27345a54EDEcC1033F2284148c81" },
|
|
93
|
+
{ address: "0x33807D6F1DCe44b9C599fFE03640762A6F08C496" },
|
|
94
|
+
{ address: "0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f" },
|
|
95
|
+
{ address: "0x86B8145c98e5BD25BA722645b15eD65f024a87EC" }
|
|
96
|
+
],
|
|
97
|
+
validators: [{
|
|
98
|
+
fee_recipient_address: "0x3CD4958e76C317abcEA19faDd076348808424F99",
|
|
99
|
+
withdrawal_address: "0xE0C5ceA4D3869F156717C66E188Ae81C80914a6e"
|
|
100
|
+
}],
|
|
101
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const ethers_1 = require("ethers");
|
|
13
|
+
const index_1 = require("../src/index");
|
|
14
|
+
const fixtures_js_1 = require("./fixtures.js");
|
|
15
|
+
const constants_1 = require("../src/constants");
|
|
16
|
+
const base_1 = require("../src/base");
|
|
17
|
+
const ajv_1 = require("../src/ajv");
|
|
18
|
+
const msw_1 = require("msw");
|
|
19
|
+
const node_1 = require("msw/node");
|
|
20
|
+
describe('Cluster Client', () => {
|
|
21
|
+
var _a;
|
|
22
|
+
const mockConfigHash = "0x1f6c94e6c070393a68c1aa6073a21cb1fd57f0e14d2a475a2958990ab728c2fd";
|
|
23
|
+
const mnemonic = ((_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) || "";
|
|
24
|
+
const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
|
|
25
|
+
const wallet = new ethers_1.ethers.Wallet(privateKey);
|
|
26
|
+
const mockSigner = wallet.connect(null);
|
|
27
|
+
const clientInstance = new index_1.Client({ baseUrl: "https://obol-api-dev.gcp.obol.tech", chainId: 5 }, mockSigner);
|
|
28
|
+
test('throws invalid ChainId when it is equal to 1', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
|
+
try {
|
|
30
|
+
new index_1.Client({ chainId: 1 }, mockSigner);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
expect(error.message).toBe("Invalid ChainId");
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
test('createClusterDefinition should return config_hash', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
clientInstance['request'] = jest.fn().mockReturnValue(Promise.resolve({ config_hash: mockConfigHash }));
|
|
38
|
+
const config_hash = yield clientInstance.createClusterDefinition(fixtures_js_1.clusterConfig);
|
|
39
|
+
expect(config_hash).toEqual(mockConfigHash);
|
|
40
|
+
}));
|
|
41
|
+
test('acceptClusterDefinition should return cluster definition', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
clientInstance['request'] = jest.fn().mockReturnValue(Promise.resolve(fixtures_js_1.clusterLockV1X7.cluster_definition));
|
|
43
|
+
const clusterDefinition = yield clientInstance.acceptClusterDefinition({ enr: fixtures_js_1.clusterLockV1X7.cluster_definition.operators[0].enr, version: fixtures_js_1.clusterLockV1X7.cluster_definition.version }, fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
44
|
+
expect(clusterDefinition).toEqual(fixtures_js_1.clusterLockV1X7.cluster_definition);
|
|
45
|
+
}));
|
|
46
|
+
test('createClusterDefinition should throw an error on invalid operators', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
|
+
clientInstance['request'] = jest.fn().mockReturnValue(Promise.resolve({ config_hash: mockConfigHash }));
|
|
48
|
+
try {
|
|
49
|
+
yield clientInstance.createClusterDefinition(Object.assign(Object.assign({}, fixtures_js_1.clusterConfig), { operators: [] }));
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
expect(error.message).toEqual("Schema compilation errors', must NOT have fewer than 4 items");
|
|
53
|
+
}
|
|
54
|
+
}));
|
|
55
|
+
test('validatePayload should throw an error on empty schema', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
|
+
try {
|
|
57
|
+
(0, ajv_1.validatePayload)(Object.assign(Object.assign({}, fixtures_js_1.clusterConfig), { operators: [] }), "");
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
expect(error.message).toEqual("schema must be object or boolean");
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
test('getClusterdefinition should return cluster definition if config hash exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
|
+
clientInstance['request'] = jest.fn().mockReturnValue(Promise.resolve(fixtures_js_1.clusterLockV1X7.cluster_definition));
|
|
65
|
+
const clusterDefinition = yield clientInstance.getClusterDefinition(fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
66
|
+
expect(clusterDefinition.config_hash).toEqual(fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
67
|
+
}));
|
|
68
|
+
test('getClusterLock should return lockFile if exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
69
|
+
clientInstance['request'] = jest.fn().mockReturnValue(Promise.resolve(fixtures_js_1.clusterLockV1X7));
|
|
70
|
+
const clusterLock = yield clientInstance.getClusterLock(fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
71
|
+
expect(clusterLock.lock_hash).toEqual(fixtures_js_1.clusterLockV1X7.lock_hash);
|
|
72
|
+
}));
|
|
73
|
+
test('request method should set user agent header', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
+
const server = (0, node_1.setupServer)(msw_1.http.get('http://testexample.com/test', ({ request }) => {
|
|
75
|
+
// Check if the request contains specific headers
|
|
76
|
+
if (request.headers.get('User-Agent') === `Obol-SDK/${constants_1.SDK_VERSION}`) {
|
|
77
|
+
return msw_1.HttpResponse.json({ message: 'user-agent header exist' });
|
|
78
|
+
}
|
|
79
|
+
}));
|
|
80
|
+
server.listen();
|
|
81
|
+
class TestBase extends base_1.Base {
|
|
82
|
+
callProtectedRequest(endpoint, options) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
return (yield this.request(endpoint, options));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const testBaseInstance = new TestBase({ baseUrl: "http://testExample.com" });
|
|
89
|
+
const result = yield testBaseInstance.callProtectedRequest('/test', {
|
|
90
|
+
method: 'GET',
|
|
91
|
+
});
|
|
92
|
+
expect(result === null || result === void 0 ? void 0 : result.message).toEqual("user-agent header exist");
|
|
93
|
+
server.close();
|
|
94
|
+
}));
|
|
95
|
+
});
|
|
96
|
+
describe('Cluster Client without a signer', () => {
|
|
97
|
+
const clientInstance = new index_1.Client({ baseUrl: "https://obol-api-dev.gcp.obol.tech", chainId: 5 });
|
|
98
|
+
test('createClusterDefinition should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
try {
|
|
100
|
+
yield clientInstance.createClusterDefinition(fixtures_js_1.clusterConfig);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
expect(err).toEqual("Signer is required in createClusterDefinition");
|
|
104
|
+
}
|
|
105
|
+
}));
|
|
106
|
+
test('acceptClusterDefinition should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
107
|
+
try {
|
|
108
|
+
yield clientInstance.acceptClusterDefinition({ enr: fixtures_js_1.clusterLockV1X7.cluster_definition.operators[0].enr, version: fixtures_js_1.clusterLockV1X7.cluster_definition.version }, fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
expect(err).toEqual("Signer is required in acceptClusterDefinition");
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
test('getClusterdefinition should return cluster definition if config hash exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
115
|
+
clientInstance['request'] = jest.fn().mockReturnValue(Promise.resolve(fixtures_js_1.clusterLockV1X7.cluster_definition));
|
|
116
|
+
const clusterDefinition = yield clientInstance.getClusterDefinition(fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
117
|
+
expect(clusterDefinition.config_hash).toEqual(fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
118
|
+
}));
|
|
119
|
+
test('getClusterLock should return lockFile if exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
|
+
clientInstance['request'] = jest.fn().mockReturnValue(Promise.resolve(fixtures_js_1.clusterLockV1X7));
|
|
121
|
+
const clusterLock = yield clientInstance.getClusterLock(fixtures_js_1.clusterLockV1X7.cluster_definition.config_hash);
|
|
122
|
+
expect(clusterLock.lock_hash).toEqual(fixtures_js_1.clusterLockV1X7.lock_hash);
|
|
123
|
+
}));
|
|
124
|
+
it('should return true on verified the cluster lock', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
125
|
+
const isValidLock = yield (0, index_1.validateClusterLock)(fixtures_js_1.clusterLockV1X7);
|
|
126
|
+
expect(isValidLock).toEqual(true);
|
|
127
|
+
}));
|
|
128
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
export function validatePayload(data, schema) {
|
|
3
|
+
const ajv = new Ajv();
|
|
4
|
+
const validate = ajv.compile(schema);
|
|
5
|
+
const isValid = validate(data);
|
|
6
|
+
if (!isValid) {
|
|
7
|
+
throw new Error(`Schema compilation errors', ${validate.errors && validate.errors[0].message}`);
|
|
8
|
+
}
|
|
9
|
+
return isValid;
|
|
10
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
// src/resources/base.ts
|
|
11
|
+
import { DEFAULT_BASE_URL, DEFAULT_CHAIN_ID, SDK_VERSION } from './constants.js';
|
|
12
|
+
import { FORK_MAPPING } from './types.js';
|
|
13
|
+
export class Base {
|
|
14
|
+
constructor({ baseUrl = DEFAULT_BASE_URL, chainId = DEFAULT_CHAIN_ID }) {
|
|
15
|
+
this.baseUrl = baseUrl;
|
|
16
|
+
this.chainId = chainId;
|
|
17
|
+
this.fork_version = FORK_MAPPING[this.chainId];
|
|
18
|
+
}
|
|
19
|
+
request(endpoint, options) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
22
|
+
const config = Object.assign(Object.assign({}, options), { headers: Object.assign({ 'Content-Type': 'application/json', 'User-Agent': `Obol-SDK/${SDK_VERSION}` }, options === null || options === void 0 ? void 0 : options.headers) });
|
|
23
|
+
try {
|
|
24
|
+
const response = yield fetch(url, config);
|
|
25
|
+
if (response.ok) {
|
|
26
|
+
return (yield response.json());
|
|
27
|
+
}
|
|
28
|
+
throw new Error(response.statusText);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
throw e;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|