@obolnetwork/obol-sdk 2.4.3 → 2.4.5

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.4.3",
3
+ "version": "2.4.5",
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"
@@ -23,7 +23,8 @@
23
23
  "lint": "eslint \"{src,test}/**/*.{js,ts}\" --fix",
24
24
  "lint-ci": "eslint \"{src,test}/**/*.{js,ts}\"",
25
25
  "prettier-ci": "prettier --check \"{src,test}/**/*.{js,ts}\"",
26
- "prettier": "prettier --write \"{src,test}/**/*.{js,ts}\""
26
+ "prettier": "prettier --write \"{src,test}/**/*.{js,ts}\"",
27
+ "docs": "typedoc"
27
28
  },
28
29
  "main": "./dist/cjs/src/index.js",
29
30
  "module": "./dist/esm/src/index.js",
@@ -79,8 +80,8 @@
79
80
  "release-it": "^17.2.1",
80
81
  "ts-jest": "^28.0.8",
81
82
  "tsup": "^6.7.0",
82
- "typedoc": "^0.25.7",
83
- "typedoc-plugin-markdown": "^4.0.0-next.50",
83
+ "typedoc": "^0.28.0",
84
+ "typedoc-plugin-markdown": "^4.5.2",
84
85
  "typescript": "~5.3.3"
85
86
  },
86
87
  "engines": {
@@ -12,8 +12,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Incentives = void 0;
13
13
  const utils_1 = require("./utils");
14
14
  const types_1 = require("./types");
15
- const incentivesHalpers_1 = require("./incentivesHalpers");
15
+ const incentiveHelpers_1 = require("./incentiveHelpers");
16
16
  const constants_1 = require("./constants");
17
+ /**
18
+ * Incentives can be used for fetching and claiming Obol incentives.
19
+ * @class
20
+ * @internal Access it through Client.incentives.
21
+ * @example
22
+ * const obolClient = new Client(config);
23
+ * await obolClient.incentives.claimIncentives(address);
24
+ */
17
25
  class Incentives {
18
26
  constructor(signer, chainId, request, provider) {
19
27
  this.signer = signer;
@@ -22,39 +30,49 @@ class Incentives {
22
30
  this.provider = provider;
23
31
  }
24
32
  /**
25
- * Claims obol incentives from a Merkle Distributor contract.
33
+ * Claims Obol incentives from a Merkle Distributor contract using an address.
34
+ *
35
+ * This method automatically fetches incentive data and verifies whether the incentives have already been claimed.
36
+ * If `txHash` is `null`, it indicates that the incentives were already claimed.
37
+ *
38
+ * Note: This method is not yet enabled and will throw an error if called.
26
39
  *
27
40
  * @remarks
28
41
  * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
29
42
  * and not pushed to version control.
30
43
  *
31
- * @param {Object} incentivesData - The incentives data needed for claiming.
32
- * @param {string} incentivesData.contractAddress - The address of the Merkle Distributor contract.
33
- * @param {number} incentivesData.index - The index in the Merkle tree.
34
- * @param {string} incentivesData.operatorAddress - The address of the operator.
35
- * @param {number} incentivesData.amount - The amount to claim.
36
- * @param {string[]} incentivesData.merkleProof - The Merkle proof.
37
- * @returns {Promise<{ txHash: string }>} The transaction hash of the claim transaction.
38
- * @throws Will throw an error if the contract is not available or the claim fails.
44
+ * @param {string} address - The address to claim incentives for
45
+ * @returns {Promise<ClaimIncentivesResponse>} The transaction hash or already claimed status
46
+ * @throws Will throw an error if the incentives data is not found or the claim fails
39
47
  *
48
+ * An example of how to use claimIncentives:
49
+ * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L281)
40
50
  */
41
- claimIncentives(incentivesData) {
51
+ claimIncentives(address) {
42
52
  return __awaiter(this, void 0, void 0, function* () {
43
53
  if (!this.signer) {
44
54
  throw new Error('Signer is required in claimIncentives');
45
55
  }
46
56
  try {
47
- const isContractDeployed = yield (0, utils_1.isContractAvailable)(incentivesData.contractAddress, this.signer.provider);
57
+ const incentivesData = yield this.getIncentivesByAddress(address);
58
+ if (!(incentivesData === null || incentivesData === void 0 ? void 0 : incentivesData.contract_address)) {
59
+ throw new Error(`No incentives found for address ${address}`);
60
+ }
61
+ const isContractDeployed = yield (0, utils_1.isContractAvailable)(incentivesData.contract_address, this.provider);
48
62
  if (!isContractDeployed) {
49
- throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contractAddress}`);
63
+ throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contract_address}`);
50
64
  }
51
- const { txHash } = yield (0, incentivesHalpers_1.claimIncentivesFromMerkleDistributor)({
65
+ const claimed = yield this.isClaimed(incentivesData.contract_address, incentivesData.index);
66
+ if (claimed) {
67
+ return { txHash: null };
68
+ }
69
+ const { txHash } = yield (0, incentiveHelpers_1.claimIncentivesFromMerkleDistributor)({
52
70
  signer: this.signer,
53
- contractAddress: incentivesData.contractAddress,
71
+ contractAddress: incentivesData.contract_address,
54
72
  index: incentivesData.index,
55
- operatorAddress: incentivesData.operatorAddress,
73
+ operatorAddress: incentivesData.operator_address,
56
74
  amount: incentivesData.amount,
57
- merkleProof: incentivesData.merkleProof,
75
+ merkleProof: incentivesData.merkle_proof,
58
76
  });
59
77
  return { txHash };
60
78
  }
@@ -71,16 +89,22 @@ class Incentives {
71
89
  * @param {ETH_ADDRESS} index - operator index in merkle tree
72
90
  * @returns {Promise<boolean>} true if incentives are already claime
73
91
  *
92
+ *
93
+ * An example of how to use isClaimed:
94
+ * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L266)
74
95
  */
75
96
  isClaimed(contractAddress, index) {
76
97
  return __awaiter(this, void 0, void 0, function* () {
77
- return yield (0, incentivesHalpers_1.isClaimedFromMerkleDistributor)(this.chainId, contractAddress, index, this.provider);
98
+ return yield (0, incentiveHelpers_1.isClaimedFromMerkleDistributor)(this.chainId, contractAddress, index, this.provider);
78
99
  });
79
100
  }
80
101
  /**
81
102
  * @param address - Operator address
82
103
  * @returns {Promise<IncentivesType>} The matched incentives from DB
83
104
  * @throws On not found if address not found.
105
+ *
106
+ * An example of how to use getIncentivesByAddress:
107
+ * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L250)
84
108
  */
85
109
  getIncentivesByAddress(address) {
86
110
  return __awaiter(this, void 0, void 0, function* () {
@@ -23,7 +23,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
23
23
  });
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.Client = void 0;
26
+ exports.Client = exports.Incentives = void 0;
27
27
  const ethers_1 = require("ethers");
28
28
  const uuid_1 = require("uuid");
29
29
  const base_js_1 = require("./base.js");
@@ -39,6 +39,8 @@ __exportStar(require("./types.js"), exports);
39
39
  __exportStar(require("./services.js"), exports);
40
40
  __exportStar(require("./verification/signature-validator.js"), exports);
41
41
  __exportStar(require("./verification/common.js"), exports);
42
+ var incentives_js_2 = require("./incentives.js");
43
+ Object.defineProperty(exports, "Incentives", { enumerable: true, get: function () { return incentives_js_2.Incentives; } });
42
44
  /**
43
45
  * Obol sdk Client can be used for creating, managing and activating distributed validators.
44
46
  */
@@ -59,7 +61,7 @@ class Client extends base_js_1.Base {
59
61
  // Use the provided provider, or fall back to signer.provider if available
60
62
  this.provider =
61
63
  provider !== null && provider !== void 0 ? provider : (signer && 'provider' in signer ? signer.provider : undefined);
62
- this.incentives = new incentives_js_1.Incentives(this.signer, this.chainId, this.request.bind(this), (this.provider = provider));
64
+ this.incentives = new incentives_js_1.Incentives(this.signer, this.chainId, this.request.bind(this), this.provider);
63
65
  }
64
66
  /**
65
67
  * Accepts Obol terms and conditions to be able to create or update data.
@@ -19,20 +19,11 @@ var FORK_MAPPING;
19
19
  /** Hoodi Chain. */
20
20
  FORK_MAPPING[FORK_MAPPING["0x10000910"] = 560048] = "0x10000910";
21
21
  })(FORK_MAPPING || (exports.FORK_MAPPING = FORK_MAPPING = {}));
22
- /**
23
- * Permitted Chain Names
24
- */
25
22
  exports.FORK_NAMES = {
26
- /** Mainnet. */
27
23
  [FORK_MAPPING['0x00000000']]: 'mainnet',
28
- /** Goerli/Prater. */
29
24
  [FORK_MAPPING['0x00001020']]: 'goerli',
30
- /** Gnosis Chain. */
31
25
  [FORK_MAPPING['0x00000064']]: 'gnosis',
32
- /** Holesky. */
33
26
  [FORK_MAPPING['0x01017000']]: 'holesky',
34
- /** Sepolia. */
35
27
  [FORK_MAPPING['0x90000069']]: 'sepolia',
36
- /** Hoodi. */
37
28
  [FORK_MAPPING['0x10000910']]: 'hoodi',
38
29
  };
@@ -36,117 +36,145 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const ethers_1 = require("ethers");
37
37
  const index_1 = require("../src/index");
38
38
  const utils = __importStar(require("../src/utils"));
39
- const incentivesHelpers = __importStar(require("../src/incentivesHalpers"));
39
+ const incentivesHelpers = __importStar(require("../src/incentiveHelpers"));
40
40
  const constants_1 = require("../src/constants");
41
+ const globals_1 = require("@jest/globals");
41
42
  const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
42
43
  const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
43
44
  const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
44
45
  const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
45
46
  const mockSigner = wallet.connect(provider);
46
47
  const baseUrl = 'https://obol-api-dev.gcp.obol.tech';
47
- global.fetch = jest.fn();
48
- describe('Client.incentives', () => {
48
+ // Fix the type error by properly typing the mock function
49
+ global.fetch = globals_1.jest.fn();
50
+ (0, globals_1.describe)('Client.incentives', () => {
49
51
  let clientInstance;
50
52
  const mockIncentivesData = {
51
- contractAddress: '0x1234567890abcdef1234567890abcdef12345678',
53
+ contract_address: '0x1234567890abcdef1234567890abcdef12345678',
52
54
  index: 5,
53
- operatorAddress: '0xabcdef1234567890abcdef1234567890abcdef12',
54
- amount: 1000000000000000000,
55
- merkleProof: [
55
+ operator_address: '0xabcdef1234567890abcdef1234567890abcdef12',
56
+ amount: '1000000000000000000',
57
+ merkle_proof: [
56
58
  '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
57
59
  '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
58
60
  ],
59
61
  };
60
- beforeEach(() => {
61
- jest.clearAllMocks();
62
+ (0, globals_1.beforeEach)(() => {
63
+ globals_1.jest.clearAllMocks();
62
64
  clientInstance = new index_1.Client({ baseUrl, chainId: 17000 }, mockSigner);
63
65
  global.fetch.mockReset();
64
66
  });
65
- test('claimIncentives should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
67
+ (0, globals_1.test)('claimIncentives should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
66
68
  const clientWithoutSigner = new index_1.Client({
67
69
  baseUrl,
68
70
  chainId: 17000,
69
71
  });
70
- yield expect(clientWithoutSigner.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Signer is required in claimIncentives');
72
+ yield (0, globals_1.expect)(clientWithoutSigner.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow('Signer is required in claimIncentives');
71
73
  }));
72
- test('claimIncentives should throw an error if contract is not available', () => __awaiter(void 0, void 0, void 0, function* () {
73
- jest
74
+ (0, globals_1.test)('claimIncentives should throw an error if contract is not available', () => __awaiter(void 0, void 0, void 0, function* () {
75
+ globals_1.jest
76
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
77
+ .mockResolvedValue(mockIncentivesData);
78
+ globals_1.jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(false);
79
+ globals_1.jest
74
80
  .spyOn(utils, 'isContractAvailable')
75
81
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(false); }));
76
- yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow(`Merkle Distributor contract is not available at address ${mockIncentivesData.contractAddress}`);
82
+ yield (0, globals_1.expect)(clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow(`Merkle Distributor contract is not available at address ${mockIncentivesData.contract_address}`);
77
83
  }));
78
- test('claimIncentives should return txHash on successful claim', () => __awaiter(void 0, void 0, void 0, function* () {
84
+ (0, globals_1.test)('claimIncentives should return txHash on successful claim', () => __awaiter(void 0, void 0, void 0, function* () {
79
85
  const mockTxHash = '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
80
- jest
86
+ globals_1.jest
87
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
88
+ .mockResolvedValue(mockIncentivesData);
89
+ globals_1.jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(false);
90
+ globals_1.jest
81
91
  .spyOn(utils, 'isContractAvailable')
82
92
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
83
- jest
93
+ globals_1.jest
84
94
  .spyOn(incentivesHelpers, 'claimIncentivesFromMerkleDistributor')
85
95
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve({ txHash: mockTxHash }); }));
86
- const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData);
87
- expect(result).toEqual({ txHash: mockTxHash });
88
- expect(incentivesHelpers.claimIncentivesFromMerkleDistributor).toHaveBeenCalledWith({
96
+ const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address);
97
+ (0, globals_1.expect)(result).toEqual({ txHash: mockTxHash });
98
+ (0, globals_1.expect)(incentivesHelpers.claimIncentivesFromMerkleDistributor).toHaveBeenCalledWith({
89
99
  signer: mockSigner,
90
- contractAddress: mockIncentivesData.contractAddress,
100
+ contractAddress: mockIncentivesData.contract_address,
91
101
  index: mockIncentivesData.index,
92
- operatorAddress: mockIncentivesData.operatorAddress,
102
+ operatorAddress: mockIncentivesData.operator_address,
93
103
  amount: mockIncentivesData.amount,
94
- merkleProof: mockIncentivesData.merkleProof,
104
+ merkleProof: mockIncentivesData.merkle_proof,
95
105
  });
96
106
  }));
97
- test('claimIncentives should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
98
- jest
107
+ (0, globals_1.test)('claimIncentives should return txHash as null when incentives are already claimed', () => __awaiter(void 0, void 0, void 0, function* () {
108
+ globals_1.jest
109
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
110
+ .mockResolvedValue(mockIncentivesData);
111
+ globals_1.jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(true);
112
+ const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address);
113
+ (0, globals_1.expect)(result).toEqual({ txHash: null });
114
+ (0, globals_1.expect)(incentivesHelpers.claimIncentivesFromMerkleDistributor).not.toHaveBeenCalled();
115
+ }));
116
+ (0, globals_1.test)('claimIncentives should throw an error if no incentives found for address', () => __awaiter(void 0, void 0, void 0, function* () {
117
+ globals_1.jest
118
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
119
+ .mockRejectedValue(new Error('No incentives found for address'));
120
+ yield (0, globals_1.expect)(clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow('Failed to claim incentives: No incentives found for address');
121
+ }));
122
+ (0, globals_1.test)('claimIncentives should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
123
+ globals_1.jest
124
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
125
+ .mockResolvedValue(mockIncentivesData);
126
+ globals_1.jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(false);
127
+ globals_1.jest
99
128
  .spyOn(utils, 'isContractAvailable')
100
129
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
101
- jest
130
+ globals_1.jest
102
131
  .spyOn(incentivesHelpers, 'claimIncentivesFromMerkleDistributor')
103
132
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
104
133
  throw new Error('Helper function error');
105
134
  }));
106
- yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Failed to claim incentives: Helper function error');
135
+ yield (0, globals_1.expect)(clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow('Failed to claim incentives: Helper function error');
107
136
  }));
108
- test('incentives should be initialized with the same chainId as client', () => {
137
+ (0, globals_1.test)('incentives should be initialized with the same chainId as client', () => {
109
138
  const customChainId = 5;
110
139
  const clientWithCustomChain = new index_1.Client({ baseUrl, chainId: customChainId }, mockSigner);
111
- expect(clientWithCustomChain.incentives.chainId).toBe(customChainId);
140
+ (0, globals_1.expect)(clientWithCustomChain.incentives.chainId).toBe(customChainId);
112
141
  });
113
- test('isClaimed should return true when incentive is claimed', () => __awaiter(void 0, void 0, void 0, function* () {
114
- jest
142
+ (0, globals_1.test)('isClaimed should return true when incentive is claimed', () => __awaiter(void 0, void 0, void 0, function* () {
143
+ globals_1.jest
115
144
  .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
116
145
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
117
- const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
118
- expect(result).toBe(true);
119
- expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientInstance.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index, undefined);
146
+ const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
147
+ (0, globals_1.expect)(result).toBe(true);
148
+ (0, globals_1.expect)(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientInstance.incentives.chainId, mockIncentivesData.contract_address, mockIncentivesData.index, {});
120
149
  }));
121
- test('isClaimed should return false when incentive is not claimed', () => __awaiter(void 0, void 0, void 0, function* () {
122
- jest
150
+ (0, globals_1.test)('isClaimed should return false when incentive is not claimed', () => __awaiter(void 0, void 0, void 0, function* () {
151
+ globals_1.jest
123
152
  .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
124
153
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(false); }));
125
- const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
126
- expect(result).toBe(false);
154
+ const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
155
+ (0, globals_1.expect)(result).toBe(false);
127
156
  }));
128
- test('isClaimed should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
129
- jest
157
+ (0, globals_1.test)('isClaimed should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
158
+ globals_1.jest
130
159
  .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
131
160
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
132
161
  throw new Error('Helper function error');
133
162
  }));
134
- yield expect(clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index)).rejects.toThrow('Helper function error');
163
+ yield (0, globals_1.expect)(clientInstance.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index)).rejects.toThrow('Helper function error');
135
164
  }));
136
- test('isClaimed should work with a provider and a without signer', () => __awaiter(void 0, void 0, void 0, function* () {
137
- // Create a client without a signer
165
+ (0, globals_1.test)('isClaimed should work with a provider and a without signer', () => __awaiter(void 0, void 0, void 0, function* () {
138
166
  const clientWithoutSigner = new index_1.Client({
139
167
  baseUrl,
140
168
  chainId: 17000,
141
169
  }, undefined, provider);
142
- jest
170
+ globals_1.jest
143
171
  .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
144
172
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
145
- const result = yield clientWithoutSigner.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
146
- expect(result).toBe(true);
147
- expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientWithoutSigner.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index, provider);
173
+ const result = yield clientWithoutSigner.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
174
+ (0, globals_1.expect)(result).toBe(true);
175
+ (0, globals_1.expect)(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientWithoutSigner.incentives.chainId, mockIncentivesData.contract_address, mockIncentivesData.index, provider);
148
176
  }));
149
- test('getIncentivesByAddress should make the correct API request', () => __awaiter(void 0, void 0, void 0, function* () {
177
+ (0, globals_1.test)('getIncentivesByAddress should make the correct API request', () => __awaiter(void 0, void 0, void 0, function* () {
150
178
  const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
151
179
  const mockIncentives = {
152
180
  operator_address: '0x8c00157cae72c4ed6a1f8bfb60205601f0252e26',
@@ -162,13 +190,13 @@ describe('Client.incentives', () => {
162
190
  headers: new Headers(),
163
191
  });
164
192
  const result = yield clientInstance.incentives.getIncentivesByAddress(mockAddress);
165
- expect(result).toEqual(mockIncentives);
166
- expect(global.fetch).toHaveBeenCalledWith(`${baseUrl}/${constants_1.DEFAULT_BASE_VERSION}/address/incentives/holesky/${mockAddress}`, expect.objectContaining({ method: 'GET' }));
193
+ (0, globals_1.expect)(result).toEqual(mockIncentives);
194
+ (0, globals_1.expect)(global.fetch).toHaveBeenCalledWith(`${baseUrl}/${constants_1.DEFAULT_BASE_VERSION}/address/incentives/holesky/${mockAddress}`, globals_1.expect.objectContaining({ method: 'GET' }));
167
195
  }));
168
- test('getIncentivesByAddress should handle API errors', () => __awaiter(void 0, void 0, void 0, function* () {
196
+ (0, globals_1.test)('getIncentivesByAddress should handle API errors', () => __awaiter(void 0, void 0, void 0, function* () {
169
197
  const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
170
198
  global.fetch.mockRejectedValue(new Error('Network error'));
171
- yield expect(clientInstance.incentives.getIncentivesByAddress(mockAddress)).rejects.toThrow();
172
- expect(global.fetch).toHaveBeenCalled();
199
+ yield (0, globals_1.expect)(clientInstance.incentives.getIncentivesByAddress(mockAddress)).rejects.toThrow();
200
+ (0, globals_1.expect)(global.fetch).toHaveBeenCalled();
173
201
  }));
174
202
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.4.3",
3
+ "version": "2.4.5",
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"
@@ -23,7 +23,8 @@
23
23
  "lint": "eslint \"{src,test}/**/*.{js,ts}\" --fix",
24
24
  "lint-ci": "eslint \"{src,test}/**/*.{js,ts}\"",
25
25
  "prettier-ci": "prettier --check \"{src,test}/**/*.{js,ts}\"",
26
- "prettier": "prettier --write \"{src,test}/**/*.{js,ts}\""
26
+ "prettier": "prettier --write \"{src,test}/**/*.{js,ts}\"",
27
+ "docs": "typedoc"
27
28
  },
28
29
  "main": "./dist/cjs/src/index.js",
29
30
  "module": "./dist/esm/src/index.js",
@@ -79,8 +80,8 @@
79
80
  "release-it": "^17.2.1",
80
81
  "ts-jest": "^28.0.8",
81
82
  "tsup": "^6.7.0",
82
- "typedoc": "^0.25.7",
83
- "typedoc-plugin-markdown": "^4.0.0-next.50",
83
+ "typedoc": "^0.28.0",
84
+ "typedoc-plugin-markdown": "^4.5.2",
84
85
  "typescript": "~5.3.3"
85
86
  },
86
87
  "engines": {
@@ -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 { Contract, } from 'ethers';
10
+ import { Contract } from 'ethers';
11
11
  import { MerkleDistributorABI } from './abi/MerkleDistributorWithDeadline';
12
12
  import { getProvider } from './utils';
13
13
  export const claimIncentivesFromMerkleDistributor = (incentivesData) => __awaiter(void 0, void 0, void 0, function* () {
@@ -9,8 +9,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { isContractAvailable } from './utils';
11
11
  import { FORK_NAMES, } from './types';
12
- import { claimIncentivesFromMerkleDistributor, isClaimedFromMerkleDistributor, } from './incentivesHalpers';
12
+ import { claimIncentivesFromMerkleDistributor, isClaimedFromMerkleDistributor, } from './incentiveHelpers';
13
13
  import { DEFAULT_BASE_VERSION } from './constants';
14
+ /**
15
+ * Incentives can be used for fetching and claiming Obol incentives.
16
+ * @class
17
+ * @internal Access it through Client.incentives.
18
+ * @example
19
+ * const obolClient = new Client(config);
20
+ * await obolClient.incentives.claimIncentives(address);
21
+ */
14
22
  export class Incentives {
15
23
  constructor(signer, chainId, request, provider) {
16
24
  this.signer = signer;
@@ -19,39 +27,49 @@ export class Incentives {
19
27
  this.provider = provider;
20
28
  }
21
29
  /**
22
- * Claims obol incentives from a Merkle Distributor contract.
30
+ * Claims Obol incentives from a Merkle Distributor contract using an address.
31
+ *
32
+ * This method automatically fetches incentive data and verifies whether the incentives have already been claimed.
33
+ * If `txHash` is `null`, it indicates that the incentives were already claimed.
34
+ *
35
+ * Note: This method is not yet enabled and will throw an error if called.
23
36
  *
24
37
  * @remarks
25
38
  * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
26
39
  * and not pushed to version control.
27
40
  *
28
- * @param {Object} incentivesData - The incentives data needed for claiming.
29
- * @param {string} incentivesData.contractAddress - The address of the Merkle Distributor contract.
30
- * @param {number} incentivesData.index - The index in the Merkle tree.
31
- * @param {string} incentivesData.operatorAddress - The address of the operator.
32
- * @param {number} incentivesData.amount - The amount to claim.
33
- * @param {string[]} incentivesData.merkleProof - The Merkle proof.
34
- * @returns {Promise<{ txHash: string }>} The transaction hash of the claim transaction.
35
- * @throws Will throw an error if the contract is not available or the claim fails.
41
+ * @param {string} address - The address to claim incentives for
42
+ * @returns {Promise<ClaimIncentivesResponse>} The transaction hash or already claimed status
43
+ * @throws Will throw an error if the incentives data is not found or the claim fails
36
44
  *
45
+ * An example of how to use claimIncentives:
46
+ * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L281)
37
47
  */
38
- claimIncentives(incentivesData) {
48
+ claimIncentives(address) {
39
49
  return __awaiter(this, void 0, void 0, function* () {
40
50
  if (!this.signer) {
41
51
  throw new Error('Signer is required in claimIncentives');
42
52
  }
43
53
  try {
44
- const isContractDeployed = yield isContractAvailable(incentivesData.contractAddress, this.signer.provider);
54
+ const incentivesData = yield this.getIncentivesByAddress(address);
55
+ if (!(incentivesData === null || incentivesData === void 0 ? void 0 : incentivesData.contract_address)) {
56
+ throw new Error(`No incentives found for address ${address}`);
57
+ }
58
+ const isContractDeployed = yield isContractAvailable(incentivesData.contract_address, this.provider);
45
59
  if (!isContractDeployed) {
46
- throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contractAddress}`);
60
+ throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contract_address}`);
61
+ }
62
+ const claimed = yield this.isClaimed(incentivesData.contract_address, incentivesData.index);
63
+ if (claimed) {
64
+ return { txHash: null };
47
65
  }
48
66
  const { txHash } = yield claimIncentivesFromMerkleDistributor({
49
67
  signer: this.signer,
50
- contractAddress: incentivesData.contractAddress,
68
+ contractAddress: incentivesData.contract_address,
51
69
  index: incentivesData.index,
52
- operatorAddress: incentivesData.operatorAddress,
70
+ operatorAddress: incentivesData.operator_address,
53
71
  amount: incentivesData.amount,
54
- merkleProof: incentivesData.merkleProof,
72
+ merkleProof: incentivesData.merkle_proof,
55
73
  });
56
74
  return { txHash };
57
75
  }
@@ -68,6 +86,9 @@ export class Incentives {
68
86
  * @param {ETH_ADDRESS} index - operator index in merkle tree
69
87
  * @returns {Promise<boolean>} true if incentives are already claime
70
88
  *
89
+ *
90
+ * An example of how to use isClaimed:
91
+ * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L266)
71
92
  */
72
93
  isClaimed(contractAddress, index) {
73
94
  return __awaiter(this, void 0, void 0, function* () {
@@ -78,6 +99,9 @@ export class Incentives {
78
99
  * @param address - Operator address
79
100
  * @returns {Promise<IncentivesType>} The matched incentives from DB
80
101
  * @throws On not found if address not found.
102
+ *
103
+ * An example of how to use getIncentivesByAddress:
104
+ * [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L250)
81
105
  */
82
106
  getIncentivesByAddress(address) {
83
107
  return __awaiter(this, void 0, void 0, function* () {
@@ -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';
@@ -22,6 +22,7 @@ export * from './types.js';
22
22
  export * from './services.js';
23
23
  export * from './verification/signature-validator.js';
24
24
  export * from './verification/common.js';
25
+ export { Incentives } from './incentives.js';
25
26
  /**
26
27
  * Obol sdk Client can be used for creating, managing and activating distributed validators.
27
28
  */
@@ -42,7 +43,7 @@ export class Client extends Base {
42
43
  // Use the provided provider, or fall back to signer.provider if available
43
44
  this.provider =
44
45
  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));
46
+ this.incentives = new Incentives(this.signer, this.chainId, this.request.bind(this), this.provider);
46
47
  }
47
48
  /**
48
49
  * Accepts Obol terms and conditions to be able to create or update data.
@@ -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 { Contract, Interface, parseEther, ZeroAddress, } from 'ethers';
10
+ import { Contract, Interface, parseEther, ZeroAddress } from 'ethers';
11
11
  import { OWRContract, OWRFactoryContract } from './abi/OWR';
12
12
  import { splitMainEthereumAbi } from './abi/SplitMain';
13
13
  import { MultiCallContract } from './abi/Multicall';
@@ -16,20 +16,11 @@ export var FORK_MAPPING;
16
16
  /** Hoodi Chain. */
17
17
  FORK_MAPPING[FORK_MAPPING["0x10000910"] = 560048] = "0x10000910";
18
18
  })(FORK_MAPPING || (FORK_MAPPING = {}));
19
- /**
20
- * Permitted Chain Names
21
- */
22
19
  export const FORK_NAMES = {
23
- /** Mainnet. */
24
20
  [FORK_MAPPING['0x00000000']]: 'mainnet',
25
- /** Goerli/Prater. */
26
21
  [FORK_MAPPING['0x00001020']]: 'goerli',
27
- /** Gnosis Chain. */
28
22
  [FORK_MAPPING['0x00000064']]: 'gnosis',
29
- /** Holesky. */
30
23
  [FORK_MAPPING['0x01017000']]: 'holesky',
31
- /** Sepolia. */
32
24
  [FORK_MAPPING['0x90000069']]: 'sepolia',
33
- /** Hoodi. */
34
25
  [FORK_MAPPING['0x10000910']]: 'hoodi',
35
26
  };