@obolnetwork/obol-sdk 2.4.2 → 2.4.4

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.2",
3
+ "version": "2.4.4",
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"
@@ -12,7 +12,7 @@ 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
17
  class Incentives {
18
18
  constructor(signer, chainId, request, provider) {
@@ -22,39 +22,42 @@ class Incentives {
22
22
  this.provider = provider;
23
23
  }
24
24
  /**
25
- * Claims obol incentives from a Merkle Distributor contract.
25
+ * Claims obol incentives from a Merkle Distributor contract using just an address.
26
+ * The method automatically fetches incentives data and checks if already claimed.
26
27
  *
27
28
  * @remarks
28
29
  * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
29
30
  * and not pushed to version control.
30
31
  *
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.
39
- *
32
+ * @param {string} address - The address to claim incentives for
33
+ * @returns {Promise<{ txHash: string } | { alreadyClaimed: true }>} The transaction hash or already claimed status
34
+ * @throws Will throw an error if the incentives data is not found or the claim fails
40
35
  */
41
- claimIncentives(incentivesData) {
36
+ claimIncentives(address) {
42
37
  return __awaiter(this, void 0, void 0, function* () {
43
38
  if (!this.signer) {
44
39
  throw new Error('Signer is required in claimIncentives');
45
40
  }
46
41
  try {
47
- const isContractDeployed = yield (0, utils_1.isContractAvailable)(incentivesData.contractAddress, this.signer.provider);
42
+ const incentivesData = yield this.getIncentivesByAddress(address);
43
+ if (!(incentivesData === null || incentivesData === void 0 ? void 0 : incentivesData.contract_address)) {
44
+ throw new Error(`No incentives found for address ${address}`);
45
+ }
46
+ const isContractDeployed = yield (0, utils_1.isContractAvailable)(incentivesData.contract_address, this.provider);
48
47
  if (!isContractDeployed) {
49
- throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contractAddress}`);
48
+ throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contract_address}`);
49
+ }
50
+ const claimed = yield this.isClaimed(incentivesData.contract_address, incentivesData.index);
51
+ if (claimed) {
52
+ return { alreadyClaimed: true };
50
53
  }
51
- const { txHash } = yield (0, incentivesHalpers_1.claimIncentivesFromMerkleDistributor)({
54
+ const { txHash } = yield (0, incentiveHelpers_1.claimIncentivesFromMerkleDistributor)({
52
55
  signer: this.signer,
53
- contractAddress: incentivesData.contractAddress,
56
+ contractAddress: incentivesData.contract_address,
54
57
  index: incentivesData.index,
55
- operatorAddress: incentivesData.operatorAddress,
58
+ operatorAddress: incentivesData.operator_address,
56
59
  amount: incentivesData.amount,
57
- merkleProof: incentivesData.merkleProof,
60
+ merkleProof: incentivesData.merkle_proof,
58
61
  });
59
62
  return { txHash };
60
63
  }
@@ -74,7 +77,7 @@ class Incentives {
74
77
  */
75
78
  isClaimed(contractAddress, index) {
76
79
  return __awaiter(this, void 0, void 0, function* () {
77
- return yield (0, incentivesHalpers_1.isClaimedFromMerkleDistributor)(this.chainId, contractAddress, index, this.provider);
80
+ return yield (0, incentiveHelpers_1.isClaimedFromMerkleDistributor)(this.chainId, contractAddress, index, this.provider);
78
81
  });
79
82
  }
80
83
  /**
@@ -59,7 +59,7 @@ class Client extends base_js_1.Base {
59
59
  // Use the provided provider, or fall back to signer.provider if available
60
60
  this.provider =
61
61
  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));
62
+ this.incentives = new incentives_js_1.Incentives(this.signer, this.chainId, this.request.bind(this), this.provider);
63
63
  }
64
64
  /**
65
65
  * Accepts Obol terms and conditions to be able to create or update data.
@@ -16,6 +16,8 @@ var FORK_MAPPING;
16
16
  FORK_MAPPING[FORK_MAPPING["0x01017000"] = 17000] = "0x01017000";
17
17
  /** Sepolia. */
18
18
  FORK_MAPPING[FORK_MAPPING["0x90000069"] = 11155111] = "0x90000069";
19
+ /** Hoodi Chain. */
20
+ FORK_MAPPING[FORK_MAPPING["0x10000910"] = 560048] = "0x10000910";
19
21
  })(FORK_MAPPING || (exports.FORK_MAPPING = FORK_MAPPING = {}));
20
22
  /**
21
23
  * Permitted Chain Names
@@ -31,4 +33,6 @@ exports.FORK_NAMES = {
31
33
  [FORK_MAPPING['0x01017000']]: 'holesky',
32
34
  /** Sepolia. */
33
35
  [FORK_MAPPING['0x90000069']]: 'sepolia',
36
+ /** Hoodi. */
37
+ [FORK_MAPPING['0x10000910']]: 'hoodi',
34
38
  };
@@ -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 alreadyClaimed 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({ alreadyClaimed: true });
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.2",
3
+ "version": "2.4.4",
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"
@@ -9,7 +9,7 @@ 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
14
  export class Incentives {
15
15
  constructor(signer, chainId, request, provider) {
@@ -19,39 +19,42 @@ export class Incentives {
19
19
  this.provider = provider;
20
20
  }
21
21
  /**
22
- * Claims obol incentives from a Merkle Distributor contract.
22
+ * Claims obol incentives from a Merkle Distributor contract using just an address.
23
+ * The method automatically fetches incentives data and checks if already claimed.
23
24
  *
24
25
  * @remarks
25
26
  * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
26
27
  * and not pushed to version control.
27
28
  *
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.
36
- *
29
+ * @param {string} address - The address to claim incentives for
30
+ * @returns {Promise<{ txHash: string } | { alreadyClaimed: true }>} The transaction hash or already claimed status
31
+ * @throws Will throw an error if the incentives data is not found or the claim fails
37
32
  */
38
- claimIncentives(incentivesData) {
33
+ claimIncentives(address) {
39
34
  return __awaiter(this, void 0, void 0, function* () {
40
35
  if (!this.signer) {
41
36
  throw new Error('Signer is required in claimIncentives');
42
37
  }
43
38
  try {
44
- const isContractDeployed = yield isContractAvailable(incentivesData.contractAddress, this.signer.provider);
39
+ const incentivesData = yield this.getIncentivesByAddress(address);
40
+ if (!(incentivesData === null || incentivesData === void 0 ? void 0 : incentivesData.contract_address)) {
41
+ throw new Error(`No incentives found for address ${address}`);
42
+ }
43
+ const isContractDeployed = yield isContractAvailable(incentivesData.contract_address, this.provider);
45
44
  if (!isContractDeployed) {
46
- throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contractAddress}`);
45
+ throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contract_address}`);
46
+ }
47
+ const claimed = yield this.isClaimed(incentivesData.contract_address, incentivesData.index);
48
+ if (claimed) {
49
+ return { alreadyClaimed: true };
47
50
  }
48
51
  const { txHash } = yield claimIncentivesFromMerkleDistributor({
49
52
  signer: this.signer,
50
- contractAddress: incentivesData.contractAddress,
53
+ contractAddress: incentivesData.contract_address,
51
54
  index: incentivesData.index,
52
- operatorAddress: incentivesData.operatorAddress,
55
+ operatorAddress: incentivesData.operator_address,
53
56
  amount: incentivesData.amount,
54
- merkleProof: incentivesData.merkleProof,
57
+ merkleProof: incentivesData.merkle_proof,
55
58
  });
56
59
  return { txHash };
57
60
  }
@@ -42,7 +42,7 @@ export class Client extends Base {
42
42
  // Use the provided provider, or fall back to signer.provider if available
43
43
  this.provider =
44
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));
45
+ this.incentives = new Incentives(this.signer, this.chainId, this.request.bind(this), this.provider);
46
46
  }
47
47
  /**
48
48
  * Accepts Obol terms and conditions to be able to create or update data.
@@ -13,6 +13,8 @@ export var FORK_MAPPING;
13
13
  FORK_MAPPING[FORK_MAPPING["0x01017000"] = 17000] = "0x01017000";
14
14
  /** Sepolia. */
15
15
  FORK_MAPPING[FORK_MAPPING["0x90000069"] = 11155111] = "0x90000069";
16
+ /** Hoodi Chain. */
17
+ FORK_MAPPING[FORK_MAPPING["0x10000910"] = 560048] = "0x10000910";
16
18
  })(FORK_MAPPING || (FORK_MAPPING = {}));
17
19
  /**
18
20
  * Permitted Chain Names
@@ -28,4 +30,6 @@ export const FORK_NAMES = {
28
30
  [FORK_MAPPING['0x01017000']]: 'holesky',
29
31
  /** Sepolia. */
30
32
  [FORK_MAPPING['0x90000069']]: 'sepolia',
33
+ /** Hoodi. */
34
+ [FORK_MAPPING['0x10000910']]: 'hoodi',
31
35
  };
@@ -11,23 +11,25 @@ var _a, _b;
11
11
  import { ethers, JsonRpcProvider } from 'ethers';
12
12
  import { Client } from '../src/index';
13
13
  import * as utils from '../src/utils';
14
- import * as incentivesHelpers from '../src/incentivesHalpers';
14
+ import * as incentivesHelpers from '../src/incentiveHelpers';
15
15
  import { DEFAULT_BASE_VERSION } from '../src/constants';
16
+ import { jest, describe, beforeEach, test, expect } from '@jest/globals';
16
17
  const mnemonic = (_b = (_a = ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
17
18
  const privateKey = ethers.Wallet.fromPhrase(mnemonic).privateKey;
18
19
  const provider = new JsonRpcProvider('https://ethereum-holesky.publicnode.com');
19
20
  const wallet = new ethers.Wallet(privateKey, provider);
20
21
  const mockSigner = wallet.connect(provider);
21
22
  const baseUrl = 'https://obol-api-dev.gcp.obol.tech';
23
+ // Fix the type error by properly typing the mock function
22
24
  global.fetch = jest.fn();
23
25
  describe('Client.incentives', () => {
24
26
  let clientInstance;
25
27
  const mockIncentivesData = {
26
- contractAddress: '0x1234567890abcdef1234567890abcdef12345678',
28
+ contract_address: '0x1234567890abcdef1234567890abcdef12345678',
27
29
  index: 5,
28
- operatorAddress: '0xabcdef1234567890abcdef1234567890abcdef12',
29
- amount: 1000000000000000000,
30
- merkleProof: [
30
+ operator_address: '0xabcdef1234567890abcdef1234567890abcdef12',
31
+ amount: '1000000000000000000',
32
+ merkle_proof: [
31
33
  '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
32
34
  '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
33
35
  ],
@@ -42,34 +44,61 @@ describe('Client.incentives', () => {
42
44
  baseUrl,
43
45
  chainId: 17000,
44
46
  });
45
- yield expect(clientWithoutSigner.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Signer is required in claimIncentives');
47
+ yield expect(clientWithoutSigner.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow('Signer is required in claimIncentives');
46
48
  }));
47
49
  test('claimIncentives should throw an error if contract is not available', () => __awaiter(void 0, void 0, void 0, function* () {
50
+ jest
51
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
52
+ .mockResolvedValue(mockIncentivesData);
53
+ jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(false);
48
54
  jest
49
55
  .spyOn(utils, 'isContractAvailable')
50
56
  .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}`);
57
+ yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow(`Merkle Distributor contract is not available at address ${mockIncentivesData.contract_address}`);
52
58
  }));
53
59
  test('claimIncentives should return txHash on successful claim', () => __awaiter(void 0, void 0, void 0, function* () {
54
60
  const mockTxHash = '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
61
+ jest
62
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
63
+ .mockResolvedValue(mockIncentivesData);
64
+ jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(false);
55
65
  jest
56
66
  .spyOn(utils, 'isContractAvailable')
57
67
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
58
68
  jest
59
69
  .spyOn(incentivesHelpers, 'claimIncentivesFromMerkleDistributor')
60
70
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve({ txHash: mockTxHash }); }));
61
- const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData);
71
+ const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address);
62
72
  expect(result).toEqual({ txHash: mockTxHash });
63
73
  expect(incentivesHelpers.claimIncentivesFromMerkleDistributor).toHaveBeenCalledWith({
64
74
  signer: mockSigner,
65
- contractAddress: mockIncentivesData.contractAddress,
75
+ contractAddress: mockIncentivesData.contract_address,
66
76
  index: mockIncentivesData.index,
67
- operatorAddress: mockIncentivesData.operatorAddress,
77
+ operatorAddress: mockIncentivesData.operator_address,
68
78
  amount: mockIncentivesData.amount,
69
- merkleProof: mockIncentivesData.merkleProof,
79
+ merkleProof: mockIncentivesData.merkle_proof,
70
80
  });
71
81
  }));
82
+ test('claimIncentives should return alreadyClaimed when incentives are already claimed', () => __awaiter(void 0, void 0, void 0, function* () {
83
+ jest
84
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
85
+ .mockResolvedValue(mockIncentivesData);
86
+ jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(true);
87
+ const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address);
88
+ expect(result).toEqual({ alreadyClaimed: true });
89
+ expect(incentivesHelpers.claimIncentivesFromMerkleDistributor).not.toHaveBeenCalled();
90
+ }));
91
+ test('claimIncentives should throw an error if no incentives found for address', () => __awaiter(void 0, void 0, void 0, function* () {
92
+ jest
93
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
94
+ .mockRejectedValue(new Error('No incentives found for address'));
95
+ yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow('Failed to claim incentives: No incentives found for address');
96
+ }));
72
97
  test('claimIncentives should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
98
+ jest
99
+ .spyOn(clientInstance.incentives, 'getIncentivesByAddress')
100
+ .mockResolvedValue(mockIncentivesData);
101
+ jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(false);
73
102
  jest
74
103
  .spyOn(utils, 'isContractAvailable')
75
104
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
@@ -78,7 +107,7 @@ describe('Client.incentives', () => {
78
107
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
79
108
  throw new Error('Helper function error');
80
109
  }));
81
- yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Failed to claim incentives: Helper function error');
110
+ yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address)).rejects.toThrow('Failed to claim incentives: Helper function error');
82
111
  }));
83
112
  test('incentives should be initialized with the same chainId as client', () => {
84
113
  const customChainId = 5;
@@ -89,15 +118,15 @@ describe('Client.incentives', () => {
89
118
  jest
90
119
  .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
91
120
  .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);
121
+ const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
93
122
  expect(result).toBe(true);
94
- expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientInstance.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index, undefined);
123
+ expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientInstance.incentives.chainId, mockIncentivesData.contract_address, mockIncentivesData.index, {});
95
124
  }));
96
125
  test('isClaimed should return false when incentive is not claimed', () => __awaiter(void 0, void 0, void 0, function* () {
97
126
  jest
98
127
  .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
99
128
  .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);
129
+ const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
101
130
  expect(result).toBe(false);
102
131
  }));
103
132
  test('isClaimed should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -106,10 +135,9 @@ describe('Client.incentives', () => {
106
135
  .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
107
136
  throw new Error('Helper function error');
108
137
  }));
109
- yield expect(clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index)).rejects.toThrow('Helper function error');
138
+ yield expect(clientInstance.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index)).rejects.toThrow('Helper function error');
110
139
  }));
111
140
  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
141
  const clientWithoutSigner = new Client({
114
142
  baseUrl,
115
143
  chainId: 17000,
@@ -117,9 +145,9 @@ describe('Client.incentives', () => {
117
145
  jest
118
146
  .spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
119
147
  .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);
148
+ const result = yield clientWithoutSigner.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
121
149
  expect(result).toBe(true);
122
- expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientWithoutSigner.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index, provider);
150
+ expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientWithoutSigner.incentives.chainId, mockIncentivesData.contract_address, mockIncentivesData.index, provider);
123
151
  }));
124
152
  test('getIncentivesByAddress should make the correct API request', () => __awaiter(void 0, void 0, void 0, function* () {
125
153
  const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
@@ -5,7 +5,7 @@ export declare const claimIncentivesFromMerkleDistributor: (incentivesData: {
5
5
  contractAddress: ETH_ADDRESS;
6
6
  index: number;
7
7
  operatorAddress: ETH_ADDRESS;
8
- amount: number;
8
+ amount: string;
9
9
  merkleProof: string[];
10
10
  }) => Promise<{
11
11
  txHash: string;
@@ -1,4 +1,4 @@
1
- import { type JsonRpcApiProvider, type JsonRpcProvider, type JsonRpcSigner, type Provider, type Signer } from 'ethers';
1
+ import type { JsonRpcApiProvider, JsonRpcProvider, JsonRpcSigner, Provider, Signer } from 'ethers';
2
2
  import { type Incentives as IncentivesType, type ETH_ADDRESS } from './types';
3
3
  export declare class Incentives {
4
4
  private readonly signer;
@@ -7,30 +7,21 @@ export declare class Incentives {
7
7
  readonly provider: Provider | JsonRpcProvider | JsonRpcApiProvider | undefined | null;
8
8
  constructor(signer: Signer | JsonRpcSigner | undefined, chainId: number, request: (endpoint: string, options?: RequestInit) => Promise<any>, provider: Provider | JsonRpcProvider | JsonRpcApiProvider | undefined | null);
9
9
  /**
10
- * Claims obol incentives from a Merkle Distributor contract.
10
+ * Claims obol incentives from a Merkle Distributor contract using just an address.
11
+ * The method automatically fetches incentives data and checks if already claimed.
11
12
  *
12
13
  * @remarks
13
14
  * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
14
15
  * and not pushed to version control.
15
16
  *
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
- *
17
+ * @param {string} address - The address to claim incentives for
18
+ * @returns {Promise<{ txHash: string } | { alreadyClaimed: true }>} The transaction hash or already claimed status
19
+ * @throws Will throw an error if the incentives data is not found or the claim fails
25
20
  */
26
- claimIncentives(incentivesData: {
27
- contractAddress: ETH_ADDRESS;
28
- index: number;
29
- operatorAddress: ETH_ADDRESS;
30
- amount: number;
31
- merkleProof: string[];
32
- }): Promise<{
21
+ claimIncentives(address: string): Promise<{
33
22
  txHash: string;
23
+ } | {
24
+ alreadyClaimed: true;
34
25
  }>;
35
26
  /**
36
27
  * Read isClaimed.
@@ -11,7 +11,9 @@ export declare enum FORK_MAPPING {
11
11
  /** Holesky. */
12
12
  '0x01017000' = 17000,
13
13
  /** Sepolia. */
14
- '0x90000069' = 11155111
14
+ '0x90000069' = 11155111,
15
+ /** Hoodi Chain. */
16
+ '0x10000910' = 560048
15
17
  }
16
18
  /**
17
19
  * Permitted Chain Names
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
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"
@@ -14,7 +14,7 @@ export const claimIncentivesFromMerkleDistributor = async (incentivesData: {
14
14
  contractAddress: ETH_ADDRESS;
15
15
  index: number;
16
16
  operatorAddress: ETH_ADDRESS;
17
- amount: number;
17
+ amount: string;
18
18
  merkleProof: string[];
19
19
  }): Promise<{ txHash: string }> => {
20
20
  try {
package/src/incentives.ts CHANGED
@@ -1,9 +1,9 @@
1
- import {
2
- type JsonRpcApiProvider,
3
- type JsonRpcProvider,
4
- type JsonRpcSigner,
5
- type Provider,
6
- type Signer,
1
+ import type {
2
+ JsonRpcApiProvider,
3
+ JsonRpcProvider,
4
+ JsonRpcSigner,
5
+ Provider,
6
+ Signer,
7
7
  } from 'ethers';
8
8
  import { isContractAvailable } from './utils';
9
9
  import {
@@ -14,7 +14,7 @@ import {
14
14
  import {
15
15
  claimIncentivesFromMerkleDistributor,
16
16
  isClaimedFromMerkleDistributor,
17
- } from './incentivesHalpers';
17
+ } from './incentiveHelpers';
18
18
  import { DEFAULT_BASE_VERSION } from './constants';
19
19
 
20
20
  export class Incentives {
@@ -50,51 +50,58 @@ export class Incentives {
50
50
  }
51
51
 
52
52
  /**
53
- * Claims obol incentives from a Merkle Distributor contract.
53
+ * Claims obol incentives from a Merkle Distributor contract using just an address.
54
+ * The method automatically fetches incentives data and checks if already claimed.
54
55
  *
55
56
  * @remarks
56
57
  * **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
57
58
  * and not pushed to version control.
58
59
  *
59
- * @param {Object} incentivesData - The incentives data needed for claiming.
60
- * @param {string} incentivesData.contractAddress - The address of the Merkle Distributor contract.
61
- * @param {number} incentivesData.index - The index in the Merkle tree.
62
- * @param {string} incentivesData.operatorAddress - The address of the operator.
63
- * @param {number} incentivesData.amount - The amount to claim.
64
- * @param {string[]} incentivesData.merkleProof - The Merkle proof.
65
- * @returns {Promise<{ txHash: string }>} The transaction hash of the claim transaction.
66
- * @throws Will throw an error if the contract is not available or the claim fails.
67
- *
60
+ * @param {string} address - The address to claim incentives for
61
+ * @returns {Promise<{ txHash: string } | { alreadyClaimed: true }>} The transaction hash or already claimed status
62
+ * @throws Will throw an error if the incentives data is not found or the claim fails
68
63
  */
69
- async claimIncentives(incentivesData: {
70
- contractAddress: ETH_ADDRESS;
71
- index: number;
72
- operatorAddress: ETH_ADDRESS;
73
- amount: number;
74
- merkleProof: string[];
75
- }): Promise<{ txHash: string }> {
64
+ async claimIncentives(
65
+ address: string,
66
+ ): Promise<{ txHash: string } | { alreadyClaimed: true }> {
76
67
  if (!this.signer) {
77
68
  throw new Error('Signer is required in claimIncentives');
78
69
  }
70
+
79
71
  try {
72
+ const incentivesData = await this.getIncentivesByAddress(address);
73
+
74
+ if (!incentivesData?.contract_address) {
75
+ throw new Error(`No incentives found for address ${address}`);
76
+ }
77
+
80
78
  const isContractDeployed = await isContractAvailable(
81
- incentivesData.contractAddress,
82
- this.signer.provider as Provider,
79
+ incentivesData.contract_address,
80
+ this.provider as Provider,
83
81
  );
84
82
 
85
83
  if (!isContractDeployed) {
86
84
  throw new Error(
87
- `Merkle Distributor contract is not available at address ${incentivesData.contractAddress}`,
85
+ `Merkle Distributor contract is not available at address ${incentivesData.contract_address}`,
88
86
  );
89
87
  }
90
88
 
89
+ const claimed = await this.isClaimed(
90
+ incentivesData.contract_address,
91
+ incentivesData.index,
92
+ );
93
+
94
+ if (claimed) {
95
+ return { alreadyClaimed: true };
96
+ }
97
+
91
98
  const { txHash } = await claimIncentivesFromMerkleDistributor({
92
99
  signer: this.signer,
93
- contractAddress: incentivesData.contractAddress,
100
+ contractAddress: incentivesData.contract_address,
94
101
  index: incentivesData.index,
95
- operatorAddress: incentivesData.operatorAddress,
102
+ operatorAddress: incentivesData.operator_address,
96
103
  amount: incentivesData.amount,
97
- merkleProof: incentivesData.merkleProof,
104
+ merkleProof: incentivesData.merkle_proof,
98
105
  });
99
106
 
100
107
  return { txHash };
package/src/index.ts CHANGED
@@ -98,7 +98,7 @@ export class Client extends Base {
98
98
  this.signer,
99
99
  this.chainId,
100
100
  this.request.bind(this),
101
- (this.provider = provider),
101
+ this.provider,
102
102
  );
103
103
  }
104
104
 
package/src/types.ts CHANGED
@@ -16,6 +16,9 @@ export enum FORK_MAPPING {
16
16
 
17
17
  /** Sepolia. */
18
18
  '0x90000069' = 11155111,
19
+
20
+ /** Hoodi Chain. */
21
+ '0x10000910' = 560048,
19
22
  }
20
23
 
21
24
  /**
@@ -36,6 +39,9 @@ export const FORK_NAMES: Record<number, string> = {
36
39
 
37
40
  /** Sepolia. */
38
41
  [FORK_MAPPING['0x90000069']]: 'sepolia',
42
+
43
+ /** Hoodi. */
44
+ [FORK_MAPPING['0x10000910']]: 'hoodi',
39
45
  };
40
46
 
41
47
  /**