@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.
- package/dist/cjs/package.json +5 -4
- package/dist/cjs/src/incentives.js +42 -18
- package/dist/cjs/src/index.js +4 -2
- package/dist/cjs/src/types.js +0 -9
- package/dist/cjs/test/incentives.test.js +81 -53
- package/dist/esm/package.json +5 -4
- package/dist/esm/src/{incentivesHalpers.js → incentiveHelpers.js} +1 -1
- package/dist/esm/src/incentives.js +40 -16
- package/dist/esm/src/index.js +3 -2
- package/dist/esm/src/splitHelpers.js +1 -1
- package/dist/esm/src/types.js +0 -9
- package/dist/esm/test/incentives.test.js +47 -19
- package/dist/types/src/{incentivesHalpers.d.ts → incentiveHelpers.d.ts} +4 -5
- package/dist/types/src/incentives.d.ts +29 -22
- package/dist/types/src/index.d.ts +15 -4
- package/dist/types/src/splitHelpers.d.ts +7 -8
- package/dist/types/src/types.d.ts +15 -3
- package/dist/types/src/utils.d.ts +5 -5
- package/package.json +5 -4
- package/src/{incentivesHalpers.ts → incentiveHelpers.ts} +5 -11
- package/src/incentives.ts +56 -44
- package/src/index.ts +28 -24
- package/src/splitHelpers.ts +9 -14
- package/src/types.ts +29 -15
- package/src/utils.ts +5 -5
- /package/dist/cjs/src/{incentivesHalpers.js → incentiveHelpers.js} +0 -0
|
@@ -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/
|
|
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
|
-
|
|
28
|
+
contract_address: '0x1234567890abcdef1234567890abcdef12345678',
|
|
27
29
|
index: 5,
|
|
28
|
-
|
|
29
|
-
amount: 1000000000000000000,
|
|
30
|
-
|
|
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.
|
|
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.
|
|
75
|
+
contractAddress: mockIncentivesData.contract_address,
|
|
66
76
|
index: mockIncentivesData.index,
|
|
67
|
-
operatorAddress: mockIncentivesData.
|
|
77
|
+
operatorAddress: mockIncentivesData.operator_address,
|
|
68
78
|
amount: mockIncentivesData.amount,
|
|
69
|
-
merkleProof: mockIncentivesData.
|
|
79
|
+
merkleProof: mockIncentivesData.merkle_proof,
|
|
70
80
|
});
|
|
71
81
|
}));
|
|
82
|
+
test('claimIncentives should return txHash as null 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({ txHash: null });
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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';
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { type ETH_ADDRESS } from './types';
|
|
2
|
-
import { type JsonRpcApiProvider, type JsonRpcProvider, type Provider, type Signer } from 'ethers';
|
|
1
|
+
import { type ProviderType, type SignerType, type ETH_ADDRESS } from './types';
|
|
3
2
|
export declare const claimIncentivesFromMerkleDistributor: (incentivesData: {
|
|
4
|
-
signer:
|
|
3
|
+
signer: SignerType;
|
|
5
4
|
contractAddress: ETH_ADDRESS;
|
|
6
5
|
index: number;
|
|
7
6
|
operatorAddress: ETH_ADDRESS;
|
|
8
|
-
amount:
|
|
7
|
+
amount: string;
|
|
9
8
|
merkleProof: string[];
|
|
10
9
|
}) => Promise<{
|
|
11
10
|
txHash: string;
|
|
12
11
|
}>;
|
|
13
|
-
export declare const isClaimedFromMerkleDistributor: (chainId: number, contractAddress: ETH_ADDRESS, index: number, provider:
|
|
12
|
+
export declare const isClaimedFromMerkleDistributor: (chainId: number, contractAddress: ETH_ADDRESS, index: number, provider: ProviderType | undefined | null) => Promise<boolean>;
|
|
@@ -1,37 +1,38 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
1
|
+
import { type Incentives as IncentivesType, type ETH_ADDRESS, type ProviderType, type SignerType, type ClaimIncentivesResponse } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Incentives can be used for fetching and claiming Obol incentives.
|
|
4
|
+
* @class
|
|
5
|
+
* @internal Access it through Client.incentives.
|
|
6
|
+
* @example
|
|
7
|
+
* const obolClient = new Client(config);
|
|
8
|
+
* await obolClient.incentives.claimIncentives(address);
|
|
9
|
+
*/
|
|
3
10
|
export declare class Incentives {
|
|
4
11
|
private readonly signer;
|
|
5
12
|
readonly chainId: number;
|
|
6
13
|
private readonly request;
|
|
7
|
-
readonly provider:
|
|
8
|
-
constructor(signer:
|
|
14
|
+
readonly provider: ProviderType | undefined | null;
|
|
15
|
+
constructor(signer: SignerType | undefined, chainId: number, request: (endpoint: string, options?: RequestInit) => Promise<any>, provider: ProviderType | undefined | null);
|
|
9
16
|
/**
|
|
10
|
-
* Claims
|
|
17
|
+
* Claims Obol incentives from a Merkle Distributor contract using an address.
|
|
18
|
+
*
|
|
19
|
+
* This method automatically fetches incentive data and verifies whether the incentives have already been claimed.
|
|
20
|
+
* If `txHash` is `null`, it indicates that the incentives were already claimed.
|
|
21
|
+
*
|
|
22
|
+
* Note: This method is not yet enabled and will throw an error if called.
|
|
11
23
|
*
|
|
12
24
|
* @remarks
|
|
13
25
|
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
14
26
|
* and not pushed to version control.
|
|
15
27
|
*
|
|
16
|
-
* @param {
|
|
17
|
-
* @
|
|
18
|
-
* @
|
|
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.
|
|
28
|
+
* @param {string} address - The address to claim incentives for
|
|
29
|
+
* @returns {Promise<ClaimIncentivesResponse>} The transaction hash or already claimed status
|
|
30
|
+
* @throws Will throw an error if the incentives data is not found or the claim fails
|
|
24
31
|
*
|
|
32
|
+
* An example of how to use claimIncentives:
|
|
33
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L281)
|
|
25
34
|
*/
|
|
26
|
-
claimIncentives(
|
|
27
|
-
contractAddress: ETH_ADDRESS;
|
|
28
|
-
index: number;
|
|
29
|
-
operatorAddress: ETH_ADDRESS;
|
|
30
|
-
amount: number;
|
|
31
|
-
merkleProof: string[];
|
|
32
|
-
}): Promise<{
|
|
33
|
-
txHash: string;
|
|
34
|
-
}>;
|
|
35
|
+
claimIncentives(address: string): Promise<ClaimIncentivesResponse>;
|
|
35
36
|
/**
|
|
36
37
|
* Read isClaimed.
|
|
37
38
|
*
|
|
@@ -39,12 +40,18 @@ export declare class Incentives {
|
|
|
39
40
|
* @param {ETH_ADDRESS} index - operator index in merkle tree
|
|
40
41
|
* @returns {Promise<boolean>} true if incentives are already claime
|
|
41
42
|
*
|
|
43
|
+
*
|
|
44
|
+
* An example of how to use isClaimed:
|
|
45
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L266)
|
|
42
46
|
*/
|
|
43
47
|
isClaimed(contractAddress: ETH_ADDRESS, index: number): Promise<boolean>;
|
|
44
48
|
/**
|
|
45
49
|
* @param address - Operator address
|
|
46
50
|
* @returns {Promise<IncentivesType>} The matched incentives from DB
|
|
47
51
|
* @throws On not found if address not found.
|
|
52
|
+
*
|
|
53
|
+
* An example of how to use getIncentivesByAddress:
|
|
54
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L250)
|
|
48
55
|
*/
|
|
49
56
|
getIncentivesByAddress(address: string): Promise<IncentivesType>;
|
|
50
57
|
}
|
|
@@ -1,18 +1,29 @@
|
|
|
1
|
-
import { type Provider, type Signer, type JsonRpcSigner, type JsonRpcProvider, type JsonRpcApiProvider } from 'ethers';
|
|
2
1
|
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 } from './types.js';
|
|
2
|
+
import { type RewardsSplitPayload, type ClusterDefinition, type ClusterLock, type ClusterPayload, type OperatorPayload, type TotalSplitPayload, type ClusterValidator, type ETH_ADDRESS, type OWRTranches, type ProviderType, type SignerType } from './types.js';
|
|
4
3
|
import { Incentives } from './incentives.js';
|
|
5
4
|
export * from './types.js';
|
|
6
5
|
export * from './services.js';
|
|
7
6
|
export * from './verification/signature-validator.js';
|
|
8
7
|
export * from './verification/common.js';
|
|
8
|
+
export { Incentives } from './incentives.js';
|
|
9
9
|
/**
|
|
10
10
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
11
11
|
*/
|
|
12
12
|
export declare class Client extends Base {
|
|
13
|
+
/**
|
|
14
|
+
* The signer used for signing transactions.
|
|
15
|
+
*/
|
|
13
16
|
private readonly signer;
|
|
17
|
+
/**
|
|
18
|
+
* The incentives module, responsible for managing Obol tokens distribution.
|
|
19
|
+
* @type {Incentives}
|
|
20
|
+
*/
|
|
14
21
|
incentives: Incentives;
|
|
15
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The blockchain provider, used to interact with the network.
|
|
24
|
+
* It can be null, undefined, or a valid provider instance and defaults to the Signer provider if Signer is passed.
|
|
25
|
+
*/
|
|
26
|
+
provider: ProviderType | undefined | null;
|
|
16
27
|
/**
|
|
17
28
|
* @param config - Client configurations
|
|
18
29
|
* @param config.baseUrl - obol-api url
|
|
@@ -26,7 +37,7 @@ export declare class Client extends Base {
|
|
|
26
37
|
constructor(config: {
|
|
27
38
|
baseUrl?: string;
|
|
28
39
|
chainId?: number;
|
|
29
|
-
}, signer?:
|
|
40
|
+
}, signer?: SignerType, provider?: ProviderType);
|
|
30
41
|
/**
|
|
31
42
|
* Accepts Obol terms and conditions to be able to create or update data.
|
|
32
43
|
* @returns {Promise<string>} terms and conditions acceptance success message.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type OWRTranches, type ClusterValidator, type ETH_ADDRESS, type SplitRecipient } from './types';
|
|
2
|
-
import { type Signer } from 'ethers';
|
|
1
|
+
import { type OWRTranches, type ClusterValidator, type ETH_ADDRESS, type SplitRecipient, type SignerType } from './types';
|
|
3
2
|
type Call = {
|
|
4
3
|
target: ETH_ADDRESS;
|
|
5
4
|
callData: string;
|
|
@@ -21,7 +20,7 @@ export declare const formatSplitRecipients: (recipients: SplitRecipient[]) => {
|
|
|
21
20
|
percentAllocations: number[];
|
|
22
21
|
};
|
|
23
22
|
export declare const predictSplitterAddress: ({ signer, accounts, percentAllocations, chainId, distributorFee, controllerAddress, }: {
|
|
24
|
-
signer:
|
|
23
|
+
signer: SignerType;
|
|
25
24
|
accounts: ETH_ADDRESS[];
|
|
26
25
|
percentAllocations: number[];
|
|
27
26
|
chainId: number;
|
|
@@ -29,7 +28,7 @@ export declare const predictSplitterAddress: ({ signer, accounts, percentAllocat
|
|
|
29
28
|
controllerAddress: ETH_ADDRESS;
|
|
30
29
|
}) => Promise<ETH_ADDRESS>;
|
|
31
30
|
export declare const handleDeployOWRAndSplitter: ({ signer, isSplitterDeployed, predictedSplitterAddress, accounts, percentAllocations, etherAmount, principalRecipient, chainId, distributorFee, controllerAddress, recoveryAddress, }: {
|
|
32
|
-
signer:
|
|
31
|
+
signer: SignerType;
|
|
33
32
|
isSplitterDeployed: boolean;
|
|
34
33
|
predictedSplitterAddress: ETH_ADDRESS;
|
|
35
34
|
accounts: ETH_ADDRESS[];
|
|
@@ -42,7 +41,7 @@ export declare const handleDeployOWRAndSplitter: ({ signer, isSplitterDeployed,
|
|
|
42
41
|
recoveryAddress: ETH_ADDRESS;
|
|
43
42
|
}) => Promise<ClusterValidator>;
|
|
44
43
|
export declare const deploySplitterContract: ({ signer, accounts, percentAllocations, chainId, distributorFee, controllerAddress, }: {
|
|
45
|
-
signer:
|
|
44
|
+
signer: SignerType;
|
|
46
45
|
accounts: ETH_ADDRESS[];
|
|
47
46
|
percentAllocations: number[];
|
|
48
47
|
chainId: number;
|
|
@@ -52,7 +51,7 @@ export declare const deploySplitterContract: ({ signer, accounts, percentAllocat
|
|
|
52
51
|
export declare const deploySplitterAndOWRContracts: ({ owrArgs, splitterArgs, signer, chainId, }: {
|
|
53
52
|
owrArgs: OWRArgs;
|
|
54
53
|
splitterArgs: SplitArgs;
|
|
55
|
-
signer:
|
|
54
|
+
signer: SignerType;
|
|
56
55
|
chainId: number;
|
|
57
56
|
}) => Promise<{
|
|
58
57
|
owrAddress: ETH_ADDRESS;
|
|
@@ -60,7 +59,7 @@ export declare const deploySplitterAndOWRContracts: ({ owrArgs, splitterArgs, si
|
|
|
60
59
|
}>;
|
|
61
60
|
export declare const getOWRTranches: ({ owrAddress, signer, }: {
|
|
62
61
|
owrAddress: ETH_ADDRESS;
|
|
63
|
-
signer:
|
|
62
|
+
signer: SignerType;
|
|
64
63
|
}) => Promise<OWRTranches>;
|
|
65
|
-
export declare const multicall: (calls: Call[], signer:
|
|
64
|
+
export declare const multicall: (calls: Call[], signer: SignerType, multicallAddress: string) => Promise<any>;
|
|
66
65
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ethers, type JsonRpcApiProvider, type JsonRpcProvider, type JsonRpcSigner, type Provider, type Signer } from 'ethers';
|
|
1
2
|
/**
|
|
2
3
|
* Permitted ChainID's
|
|
3
4
|
*/
|
|
@@ -15,9 +16,6 @@ export declare enum FORK_MAPPING {
|
|
|
15
16
|
/** Hoodi Chain. */
|
|
16
17
|
'0x10000910' = 560048
|
|
17
18
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Permitted Chain Names
|
|
20
|
-
*/
|
|
21
19
|
export declare const FORK_NAMES: Record<number, string>;
|
|
22
20
|
/**
|
|
23
21
|
* Node operator data
|
|
@@ -232,3 +230,17 @@ export type Incentives = {
|
|
|
232
230
|
* String expected to be Ethereum Address
|
|
233
231
|
*/
|
|
234
232
|
export type ETH_ADDRESS = string;
|
|
233
|
+
/**
|
|
234
|
+
* Provider Types
|
|
235
|
+
*/
|
|
236
|
+
export type ProviderType = Provider | JsonRpcProvider | JsonRpcApiProvider | ethers.BrowserProvider;
|
|
237
|
+
/**
|
|
238
|
+
* Signer Types
|
|
239
|
+
*/
|
|
240
|
+
export type SignerType = Signer | JsonRpcSigner;
|
|
241
|
+
/**
|
|
242
|
+
* claimIncentives Response
|
|
243
|
+
*/
|
|
244
|
+
export type ClaimIncentivesResponse = {
|
|
245
|
+
txHash: string | null;
|
|
246
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ethers
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
2
|
import { DefinitionFlow } from './constants';
|
|
3
|
-
import { type ClusterDefinition } from './types';
|
|
3
|
+
import { type ProviderType, type ClusterDefinition } from './types';
|
|
4
4
|
export declare const hexWithout0x: (hex: string) => string;
|
|
5
5
|
export declare const strToUint8Array: (str: string) => Uint8Array;
|
|
6
6
|
export declare const definitionFlow: (clusterDefinition: ClusterDefinition) => DefinitionFlow | null;
|
|
7
|
-
export declare const findDeployedBytecode: (contractAddress: string, provider:
|
|
8
|
-
export declare const isContractAvailable: (contractAddress: string, provider:
|
|
9
|
-
export declare const getProvider: (chainId: number) => ethers.
|
|
7
|
+
export declare const findDeployedBytecode: (contractAddress: string, provider: ProviderType) => Promise<string>;
|
|
8
|
+
export declare const isContractAvailable: (contractAddress: string, provider: ProviderType, bytecode?: string) => Promise<boolean>;
|
|
9
|
+
export declare const getProvider: (chainId: number) => ethers.JsonRpcProvider;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obolnetwork/obol-sdk",
|
|
3
|
-
"version": "2.4.
|
|
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.
|
|
83
|
-
"typedoc-plugin-markdown": "^4.
|
|
83
|
+
"typedoc": "^0.28.0",
|
|
84
|
+
"typedoc-plugin-markdown": "^4.5.2",
|
|
84
85
|
"typescript": "~5.3.3"
|
|
85
86
|
},
|
|
86
87
|
"engines": {
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import { type ETH_ADDRESS } from './types';
|
|
2
|
-
import {
|
|
3
|
-
Contract,
|
|
4
|
-
type JsonRpcApiProvider,
|
|
5
|
-
type JsonRpcProvider,
|
|
6
|
-
type Provider,
|
|
7
|
-
type Signer,
|
|
8
|
-
} from 'ethers';
|
|
1
|
+
import { type ProviderType, type SignerType, type ETH_ADDRESS } from './types';
|
|
2
|
+
import { Contract } from 'ethers';
|
|
9
3
|
import { MerkleDistributorABI } from './abi/MerkleDistributorWithDeadline';
|
|
10
4
|
import { getProvider } from './utils';
|
|
11
5
|
|
|
12
6
|
export const claimIncentivesFromMerkleDistributor = async (incentivesData: {
|
|
13
|
-
signer:
|
|
7
|
+
signer: SignerType;
|
|
14
8
|
contractAddress: ETH_ADDRESS;
|
|
15
9
|
index: number;
|
|
16
10
|
operatorAddress: ETH_ADDRESS;
|
|
17
|
-
amount:
|
|
11
|
+
amount: string;
|
|
18
12
|
merkleProof: string[];
|
|
19
13
|
}): Promise<{ txHash: string }> => {
|
|
20
14
|
try {
|
|
@@ -44,7 +38,7 @@ export const isClaimedFromMerkleDistributor = async (
|
|
|
44
38
|
chainId: number,
|
|
45
39
|
contractAddress: ETH_ADDRESS,
|
|
46
40
|
index: number,
|
|
47
|
-
provider:
|
|
41
|
+
provider: ProviderType | undefined | null,
|
|
48
42
|
): Promise<boolean> => {
|
|
49
43
|
try {
|
|
50
44
|
const clientProvider = provider ?? getProvider(chainId);
|
package/src/incentives.ts
CHANGED
|
@@ -1,47 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type JsonRpcApiProvider,
|
|
3
|
-
type JsonRpcProvider,
|
|
4
|
-
type JsonRpcSigner,
|
|
5
|
-
type Provider,
|
|
6
|
-
type Signer,
|
|
7
|
-
} from 'ethers';
|
|
8
1
|
import { isContractAvailable } from './utils';
|
|
9
2
|
import {
|
|
10
3
|
type Incentives as IncentivesType,
|
|
11
4
|
type ETH_ADDRESS,
|
|
12
5
|
FORK_NAMES,
|
|
6
|
+
type ProviderType,
|
|
7
|
+
type SignerType,
|
|
8
|
+
type ClaimIncentivesResponse,
|
|
13
9
|
} from './types';
|
|
14
10
|
import {
|
|
15
11
|
claimIncentivesFromMerkleDistributor,
|
|
16
12
|
isClaimedFromMerkleDistributor,
|
|
17
|
-
} from './
|
|
13
|
+
} from './incentiveHelpers';
|
|
18
14
|
import { DEFAULT_BASE_VERSION } from './constants';
|
|
19
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Incentives can be used for fetching and claiming Obol incentives.
|
|
18
|
+
* @class
|
|
19
|
+
* @internal Access it through Client.incentives.
|
|
20
|
+
* @example
|
|
21
|
+
* const obolClient = new Client(config);
|
|
22
|
+
* await obolClient.incentives.claimIncentives(address);
|
|
23
|
+
*/
|
|
20
24
|
export class Incentives {
|
|
21
|
-
private readonly signer:
|
|
25
|
+
private readonly signer: SignerType | undefined;
|
|
22
26
|
public readonly chainId: number;
|
|
23
27
|
private readonly request: (
|
|
24
28
|
endpoint: string,
|
|
25
29
|
options?: RequestInit,
|
|
26
30
|
) => Promise<any>;
|
|
27
31
|
|
|
28
|
-
public readonly provider:
|
|
29
|
-
| Provider
|
|
30
|
-
| JsonRpcProvider
|
|
31
|
-
| JsonRpcApiProvider
|
|
32
|
-
| undefined
|
|
33
|
-
| null;
|
|
32
|
+
public readonly provider: ProviderType | undefined | null;
|
|
34
33
|
|
|
35
34
|
constructor(
|
|
36
|
-
signer:
|
|
35
|
+
signer: SignerType | undefined,
|
|
37
36
|
chainId: number,
|
|
38
37
|
request: (endpoint: string, options?: RequestInit) => Promise<any>,
|
|
39
|
-
provider:
|
|
40
|
-
| Provider
|
|
41
|
-
| JsonRpcProvider
|
|
42
|
-
| JsonRpcApiProvider
|
|
43
|
-
| undefined
|
|
44
|
-
| null,
|
|
38
|
+
provider: ProviderType | undefined | null,
|
|
45
39
|
) {
|
|
46
40
|
this.signer = signer;
|
|
47
41
|
this.chainId = chainId;
|
|
@@ -50,51 +44,63 @@ export class Incentives {
|
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
/**
|
|
53
|
-
* Claims
|
|
47
|
+
* Claims Obol incentives from a Merkle Distributor contract using an address.
|
|
48
|
+
*
|
|
49
|
+
* This method automatically fetches incentive data and verifies whether the incentives have already been claimed.
|
|
50
|
+
* If `txHash` is `null`, it indicates that the incentives were already claimed.
|
|
51
|
+
*
|
|
52
|
+
* Note: This method is not yet enabled and will throw an error if called.
|
|
54
53
|
*
|
|
55
54
|
* @remarks
|
|
56
55
|
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
57
56
|
* and not pushed to version control.
|
|
58
57
|
*
|
|
59
|
-
* @param {
|
|
60
|
-
* @
|
|
61
|
-
* @
|
|
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.
|
|
58
|
+
* @param {string} address - The address to claim incentives for
|
|
59
|
+
* @returns {Promise<ClaimIncentivesResponse>} The transaction hash or already claimed status
|
|
60
|
+
* @throws Will throw an error if the incentives data is not found or the claim fails
|
|
67
61
|
*
|
|
62
|
+
* An example of how to use claimIncentives:
|
|
63
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L281)
|
|
68
64
|
*/
|
|
69
|
-
async claimIncentives(
|
|
70
|
-
contractAddress: ETH_ADDRESS;
|
|
71
|
-
index: number;
|
|
72
|
-
operatorAddress: ETH_ADDRESS;
|
|
73
|
-
amount: number;
|
|
74
|
-
merkleProof: string[];
|
|
75
|
-
}): Promise<{ txHash: string }> {
|
|
65
|
+
async claimIncentives(address: string): Promise<ClaimIncentivesResponse> {
|
|
76
66
|
if (!this.signer) {
|
|
77
67
|
throw new Error('Signer is required in claimIncentives');
|
|
78
68
|
}
|
|
69
|
+
|
|
79
70
|
try {
|
|
71
|
+
const incentivesData = await this.getIncentivesByAddress(address);
|
|
72
|
+
|
|
73
|
+
if (!incentivesData?.contract_address) {
|
|
74
|
+
throw new Error(`No incentives found for address ${address}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
80
77
|
const isContractDeployed = await isContractAvailable(
|
|
81
|
-
incentivesData.
|
|
82
|
-
this.
|
|
78
|
+
incentivesData.contract_address,
|
|
79
|
+
this.provider as ProviderType,
|
|
83
80
|
);
|
|
84
81
|
|
|
85
82
|
if (!isContractDeployed) {
|
|
86
83
|
throw new Error(
|
|
87
|
-
`Merkle Distributor contract is not available at address ${incentivesData.
|
|
84
|
+
`Merkle Distributor contract is not available at address ${incentivesData.contract_address}`,
|
|
88
85
|
);
|
|
89
86
|
}
|
|
90
87
|
|
|
88
|
+
const claimed = await this.isClaimed(
|
|
89
|
+
incentivesData.contract_address,
|
|
90
|
+
incentivesData.index,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (claimed) {
|
|
94
|
+
return { txHash: null };
|
|
95
|
+
}
|
|
96
|
+
|
|
91
97
|
const { txHash } = await claimIncentivesFromMerkleDistributor({
|
|
92
98
|
signer: this.signer,
|
|
93
|
-
contractAddress: incentivesData.
|
|
99
|
+
contractAddress: incentivesData.contract_address,
|
|
94
100
|
index: incentivesData.index,
|
|
95
|
-
operatorAddress: incentivesData.
|
|
101
|
+
operatorAddress: incentivesData.operator_address,
|
|
96
102
|
amount: incentivesData.amount,
|
|
97
|
-
merkleProof: incentivesData.
|
|
103
|
+
merkleProof: incentivesData.merkle_proof,
|
|
98
104
|
});
|
|
99
105
|
|
|
100
106
|
return { txHash };
|
|
@@ -111,6 +117,9 @@ export class Incentives {
|
|
|
111
117
|
* @param {ETH_ADDRESS} index - operator index in merkle tree
|
|
112
118
|
* @returns {Promise<boolean>} true if incentives are already claime
|
|
113
119
|
*
|
|
120
|
+
*
|
|
121
|
+
* An example of how to use isClaimed:
|
|
122
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L266)
|
|
114
123
|
*/
|
|
115
124
|
async isClaimed(
|
|
116
125
|
contractAddress: ETH_ADDRESS,
|
|
@@ -128,6 +137,9 @@ export class Incentives {
|
|
|
128
137
|
* @param address - Operator address
|
|
129
138
|
* @returns {Promise<IncentivesType>} The matched incentives from DB
|
|
130
139
|
* @throws On not found if address not found.
|
|
140
|
+
*
|
|
141
|
+
* An example of how to use getIncentivesByAddress:
|
|
142
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L250)
|
|
131
143
|
*/
|
|
132
144
|
async getIncentivesByAddress(address: string): Promise<IncentivesType> {
|
|
133
145
|
const network = FORK_NAMES[this.chainId];
|