@obolnetwork/obol-sdk 2.2.3 → 2.3.0

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.
@@ -31,6 +31,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
31
31
  step((generator = generator.apply(thisArg, _arguments || [])).next());
32
32
  });
33
33
  };
34
+ var _a, _b;
34
35
  Object.defineProperty(exports, "__esModule", { value: true });
35
36
  const ethers_1 = require("ethers");
36
37
  const index_1 = require("../src/index");
@@ -44,15 +45,14 @@ const termsAndConditions_1 = require("../src/verification/termsAndConditions");
44
45
  const utils = __importStar(require("../src/utils"));
45
46
  const splitsHelpers = __importStar(require("../src/splitHelpers"));
46
47
  jest.setTimeout(20000);
48
+ const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
49
+ const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
50
+ const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
51
+ const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
52
+ const mockSigner = wallet.connect(provider);
47
53
  /* eslint no-new: 0 */
48
54
  describe('Cluster Client', () => {
49
- var _a, _b;
50
55
  const mockConfigHash = '0x1f6c94e6c070393a68c1aa6073a21cb1fd57f0e14d2a475a2958990ab728c2fd';
51
- const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
52
- const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
53
- const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
54
- const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
55
- const mockSigner = wallet.connect(provider);
56
56
  const clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
57
57
  test('createTermsAndConditions should return "successful authorization"', () => __awaiter(void 0, void 0, void 0, function* () {
58
58
  clientInstance['request'] = jest
@@ -117,12 +117,12 @@ describe('Cluster Client', () => {
117
117
  }
118
118
  }));
119
119
  test('getClusterdefinition should return cluster definition if config hash exist', () => __awaiter(void 0, void 0, void 0, function* () {
120
- var _c;
120
+ var _a;
121
121
  clientInstance['request'] = jest
122
122
  .fn()
123
123
  .mockReturnValue(Promise.resolve(fixtures_js_1.clusterLockV1X8.cluster_definition));
124
124
  const clusterDefinition = yield clientInstance.getClusterDefinition(fixtures_js_1.clusterLockV1X8.cluster_definition.config_hash);
125
- expect((_c = clusterDefinition.deposit_amounts) === null || _c === void 0 ? void 0 : _c.length).toEqual(fixtures_js_1.clusterLockV1X8.cluster_definition.deposit_amounts.length);
125
+ expect((_a = clusterDefinition.deposit_amounts) === null || _a === void 0 ? void 0 : _a.length).toEqual(fixtures_js_1.clusterLockV1X8.cluster_definition.deposit_amounts.length);
126
126
  expect(clusterDefinition.config_hash).toEqual(fixtures_js_1.clusterLockV1X8.cluster_definition.config_hash);
127
127
  }));
128
128
  test('getClusterLock should return lockFile if exist', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -211,6 +211,10 @@ describe('Cluster Client without a signer', () => {
211
211
  clusterLock: fixtures_js_1.clusterLockWithSafe,
212
212
  },
213
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
+ },
214
218
  ])("$version: 'should return true on verified cluster lock'", ({ clusterLock }) => __awaiter(void 0, void 0, void 0, function* () {
215
219
  const isValidLock = yield (0, index_1.validateClusterLock)(clusterLock);
216
220
  expect(isValidLock).toEqual(true);
@@ -229,9 +233,8 @@ describe('Cluster Client without a signer', () => {
229
233
  }));
230
234
  });
231
235
  describe('createObolRewardsSplit', () => {
232
- let clientInstance, clientInstanceWithourSigner, mockSplitRecipients, mockPrincipalRecipient, mockEtherAmount, mockSigner;
236
+ let clientInstance, clientInstanceWithourSigner, mockSplitRecipients, mockPrincipalRecipient, mockEtherAmount;
233
237
  beforeAll(() => {
234
- var _a, _b;
235
238
  jest
236
239
  .spyOn(utils, 'isContractAvailable')
237
240
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
@@ -244,11 +247,6 @@ describe('createObolRewardsSplit', () => {
244
247
  fee_recipient_address: '0xFeeRecipientAddress',
245
248
  });
246
249
  }));
247
- const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
248
- const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
249
- const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
250
- const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
251
- mockSigner = wallet.connect(provider);
252
250
  clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
253
251
  clientInstanceWithourSigner = new index_1.Client({
254
252
  baseUrl: 'https://obol-api-dev.gcp.obol.tech',
@@ -326,9 +324,8 @@ describe('createObolRewardsSplit', () => {
326
324
  }));
327
325
  });
328
326
  describe('createObolTotalSplit', () => {
329
- let clientInstanceWithourSigner, mockSplitRecipients, mockSigner, clientInstance;
327
+ let clientInstanceWithourSigner, mockSplitRecipients, clientInstance;
330
328
  beforeAll(() => {
331
- var _a, _b;
332
329
  jest
333
330
  .spyOn(utils, 'isContractAvailable')
334
331
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
@@ -338,11 +335,6 @@ describe('createObolTotalSplit', () => {
338
335
  jest
339
336
  .spyOn(splitsHelpers, 'deploySplitterContract')
340
337
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xSplitterAddress'); }));
341
- const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
342
- const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
343
- const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
344
- const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
345
- mockSigner = wallet.connect(provider);
346
338
  clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
347
339
  clientInstanceWithourSigner = new index_1.Client({
348
340
  baseUrl: 'https://obol-api-dev.gcp.obol.tech',
@@ -419,3 +411,47 @@ describe('createObolTotalSplit', () => {
419
411
  });
420
412
  }));
421
413
  });
414
+ describe('getIncentivesByAddress', () => {
415
+ let clientInstance;
416
+ beforeAll(() => {
417
+ jest
418
+ .spyOn(utils, 'isContractAvailable')
419
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
420
+ jest
421
+ .spyOn(splitsHelpers, 'predictSplitterAddress')
422
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xPredictedAddress'); }));
423
+ jest
424
+ .spyOn(splitsHelpers, 'deploySplitterContract')
425
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xSplitterAddress'); }));
426
+ clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
427
+ });
428
+ test('should return incentives for a valid address', () => __awaiter(void 0, void 0, void 0, function* () {
429
+ const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
430
+ const mockIncentives = {
431
+ operator_address: '0x8c00157cae72c4ed6a1f8bfb60205601f0252e26',
432
+ amount: '100',
433
+ index: 1,
434
+ merkle_proof: ['hash1', 'hash2'],
435
+ contract_address: '0xContract',
436
+ };
437
+ clientInstance['request'] = jest
438
+ .fn()
439
+ .mockReturnValue(Promise.resolve(mockIncentives));
440
+ const incentives = yield clientInstance.getIncentivesByAddress(mockAddress);
441
+ expect(incentives).toEqual(mockIncentives);
442
+ }));
443
+ test('should throw an error if address is not found', () => __awaiter(void 0, void 0, void 0, function* () {
444
+ const invalidAddress = '0x0000000000000000000000000000000000000000';
445
+ clientInstance['request'] = jest
446
+ .fn()
447
+ .mockRejectedValue(new Error('Not found'));
448
+ yield expect(clientInstance.getIncentivesByAddress(invalidAddress)).rejects.toThrow('Not found');
449
+ }));
450
+ test('should throw an error if request fails', () => __awaiter(void 0, void 0, void 0, function* () {
451
+ const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
452
+ clientInstance['request'] = jest
453
+ .fn()
454
+ .mockRejectedValue(new Error('Network error'));
455
+ yield expect(clientInstance.getIncentivesByAddress(mockAddress)).rejects.toThrow('Network error');
456
+ }));
457
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.2.3",
3
+ "version": "2.3.0",
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"
@@ -353,4 +353,17 @@ export class Client extends Base {
353
353
  return lock;
354
354
  });
355
355
  }
356
+ /**
357
+ * @param address - Operator address
358
+ * @returns {Promise<Incentives>} The matched incentives from DB
359
+ * @throws On not found if address not found.
360
+ */
361
+ getIncentivesByAddress(address) {
362
+ return __awaiter(this, void 0, void 0, function* () {
363
+ const incentives = yield this.request(`/${DEFAULT_BASE_VERSION}/address/incentives/${address}`, {
364
+ method: 'GET',
365
+ });
366
+ return incentives;
367
+ });
368
+ }
356
369
  }
@@ -208,18 +208,13 @@ const computeDomain = (domainType, lockForkVersion, genesisValidatorsRoot = from
208
208
  * @param {string} withdrawalAddress - withdrawal address in definition file.
209
209
  * @returns {boolean} - return if deposit data is valid.
210
210
  */
211
- export const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion) => {
211
+ export const verifyDepositData = (distributedPublicKey, depositData, withdrawalAddress, forkVersion, compounding) => {
212
212
  const depositDomain = computeDomain(fromHexString(DOMAIN_DEPOSIT), forkVersion);
213
- const eth1AddressWithdrawalPrefix = '0x01';
214
- const compoundingWithdrawalPrefix = '0x02';
215
- if (eth1AddressWithdrawalPrefix +
213
+ const withdrawalPrefix = compounding ? '0x02' : '0x01';
214
+ const expectedWithdrawalCredentials = withdrawalPrefix +
216
215
  '0'.repeat(22) +
217
- withdrawalAddress.toLowerCase().slice(2) !==
218
- depositData.withdrawal_credentials &&
219
- compoundingWithdrawalPrefix +
220
- '0'.repeat(22) +
221
- withdrawalAddress.toLowerCase().slice(2) !==
222
- depositData.withdrawal_credentials) {
216
+ withdrawalAddress.toLowerCase().slice(2);
217
+ if (expectedWithdrawalCredentials !== depositData.withdrawal_credentials) {
223
218
  return { isValidDepositData: false, depositDataMsg: new Uint8Array(0) };
224
219
  }
225
220
  if (distributedPublicKey !== depositData.pubkey) {
@@ -1,7 +1,7 @@
1
1
  import { UintNumberType, } from '@chainsafe/ssz/lib/type/uint';
2
2
  import { strToUint8Array } from '../utils';
3
3
  import { builderRegistrationContainer, depositDataContainer, newCreatorContainerType, newOperatorContainerType, validatorsContainerType, } from './sszTypes';
4
- import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString, } from '@chainsafe/ssz';
4
+ import { ByteListType, ByteVectorType, ContainerType, ListBasicType, ListCompositeType, fromHexString, BooleanType, } from '@chainsafe/ssz';
5
5
  import { verifyDVV1X8 } from './v1.8.0';
6
6
  /**
7
7
  * Returns the containerized cluster definition
@@ -24,6 +24,7 @@ export const clusterDefinitionContainerTypeV1X10 = (configOnly) => {
24
24
  deposit_amounts: new ListBasicType(new UintNumberType(8), 256),
25
25
  consensus_protocol: new ByteListType(256),
26
26
  target_gas_limit: new UintNumberType(8),
27
+ compounding: new BooleanType(),
27
28
  };
28
29
  if (!configOnly) {
29
30
  returnedContainerType = Object.assign(Object.assign({}, returnedContainerType), { config_hash: new ByteVectorType(32) });
@@ -75,6 +76,9 @@ export const hashClusterDefinitionV1X10 = (cluster, configOnly) => {
75
76
  if (cluster.target_gas_limit) {
76
77
  val.target_gas_limit = cluster.target_gas_limit;
77
78
  }
79
+ if (cluster.compounding) {
80
+ val.compounding = cluster.compounding;
81
+ }
78
82
  if (!configOnly) {
79
83
  val.config_hash = fromHexString(cluster.config_hash);
80
84
  }
@@ -144,7 +144,7 @@ export const verifyDVV1X8 = (clusterLock) => {
144
144
  // Deposit Data Verification
145
145
  for (const element of validator.partial_deposit_data) {
146
146
  const depositData = element;
147
- const { isValidDepositData, depositDataMsg } = verifyDepositData(distributedPublicKey, depositData, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version);
147
+ const { isValidDepositData, depositDataMsg } = verifyDepositData(distributedPublicKey, depositData, clusterLock.cluster_definition.validators[i].withdrawal_address, clusterLock.cluster_definition.fork_version, clusterLock.cluster_definition.compounding);
148
148
  if (!isValidDepositData) {
149
149
  return false;
150
150
  }