@obolnetwork/obol-sdk 2.3.0 → 2.4.1

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.
@@ -0,0 +1,89 @@
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
+ import { isContractAvailable } from './utils';
11
+ import { claimIncentivesFromMerkleDistributor, isClaimedFromMerkleDistributor, } from './incentivesHalpers';
12
+ import { DEFAULT_BASE_VERSION } from './constants';
13
+ export class Incentives {
14
+ constructor(signer, chainId, request, provider) {
15
+ this.signer = signer;
16
+ this.chainId = chainId;
17
+ this.request = request;
18
+ this.provider = provider;
19
+ }
20
+ /**
21
+ * Claims obol incentives from a Merkle Distributor contract.
22
+ *
23
+ * @remarks
24
+ * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
25
+ * and not pushed to version control.
26
+ *
27
+ * @param {Object} incentivesData - The incentives data needed for claiming.
28
+ * @param {string} incentivesData.contractAddress - The address of the Merkle Distributor contract.
29
+ * @param {number} incentivesData.index - The index in the Merkle tree.
30
+ * @param {string} incentivesData.operatorAddress - The address of the operator.
31
+ * @param {number} incentivesData.amount - The amount to claim.
32
+ * @param {string[]} incentivesData.merkleProof - The Merkle proof.
33
+ * @returns {Promise<{ txHash: string }>} The transaction hash of the claim transaction.
34
+ * @throws Will throw an error if the contract is not available or the claim fails.
35
+ *
36
+ */
37
+ claimIncentives(incentivesData) {
38
+ return __awaiter(this, void 0, void 0, function* () {
39
+ if (!this.signer) {
40
+ throw new Error('Signer is required in claimIncentives');
41
+ }
42
+ try {
43
+ const isContractDeployed = yield isContractAvailable(incentivesData.contractAddress, this.signer.provider);
44
+ if (!isContractDeployed) {
45
+ throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contractAddress}`);
46
+ }
47
+ const { txHash } = yield claimIncentivesFromMerkleDistributor({
48
+ signer: this.signer,
49
+ contractAddress: incentivesData.contractAddress,
50
+ index: incentivesData.index,
51
+ operatorAddress: incentivesData.operatorAddress,
52
+ amount: incentivesData.amount,
53
+ merkleProof: incentivesData.merkleProof,
54
+ });
55
+ return { txHash };
56
+ }
57
+ catch (error) {
58
+ console.log('Error claiming incentives:', error);
59
+ throw new Error(`Failed to claim incentives: ${error.message}`);
60
+ }
61
+ });
62
+ }
63
+ /**
64
+ * Read isClaimed.
65
+ *
66
+ * @param {ETH_ADDRESS} contractAddress - Address of the Merkle Distributor Contract
67
+ * @param {ETH_ADDRESS} index - operator index in merkle tree
68
+ * @returns {Promise<boolean>} true if incentives are already claime
69
+ *
70
+ */
71
+ isClaimed(contractAddress, index) {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ return yield isClaimedFromMerkleDistributor(this.chainId, contractAddress, index, this.provider);
74
+ });
75
+ }
76
+ /**
77
+ * @param address - Operator address
78
+ * @returns {Promise<IncentivesType>} The matched incentives from DB
79
+ * @throws On not found if address not found.
80
+ */
81
+ getIncentivesByAddress(address) {
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const incentives = yield this.request(`/${DEFAULT_BASE_VERSION}/address/incentives/${address}`, {
84
+ method: 'GET',
85
+ });
86
+ return incentives;
87
+ });
88
+ }
89
+ }
@@ -0,0 +1,36 @@
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
+ import { Contract, } from 'ethers';
11
+ import { MerkleDistributorABI } from './abi/MerkleDistributorWithDeadline';
12
+ import { getProvider } from './utils';
13
+ export const claimIncentivesFromMerkleDistributor = (incentivesData) => __awaiter(void 0, void 0, void 0, function* () {
14
+ try {
15
+ const contract = new Contract(incentivesData.contractAddress, MerkleDistributorABI.abi, incentivesData.signer);
16
+ const tx = yield contract.claim(BigInt(incentivesData.index), incentivesData.operatorAddress, BigInt(incentivesData.amount), incentivesData.merkleProof);
17
+ const receipt = yield tx.wait();
18
+ return { txHash: receipt.hash };
19
+ }
20
+ catch (error) {
21
+ console.log('Error claiming incentives:', error);
22
+ throw new Error(`Failed to claim incentives: ${error.message}`);
23
+ }
24
+ });
25
+ export const isClaimedFromMerkleDistributor = (chainId, contractAddress, index, provider) => __awaiter(void 0, void 0, void 0, function* () {
26
+ try {
27
+ const clientProvider = provider !== null && provider !== void 0 ? provider : getProvider(chainId);
28
+ const contract = new Contract(contractAddress, MerkleDistributorABI.abi, clientProvider);
29
+ const claimed = yield contract.isClaimed(BigInt(index));
30
+ return claimed;
31
+ }
32
+ catch (error) {
33
+ console.log('Error checking claim status:', error);
34
+ throw new Error(`Failed to check claim status: ${error.message}`);
35
+ }
36
+ });
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { ZeroAddress } from 'ethers';
10
+ import { ZeroAddress, } from 'ethers';
11
11
  import { v4 as uuidv4 } from 'uuid';
12
12
  import { Base } from './base.js';
13
13
  import { CONFLICT_ERROR_MSG, CreatorConfigHashSigningTypes, Domain, DKG_ALGORITHM, CONFIG_VERSION, OperatorConfigHashSigningTypes, EnrSigningTypes, TERMS_AND_CONDITIONS_VERSION, TermsAndConditionsSigningTypes, DEFAULT_BASE_VERSION, TERMS_AND_CONDITIONS_HASH, AVAILABLE_SPLITTER_CHAINS, CHAIN_CONFIGURATION, DEFAULT_RETROACTIVE_FUNDING_REWARDS_ONLY_SPLIT, DEFAULT_RETROACTIVE_FUNDING_TOTAL_SPLIT, OBOL_SDK_EMAIL, } from './constants.js';
@@ -17,6 +17,7 @@ import { validatePayload } from './ajv.js';
17
17
  import { definitionSchema, operatorPayloadSchema, rewardsSplitterPayloadSchema, totalSplitterPayloadSchema, } from './schema.js';
18
18
  import { deploySplitterContract, formatSplitRecipients, handleDeployOWRAndSplitter, predictSplitterAddress, getOWRTranches, } from './splitHelpers.js';
19
19
  import { isContractAvailable } from './utils.js';
20
+ import { Incentives } from './incentives.js';
20
21
  export * from './types.js';
21
22
  export * from './services.js';
22
23
  export * from './verification/signature-validator.js';
@@ -35,9 +36,13 @@ export class Client extends Base {
35
36
  * An example of how to instantiate obol-sdk Client:
36
37
  * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L29)
37
38
  */
38
- constructor(config, signer) {
39
+ constructor(config, signer, provider) {
39
40
  super(config);
40
41
  this.signer = signer;
42
+ // Use the provided provider, or fall back to signer.provider if available
43
+ this.provider =
44
+ provider !== null && provider !== void 0 ? provider : (signer && 'provider' in signer ? signer.provider : undefined);
45
+ this.incentives = new Incentives(this.signer, this.chainId, this.request.bind(this), (this.provider = provider));
41
46
  }
42
47
  /**
43
48
  * Accepts Obol terms and conditions to be able to create or update data.
@@ -353,17 +358,4 @@ export class Client extends Base {
353
358
  return lock;
354
359
  });
355
360
  }
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
- }
369
361
  }
@@ -16,7 +16,7 @@ import { hashTypedData } from '@safe-global/protocol-kit/dist/src/utils';
16
16
  import { isContractAvailable, getProvider } from '../utils';
17
17
  export const validateAddressSignature = ({ address, token, data, chainId, }) => __awaiter(void 0, void 0, void 0, function* () {
18
18
  try {
19
- const provider = getProvider(chainId);
19
+ const provider = getProvider(chainId); // [TODO Hanan], should expect it from signer.provider, or passed in client
20
20
  if (provider) {
21
21
  const contractAddress = yield isContractAvailable(address, provider);
22
22
  if (contractAddress) {
@@ -0,0 +1,149 @@
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
+ var _a, _b;
11
+ import { ethers, JsonRpcProvider } from 'ethers';
12
+ import { Client } from '../src/index';
13
+ import * as utils from '../src/utils';
14
+ import * as incentivesHelpers from '../src/incentivesHalpers';
15
+ import { DEFAULT_BASE_VERSION } from '../src/constants';
16
+ const mnemonic = (_b = (_a = ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
17
+ const privateKey = ethers.Wallet.fromPhrase(mnemonic).privateKey;
18
+ const provider = new JsonRpcProvider('https://ethereum-holesky.publicnode.com');
19
+ const wallet = new ethers.Wallet(privateKey, provider);
20
+ const mockSigner = wallet.connect(provider);
21
+ const baseUrl = 'https://obol-api-dev.gcp.obol.tech';
22
+ global.fetch = jest.fn();
23
+ describe('Client.incentives', () => {
24
+ let clientInstance;
25
+ const mockIncentivesData = {
26
+ contractAddress: '0x1234567890abcdef1234567890abcdef12345678',
27
+ index: 5,
28
+ operatorAddress: '0xabcdef1234567890abcdef1234567890abcdef12',
29
+ amount: 1000000000000000000,
30
+ merkleProof: [
31
+ '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
32
+ '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
33
+ ],
34
+ };
35
+ beforeEach(() => {
36
+ jest.clearAllMocks();
37
+ clientInstance = new Client({ baseUrl, chainId: 17000 }, mockSigner);
38
+ global.fetch.mockReset();
39
+ });
40
+ test('claimIncentives should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
41
+ const clientWithoutSigner = new Client({
42
+ baseUrl,
43
+ chainId: 17000,
44
+ });
45
+ yield expect(clientWithoutSigner.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Signer is required in claimIncentives');
46
+ }));
47
+ test('claimIncentives should throw an error if contract is not available', () => __awaiter(void 0, void 0, void 0, function* () {
48
+ jest
49
+ .spyOn(utils, 'isContractAvailable')
50
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(false); }));
51
+ yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow(`Merkle Distributor contract is not available at address ${mockIncentivesData.contractAddress}`);
52
+ }));
53
+ test('claimIncentives should return txHash on successful claim', () => __awaiter(void 0, void 0, void 0, function* () {
54
+ const mockTxHash = '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
55
+ jest
56
+ .spyOn(utils, 'isContractAvailable')
57
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
58
+ jest
59
+ .spyOn(incentivesHelpers, 'claimIncentivesFromMerkleDistributor')
60
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve({ txHash: mockTxHash }); }));
61
+ const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData);
62
+ expect(result).toEqual({ txHash: mockTxHash });
63
+ expect(incentivesHelpers.claimIncentivesFromMerkleDistributor).toHaveBeenCalledWith({
64
+ signer: mockSigner,
65
+ contractAddress: mockIncentivesData.contractAddress,
66
+ index: mockIncentivesData.index,
67
+ operatorAddress: mockIncentivesData.operatorAddress,
68
+ amount: mockIncentivesData.amount,
69
+ merkleProof: mockIncentivesData.merkleProof,
70
+ });
71
+ }));
72
+ test('claimIncentives should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
73
+ jest
74
+ .spyOn(utils, 'isContractAvailable')
75
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
76
+ jest
77
+ .spyOn(incentivesHelpers, 'claimIncentivesFromMerkleDistributor')
78
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
79
+ throw new Error('Helper function error');
80
+ }));
81
+ yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Failed to claim incentives: Helper function error');
82
+ }));
83
+ test('incentives should be initialized with the same chainId as client', () => {
84
+ const customChainId = 5;
85
+ const clientWithCustomChain = new Client({ baseUrl, chainId: customChainId }, mockSigner);
86
+ expect(clientWithCustomChain.incentives.chainId).toBe(customChainId);
87
+ });
88
+ test('isClaimed should return true when incentive is claimed', () => __awaiter(void 0, void 0, void 0, function* () {
89
+ jest
90
+ .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
91
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
92
+ const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
93
+ expect(result).toBe(true);
94
+ expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientInstance.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index, undefined);
95
+ }));
96
+ test('isClaimed should return false when incentive is not claimed', () => __awaiter(void 0, void 0, void 0, function* () {
97
+ jest
98
+ .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
99
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(false); }));
100
+ const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
101
+ expect(result).toBe(false);
102
+ }));
103
+ test('isClaimed should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
104
+ jest
105
+ .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
106
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
107
+ throw new Error('Helper function error');
108
+ }));
109
+ yield expect(clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index)).rejects.toThrow('Helper function error');
110
+ }));
111
+ test('isClaimed should work with a provider and a without signer', () => __awaiter(void 0, void 0, void 0, function* () {
112
+ // Create a client without a signer
113
+ const clientWithoutSigner = new Client({
114
+ baseUrl,
115
+ chainId: 17000,
116
+ }, undefined, provider);
117
+ jest
118
+ .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
119
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
120
+ const result = yield clientWithoutSigner.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
121
+ expect(result).toBe(true);
122
+ expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientWithoutSigner.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index, provider);
123
+ }));
124
+ test('getIncentivesByAddress should make the correct API request', () => __awaiter(void 0, void 0, void 0, function* () {
125
+ const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
126
+ const mockIncentives = {
127
+ operator_address: '0x8c00157cae72c4ed6a1f8bfb60205601f0252e26',
128
+ amount: '100',
129
+ index: 1,
130
+ merkle_proof: ['hash1', 'hash2'],
131
+ contract_address: '0xContract',
132
+ };
133
+ global.fetch.mockResolvedValueOnce({
134
+ ok: true,
135
+ status: 200,
136
+ json: () => __awaiter(void 0, void 0, void 0, function* () { return mockIncentives; }),
137
+ headers: new Headers(),
138
+ });
139
+ const result = yield clientInstance.incentives.getIncentivesByAddress(mockAddress);
140
+ expect(result).toEqual(mockIncentives);
141
+ expect(global.fetch).toHaveBeenCalledWith(`${baseUrl}/${DEFAULT_BASE_VERSION}/address/incentives/${mockAddress}`, expect.objectContaining({ method: 'GET' }));
142
+ }));
143
+ test('getIncentivesByAddress should handle API errors', () => __awaiter(void 0, void 0, void 0, function* () {
144
+ const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
145
+ global.fetch.mockRejectedValue(new Error('Network error'));
146
+ yield expect(clientInstance.incentives.getIncentivesByAddress(mockAddress)).rejects.toThrow();
147
+ expect(global.fetch).toHaveBeenCalled();
148
+ }));
149
+ });
@@ -386,47 +386,3 @@ describe('createObolTotalSplit', () => {
386
386
  });
387
387
  }));
388
388
  });
389
- describe('getIncentivesByAddress', () => {
390
- let clientInstance;
391
- beforeAll(() => {
392
- jest
393
- .spyOn(utils, 'isContractAvailable')
394
- .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
395
- jest
396
- .spyOn(splitsHelpers, 'predictSplitterAddress')
397
- .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xPredictedAddress'); }));
398
- jest
399
- .spyOn(splitsHelpers, 'deploySplitterContract')
400
- .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xSplitterAddress'); }));
401
- clientInstance = new Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
402
- });
403
- test('should return incentives for a valid address', () => __awaiter(void 0, void 0, void 0, function* () {
404
- const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
405
- const mockIncentives = {
406
- operator_address: '0x8c00157cae72c4ed6a1f8bfb60205601f0252e26',
407
- amount: '100',
408
- index: 1,
409
- merkle_proof: ['hash1', 'hash2'],
410
- contract_address: '0xContract',
411
- };
412
- clientInstance['request'] = jest
413
- .fn()
414
- .mockReturnValue(Promise.resolve(mockIncentives));
415
- const incentives = yield clientInstance.getIncentivesByAddress(mockAddress);
416
- expect(incentives).toEqual(mockIncentives);
417
- }));
418
- test('should throw an error if address is not found', () => __awaiter(void 0, void 0, void 0, function* () {
419
- const invalidAddress = '0x0000000000000000000000000000000000000000';
420
- clientInstance['request'] = jest
421
- .fn()
422
- .mockRejectedValue(new Error('Not found'));
423
- yield expect(clientInstance.getIncentivesByAddress(invalidAddress)).rejects.toThrow('Not found');
424
- }));
425
- test('should throw an error if request fails', () => __awaiter(void 0, void 0, void 0, function* () {
426
- const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
427
- clientInstance['request'] = jest
428
- .fn()
429
- .mockRejectedValue(new Error('Network error'));
430
- yield expect(clientInstance.getIncentivesByAddress(mockAddress)).rejects.toThrow('Network error');
431
- }));
432
- });
@@ -0,0 +1,91 @@
1
+ export declare const MerkleDistributorABI: {
2
+ abi: readonly [{
3
+ readonly inputs: readonly [{
4
+ readonly internalType: "address";
5
+ readonly name: "token_";
6
+ readonly type: "address";
7
+ }, {
8
+ readonly internalType: "bytes32";
9
+ readonly name: "merkleRoot_";
10
+ readonly type: "bytes32";
11
+ }];
12
+ readonly stateMutability: "nonpayable";
13
+ readonly type: "constructor";
14
+ }, {
15
+ readonly anonymous: false;
16
+ readonly inputs: readonly [{
17
+ readonly indexed: false;
18
+ readonly internalType: "uint256";
19
+ readonly name: "index";
20
+ readonly type: "uint256";
21
+ }, {
22
+ readonly indexed: false;
23
+ readonly internalType: "address";
24
+ readonly name: "account";
25
+ readonly type: "address";
26
+ }, {
27
+ readonly indexed: false;
28
+ readonly internalType: "uint256";
29
+ readonly name: "amount";
30
+ readonly type: "uint256";
31
+ }];
32
+ readonly name: "Claimed";
33
+ readonly type: "event";
34
+ }, {
35
+ readonly inputs: readonly [{
36
+ readonly internalType: "uint256";
37
+ readonly name: "index";
38
+ readonly type: "uint256";
39
+ }, {
40
+ readonly internalType: "address";
41
+ readonly name: "account";
42
+ readonly type: "address";
43
+ }, {
44
+ readonly internalType: "uint256";
45
+ readonly name: "amount";
46
+ readonly type: "uint256";
47
+ }, {
48
+ readonly internalType: "bytes32[]";
49
+ readonly name: "merkleProof";
50
+ readonly type: "bytes32[]";
51
+ }];
52
+ readonly name: "claim";
53
+ readonly outputs: readonly [];
54
+ readonly stateMutability: "nonpayable";
55
+ readonly type: "function";
56
+ }, {
57
+ readonly inputs: readonly [{
58
+ readonly internalType: "uint256";
59
+ readonly name: "index";
60
+ readonly type: "uint256";
61
+ }];
62
+ readonly name: "isClaimed";
63
+ readonly outputs: readonly [{
64
+ readonly internalType: "bool";
65
+ readonly name: "";
66
+ readonly type: "bool";
67
+ }];
68
+ readonly stateMutability: "view";
69
+ readonly type: "function";
70
+ }, {
71
+ readonly inputs: readonly [];
72
+ readonly name: "merkleRoot";
73
+ readonly outputs: readonly [{
74
+ readonly internalType: "bytes32";
75
+ readonly name: "";
76
+ readonly type: "bytes32";
77
+ }];
78
+ readonly stateMutability: "view";
79
+ readonly type: "function";
80
+ }, {
81
+ readonly inputs: readonly [];
82
+ readonly name: "token";
83
+ readonly outputs: readonly [{
84
+ readonly internalType: "address";
85
+ readonly name: "";
86
+ readonly type: "address";
87
+ }];
88
+ readonly stateMutability: "view";
89
+ readonly type: "function";
90
+ }];
91
+ };
@@ -0,0 +1,50 @@
1
+ import { type JsonRpcApiProvider, type JsonRpcProvider, type JsonRpcSigner, type Provider, type Signer } from 'ethers';
2
+ import { type Incentives as IncentivesType, type ETH_ADDRESS } from './types';
3
+ export declare class Incentives {
4
+ private readonly signer;
5
+ readonly chainId: number;
6
+ private readonly request;
7
+ readonly provider: Provider | JsonRpcProvider | JsonRpcApiProvider | undefined | null;
8
+ constructor(signer: Signer | JsonRpcSigner | undefined, chainId: number, request: (endpoint: string, options?: RequestInit) => Promise<any>, provider: Provider | JsonRpcProvider | JsonRpcApiProvider | undefined | null);
9
+ /**
10
+ * Claims obol incentives from a Merkle Distributor contract.
11
+ *
12
+ * @remarks
13
+ * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
14
+ * and not pushed to version control.
15
+ *
16
+ * @param {Object} incentivesData - The incentives data needed for claiming.
17
+ * @param {string} incentivesData.contractAddress - The address of the Merkle Distributor contract.
18
+ * @param {number} incentivesData.index - The index in the Merkle tree.
19
+ * @param {string} incentivesData.operatorAddress - The address of the operator.
20
+ * @param {number} incentivesData.amount - The amount to claim.
21
+ * @param {string[]} incentivesData.merkleProof - The Merkle proof.
22
+ * @returns {Promise<{ txHash: string }>} The transaction hash of the claim transaction.
23
+ * @throws Will throw an error if the contract is not available or the claim fails.
24
+ *
25
+ */
26
+ claimIncentives(incentivesData: {
27
+ contractAddress: ETH_ADDRESS;
28
+ index: number;
29
+ operatorAddress: ETH_ADDRESS;
30
+ amount: number;
31
+ merkleProof: string[];
32
+ }): Promise<{
33
+ txHash: string;
34
+ }>;
35
+ /**
36
+ * Read isClaimed.
37
+ *
38
+ * @param {ETH_ADDRESS} contractAddress - Address of the Merkle Distributor Contract
39
+ * @param {ETH_ADDRESS} index - operator index in merkle tree
40
+ * @returns {Promise<boolean>} true if incentives are already claime
41
+ *
42
+ */
43
+ isClaimed(contractAddress: ETH_ADDRESS, index: number): Promise<boolean>;
44
+ /**
45
+ * @param address - Operator address
46
+ * @returns {Promise<IncentivesType>} The matched incentives from DB
47
+ * @throws On not found if address not found.
48
+ */
49
+ getIncentivesByAddress(address: string): Promise<IncentivesType>;
50
+ }
@@ -0,0 +1,13 @@
1
+ import { type ETH_ADDRESS } from './types';
2
+ import { type JsonRpcApiProvider, type JsonRpcProvider, type Provider, type Signer } from 'ethers';
3
+ export declare const claimIncentivesFromMerkleDistributor: (incentivesData: {
4
+ signer: Signer;
5
+ contractAddress: ETH_ADDRESS;
6
+ index: number;
7
+ operatorAddress: ETH_ADDRESS;
8
+ amount: number;
9
+ merkleProof: string[];
10
+ }) => Promise<{
11
+ txHash: string;
12
+ }>;
13
+ export declare const isClaimedFromMerkleDistributor: (chainId: number, contractAddress: ETH_ADDRESS, index: number, provider: Provider | JsonRpcProvider | JsonRpcApiProvider | undefined | null) => Promise<boolean>;
@@ -1,6 +1,7 @@
1
- import { type Signer } from 'ethers';
1
+ import { type Provider, type Signer, type JsonRpcSigner, type JsonRpcProvider, type JsonRpcApiProvider } from 'ethers';
2
2
  import { Base } from './base.js';
3
- import { type RewardsSplitPayload, type ClusterDefinition, type ClusterLock, type ClusterPayload, type OperatorPayload, type TotalSplitPayload, type ClusterValidator, type ETH_ADDRESS, type OWRTranches, type Incentives } from './types.js';
3
+ import { type RewardsSplitPayload, type ClusterDefinition, type ClusterLock, type ClusterPayload, type OperatorPayload, type TotalSplitPayload, type ClusterValidator, type ETH_ADDRESS, type OWRTranches } from './types.js';
4
+ import { Incentives } from './incentives.js';
4
5
  export * from './types.js';
5
6
  export * from './services.js';
6
7
  export * from './verification/signature-validator.js';
@@ -10,6 +11,8 @@ export * from './verification/common.js';
10
11
  */
11
12
  export declare class Client extends Base {
12
13
  private readonly signer;
14
+ incentives: Incentives;
15
+ provider: Provider | JsonRpcProvider | JsonRpcApiProvider | undefined | null;
13
16
  /**
14
17
  * @param config - Client configurations
15
18
  * @param config.baseUrl - obol-api url
@@ -23,7 +26,7 @@ export declare class Client extends Base {
23
26
  constructor(config: {
24
27
  baseUrl?: string;
25
28
  chainId?: number;
26
- }, signer?: Signer);
29
+ }, signer?: Signer | JsonRpcSigner, provider?: Provider | JsonRpcProvider);
27
30
  /**
28
31
  * Accepts Obol terms and conditions to be able to create or update data.
29
32
  * @returns {Promise<string>} terms and conditions acceptance success message.
@@ -112,10 +115,4 @@ export declare class Client extends Base {
112
115
  * [getObolClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L89)
113
116
  */
114
117
  getClusterLock(configHash: string): Promise<ClusterLock>;
115
- /**
116
- * @param address - Operator address
117
- * @returns {Promise<Incentives>} The matched incentives from DB
118
- * @throws On not found if address not found.
119
- */
120
- getIncentivesByAddress(address: string): Promise<Incentives>;
121
118
  }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
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"
@@ -15,7 +15,7 @@
15
15
  "compile": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json ./tsconfig.types.json",
16
16
  "build:clean": "rm -rf ./dist",
17
17
  "build": "npm-run-all build:clean compile",
18
- "test": "jest ./test/methods.test.ts",
18
+ "test": "jest ./test/*.test.ts",
19
19
  "generate-typedoc": "typedoc",
20
20
  "npm:publish": "npm publish --tag latest",
21
21
  "release": "release-it",