@obolnetwork/obol-sdk 2.4.4 → 2.4.6
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/README.md +1 -1
- package/dist/cjs/package.json +6 -5
- package/dist/cjs/src/incentiveHelpers.js +2 -4
- package/dist/cjs/src/incentives.js +26 -5
- package/dist/cjs/src/index.js +3 -1
- package/dist/cjs/src/services.js +3 -2
- package/dist/cjs/src/types.js +0 -9
- package/dist/cjs/src/utils.js +4 -4
- package/dist/cjs/src/verification/common.js +12 -9
- package/dist/cjs/src/verification/signature-validator.js +6 -5
- package/dist/cjs/test/incentives.test.js +4 -4
- package/dist/cjs/test/methods.test.js +11 -0
- package/dist/esm/package.json +6 -5
- package/dist/esm/src/incentiveHelpers.js +3 -5
- package/dist/esm/src/incentives.js +26 -5
- package/dist/esm/src/index.js +2 -1
- package/dist/esm/src/services.js +3 -2
- package/dist/esm/src/splitHelpers.js +1 -1
- package/dist/esm/src/types.js +0 -9
- package/dist/esm/src/utils.js +4 -4
- package/dist/esm/src/verification/common.js +12 -9
- package/dist/esm/src/verification/signature-validator.js +6 -5
- package/dist/esm/test/incentives.test.js +4 -4
- package/dist/esm/test/methods.test.js +11 -0
- package/dist/types/src/incentiveHelpers.d.ts +3 -4
- package/dist/types/src/incentives.d.ts +29 -13
- package/dist/types/src/index.d.ts +15 -4
- package/dist/types/src/services.d.ts +3 -2
- package/dist/types/src/splitHelpers.d.ts +7 -8
- package/dist/types/src/types.d.ts +21 -5
- package/dist/types/src/utils.d.ts +5 -5
- package/dist/types/src/verification/common.d.ts +2 -2
- package/dist/types/src/verification/signature-validator.d.ts +5 -2
- package/package.json +6 -5
- package/src/incentiveHelpers.ts +5 -15
- package/src/incentives.ts +37 -33
- package/src/index.ts +27 -23
- package/src/services.ts +4 -2
- package/src/splitHelpers.ts +9 -14
- package/src/types.ts +37 -17
- package/src/utils.ts +11 -8
- package/src/verification/common.ts +13 -1
- package/src/verification/signature-validator.ts +10 -3
package/src/incentives.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
JsonRpcApiProvider,
|
|
3
|
-
JsonRpcProvider,
|
|
4
|
-
JsonRpcSigner,
|
|
5
|
-
Provider,
|
|
6
|
-
Signer,
|
|
7
|
-
} from 'ethers';
|
|
8
1
|
import { isContractAvailable } from './utils';
|
|
9
2
|
import {
|
|
10
|
-
type
|
|
3
|
+
type ClaimableIncentives,
|
|
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,
|
|
@@ -17,31 +13,29 @@ import {
|
|
|
17
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,20 +44,25 @@ export class Incentives {
|
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
/**
|
|
53
|
-
* Claims
|
|
54
|
-
*
|
|
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.
|
|
55
53
|
*
|
|
56
54
|
* @remarks
|
|
57
55
|
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
58
56
|
* and not pushed to version control.
|
|
59
57
|
*
|
|
60
58
|
* @param {string} address - The address to claim incentives for
|
|
61
|
-
* @returns {Promise<
|
|
59
|
+
* @returns {Promise<ClaimIncentivesResponse>} The transaction hash or already claimed status
|
|
62
60
|
* @throws Will throw an error if the incentives data is not found or the claim fails
|
|
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)
|
|
63
64
|
*/
|
|
64
|
-
async claimIncentives(
|
|
65
|
-
address: string,
|
|
66
|
-
): Promise<{ txHash: string } | { alreadyClaimed: true }> {
|
|
65
|
+
async claimIncentives(address: string): Promise<ClaimIncentivesResponse> {
|
|
67
66
|
if (!this.signer) {
|
|
68
67
|
throw new Error('Signer is required in claimIncentives');
|
|
69
68
|
}
|
|
@@ -77,7 +76,7 @@ export class Incentives {
|
|
|
77
76
|
|
|
78
77
|
const isContractDeployed = await isContractAvailable(
|
|
79
78
|
incentivesData.contract_address,
|
|
80
|
-
this.provider as
|
|
79
|
+
this.provider as ProviderType,
|
|
81
80
|
);
|
|
82
81
|
|
|
83
82
|
if (!isContractDeployed) {
|
|
@@ -92,7 +91,7 @@ export class Incentives {
|
|
|
92
91
|
);
|
|
93
92
|
|
|
94
93
|
if (claimed) {
|
|
95
|
-
return {
|
|
94
|
+
return { txHash: null };
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
const { txHash } = await claimIncentivesFromMerkleDistributor({
|
|
@@ -118,13 +117,15 @@ export class Incentives {
|
|
|
118
117
|
* @param {ETH_ADDRESS} index - operator index in merkle tree
|
|
119
118
|
* @returns {Promise<boolean>} true if incentives are already claime
|
|
120
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)
|
|
121
123
|
*/
|
|
122
124
|
async isClaimed(
|
|
123
125
|
contractAddress: ETH_ADDRESS,
|
|
124
126
|
index: number,
|
|
125
127
|
): Promise<boolean> {
|
|
126
128
|
return await isClaimedFromMerkleDistributor(
|
|
127
|
-
this.chainId,
|
|
128
129
|
contractAddress,
|
|
129
130
|
index,
|
|
130
131
|
this.provider,
|
|
@@ -135,10 +136,13 @@ export class Incentives {
|
|
|
135
136
|
* @param address - Operator address
|
|
136
137
|
* @returns {Promise<IncentivesType>} The matched incentives from DB
|
|
137
138
|
* @throws On not found if address not found.
|
|
139
|
+
*
|
|
140
|
+
* An example of how to use getIncentivesByAddress:
|
|
141
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L250)
|
|
138
142
|
*/
|
|
139
|
-
async getIncentivesByAddress(address: string): Promise<
|
|
143
|
+
async getIncentivesByAddress(address: string): Promise<ClaimableIncentives> {
|
|
140
144
|
const network = FORK_NAMES[this.chainId];
|
|
141
|
-
const incentives:
|
|
145
|
+
const incentives: ClaimableIncentives = await this.request(
|
|
142
146
|
`/${DEFAULT_BASE_VERSION}/address/incentives/${network}/${address}`,
|
|
143
147
|
{
|
|
144
148
|
method: 'GET',
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ZeroAddress,
|
|
3
|
-
type Provider,
|
|
4
|
-
type Signer,
|
|
5
|
-
type JsonRpcSigner,
|
|
6
|
-
type JsonRpcProvider,
|
|
7
|
-
type JsonRpcApiProvider,
|
|
8
|
-
} from 'ethers';
|
|
1
|
+
import { ZeroAddress } from 'ethers';
|
|
9
2
|
import { v4 as uuidv4 } from 'uuid';
|
|
10
3
|
import { Base } from './base.js';
|
|
11
4
|
import {
|
|
@@ -37,6 +30,8 @@ import {
|
|
|
37
30
|
type ClusterValidator,
|
|
38
31
|
type ETH_ADDRESS,
|
|
39
32
|
type OWRTranches,
|
|
33
|
+
type ProviderType,
|
|
34
|
+
type SignerType,
|
|
40
35
|
} from './types.js';
|
|
41
36
|
import { clusterConfigOrDefinitionHash } from './verification/common.js';
|
|
42
37
|
import { validatePayload } from './ajv.js';
|
|
@@ -59,19 +54,28 @@ export * from './types.js';
|
|
|
59
54
|
export * from './services.js';
|
|
60
55
|
export * from './verification/signature-validator.js';
|
|
61
56
|
export * from './verification/common.js';
|
|
57
|
+
export { Incentives } from './incentives.js';
|
|
62
58
|
|
|
63
59
|
/**
|
|
64
60
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
65
61
|
*/
|
|
66
62
|
export class Client extends Base {
|
|
67
|
-
|
|
63
|
+
/**
|
|
64
|
+
* The signer used for signing transactions.
|
|
65
|
+
*/
|
|
66
|
+
private readonly signer: SignerType | undefined;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The incentives module, responsible for managing Obol tokens distribution.
|
|
70
|
+
* @type {Incentives}
|
|
71
|
+
*/
|
|
68
72
|
public incentives: Incentives;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The blockchain provider, used to interact with the network.
|
|
76
|
+
* It can be null, undefined, or a valid provider instance and defaults to the Signer provider if Signer is passed.
|
|
77
|
+
*/
|
|
78
|
+
public provider: ProviderType | undefined | null;
|
|
75
79
|
|
|
76
80
|
/**
|
|
77
81
|
* @param config - Client configurations
|
|
@@ -85,8 +89,8 @@ export class Client extends Base {
|
|
|
85
89
|
*/
|
|
86
90
|
constructor(
|
|
87
91
|
config: { baseUrl?: string; chainId?: number },
|
|
88
|
-
signer?:
|
|
89
|
-
provider?:
|
|
92
|
+
signer?: SignerType,
|
|
93
|
+
provider?: ProviderType,
|
|
90
94
|
) {
|
|
91
95
|
super(config);
|
|
92
96
|
this.signer = signer;
|
|
@@ -201,19 +205,19 @@ export class Client extends Base {
|
|
|
201
205
|
|
|
202
206
|
const checkSplitMainAddress = await isContractAvailable(
|
|
203
207
|
CHAIN_CONFIGURATION[this.chainId].SPLITMAIN_ADDRESS.address,
|
|
204
|
-
this.signer.provider as
|
|
208
|
+
this.signer.provider as ProviderType,
|
|
205
209
|
CHAIN_CONFIGURATION[this.chainId].SPLITMAIN_ADDRESS.bytecode,
|
|
206
210
|
);
|
|
207
211
|
|
|
208
212
|
const checkMulticallAddress = await isContractAvailable(
|
|
209
213
|
CHAIN_CONFIGURATION[this.chainId].MULTICALL_ADDRESS.address,
|
|
210
|
-
this.signer.provider as
|
|
214
|
+
this.signer.provider as ProviderType,
|
|
211
215
|
CHAIN_CONFIGURATION[this.chainId].MULTICALL_ADDRESS.bytecode,
|
|
212
216
|
);
|
|
213
217
|
|
|
214
218
|
const checkOWRFactoryAddress = await isContractAvailable(
|
|
215
219
|
CHAIN_CONFIGURATION[this.chainId].OWR_FACTORY_ADDRESS.address,
|
|
216
|
-
this.signer.provider as
|
|
220
|
+
this.signer.provider as ProviderType,
|
|
217
221
|
CHAIN_CONFIGURATION[this.chainId].OWR_FACTORY_ADDRESS.bytecode,
|
|
218
222
|
);
|
|
219
223
|
|
|
@@ -251,7 +255,7 @@ export class Client extends Base {
|
|
|
251
255
|
|
|
252
256
|
const isSplitterDeployed = await isContractAvailable(
|
|
253
257
|
predictedSplitterAddress,
|
|
254
|
-
this.signer.provider as
|
|
258
|
+
this.signer.provider as ProviderType,
|
|
255
259
|
);
|
|
256
260
|
|
|
257
261
|
const { withdrawal_address, fee_recipient_address } =
|
|
@@ -316,7 +320,7 @@ export class Client extends Base {
|
|
|
316
320
|
|
|
317
321
|
const checkSplitMainAddress = await isContractAvailable(
|
|
318
322
|
CHAIN_CONFIGURATION[this.chainId].SPLITMAIN_ADDRESS.address,
|
|
319
|
-
this.signer.provider as
|
|
323
|
+
this.signer.provider as ProviderType,
|
|
320
324
|
CHAIN_CONFIGURATION[this.chainId].SPLITMAIN_ADDRESS.bytecode,
|
|
321
325
|
);
|
|
322
326
|
|
|
@@ -349,7 +353,7 @@ export class Client extends Base {
|
|
|
349
353
|
|
|
350
354
|
const isSplitterDeployed = await isContractAvailable(
|
|
351
355
|
predictedSplitterAddress,
|
|
352
|
-
this.signer.provider as
|
|
356
|
+
this.signer.provider as ProviderType,
|
|
353
357
|
);
|
|
354
358
|
|
|
355
359
|
if (!isSplitterDeployed) {
|
package/src/services.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { type ClusterLock } from './types.js';
|
|
1
|
+
import { type SafeRpcUrl, type ClusterLock } from './types.js';
|
|
2
2
|
import { isValidClusterLock } from './verification/common.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Verifies Cluster Lock's validity.
|
|
6
6
|
* @param lock - cluster lock
|
|
7
|
+
* @param safeRpcUrl - optional safeRpcUrl for safe wallet verification
|
|
7
8
|
* @returns {Promise<{ result: boolean }> } boolean result to indicate if lock is valid
|
|
8
9
|
* @throws on missing keys or values.
|
|
9
10
|
*
|
|
@@ -12,9 +13,10 @@ import { isValidClusterLock } from './verification/common.js';
|
|
|
12
13
|
*/
|
|
13
14
|
export const validateClusterLock = async (
|
|
14
15
|
lock: ClusterLock,
|
|
16
|
+
safeRpcUrl?: SafeRpcUrl,
|
|
15
17
|
): Promise<boolean> => {
|
|
16
18
|
try {
|
|
17
|
-
const isLockValid = await isValidClusterLock(lock);
|
|
19
|
+
const isLockValid = await isValidClusterLock(lock, safeRpcUrl);
|
|
18
20
|
return isLockValid;
|
|
19
21
|
} catch (err: any) {
|
|
20
22
|
throw err;
|
package/src/splitHelpers.ts
CHANGED
|
@@ -3,14 +3,9 @@ import {
|
|
|
3
3
|
type ClusterValidator,
|
|
4
4
|
type ETH_ADDRESS,
|
|
5
5
|
type SplitRecipient,
|
|
6
|
+
type SignerType,
|
|
6
7
|
} from './types';
|
|
7
|
-
import {
|
|
8
|
-
Contract,
|
|
9
|
-
Interface,
|
|
10
|
-
parseEther,
|
|
11
|
-
ZeroAddress,
|
|
12
|
-
type Signer,
|
|
13
|
-
} from 'ethers';
|
|
8
|
+
import { Contract, Interface, parseEther, ZeroAddress } from 'ethers';
|
|
14
9
|
import { OWRContract, OWRFactoryContract } from './abi/OWR';
|
|
15
10
|
import { splitMainEthereumAbi } from './abi/SplitMain';
|
|
16
11
|
import { MultiCallContract } from './abi/Multicall';
|
|
@@ -59,7 +54,7 @@ export const predictSplitterAddress = async ({
|
|
|
59
54
|
distributorFee,
|
|
60
55
|
controllerAddress,
|
|
61
56
|
}: {
|
|
62
|
-
signer:
|
|
57
|
+
signer: SignerType;
|
|
63
58
|
accounts: ETH_ADDRESS[];
|
|
64
59
|
percentAllocations: number[];
|
|
65
60
|
chainId: number;
|
|
@@ -111,7 +106,7 @@ export const handleDeployOWRAndSplitter = async ({
|
|
|
111
106
|
controllerAddress,
|
|
112
107
|
recoveryAddress,
|
|
113
108
|
}: {
|
|
114
|
-
signer:
|
|
109
|
+
signer: SignerType;
|
|
115
110
|
isSplitterDeployed: boolean;
|
|
116
111
|
predictedSplitterAddress: ETH_ADDRESS;
|
|
117
112
|
accounts: ETH_ADDRESS[];
|
|
@@ -174,7 +169,7 @@ const createOWRContract = async ({
|
|
|
174
169
|
chainId,
|
|
175
170
|
}: {
|
|
176
171
|
owrArgs: OWRArgs;
|
|
177
|
-
signer:
|
|
172
|
+
signer: SignerType;
|
|
178
173
|
chainId: number;
|
|
179
174
|
}): Promise<ETH_ADDRESS> => {
|
|
180
175
|
try {
|
|
@@ -209,7 +204,7 @@ export const deploySplitterContract = async ({
|
|
|
209
204
|
distributorFee,
|
|
210
205
|
controllerAddress,
|
|
211
206
|
}: {
|
|
212
|
-
signer:
|
|
207
|
+
signer: SignerType;
|
|
213
208
|
accounts: ETH_ADDRESS[];
|
|
214
209
|
percentAllocations: number[];
|
|
215
210
|
chainId: number;
|
|
@@ -247,7 +242,7 @@ export const deploySplitterAndOWRContracts = async ({
|
|
|
247
242
|
}: {
|
|
248
243
|
owrArgs: OWRArgs;
|
|
249
244
|
splitterArgs: SplitArgs;
|
|
250
|
-
signer:
|
|
245
|
+
signer: SignerType;
|
|
251
246
|
chainId: number;
|
|
252
247
|
}): Promise<{ owrAddress: ETH_ADDRESS; splitterAddress: ETH_ADDRESS }> => {
|
|
253
248
|
const executeCalls: Call[] = [];
|
|
@@ -304,7 +299,7 @@ export const getOWRTranches = async ({
|
|
|
304
299
|
signer,
|
|
305
300
|
}: {
|
|
306
301
|
owrAddress: ETH_ADDRESS;
|
|
307
|
-
signer:
|
|
302
|
+
signer: SignerType;
|
|
308
303
|
}): Promise<OWRTranches> => {
|
|
309
304
|
const owrContract = new Contract(owrAddress, OWRContract.abi, signer);
|
|
310
305
|
const res = await owrContract.getTranches();
|
|
@@ -318,7 +313,7 @@ export const getOWRTranches = async ({
|
|
|
318
313
|
|
|
319
314
|
export const multicall = async (
|
|
320
315
|
calls: Call[],
|
|
321
|
-
signer:
|
|
316
|
+
signer: SignerType,
|
|
322
317
|
multicallAddress: string,
|
|
323
318
|
): Promise<any> => {
|
|
324
319
|
const multiCallContractInstance = new Contract(
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Wallet,
|
|
3
|
+
type ethers,
|
|
4
|
+
type JsonRpcApiProvider,
|
|
5
|
+
type JsonRpcProvider,
|
|
6
|
+
type JsonRpcSigner,
|
|
7
|
+
type Provider,
|
|
8
|
+
type Signer,
|
|
9
|
+
} from 'ethers';
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Permitted ChainID's
|
|
3
13
|
*/
|
|
@@ -21,28 +31,14 @@ export enum FORK_MAPPING {
|
|
|
21
31
|
'0x10000910' = 560048,
|
|
22
32
|
}
|
|
23
33
|
|
|
24
|
-
/**
|
|
25
|
-
* Permitted Chain Names
|
|
26
|
-
*/
|
|
27
34
|
export const FORK_NAMES: Record<number, string> = {
|
|
28
|
-
/** Mainnet. */
|
|
29
35
|
[FORK_MAPPING['0x00000000']]: 'mainnet',
|
|
30
|
-
|
|
31
|
-
/** Goerli/Prater. */
|
|
32
36
|
[FORK_MAPPING['0x00001020']]: 'goerli',
|
|
33
|
-
|
|
34
|
-
/** Gnosis Chain. */
|
|
35
37
|
[FORK_MAPPING['0x00000064']]: 'gnosis',
|
|
36
|
-
|
|
37
|
-
/** Holesky. */
|
|
38
38
|
[FORK_MAPPING['0x01017000']]: 'holesky',
|
|
39
|
-
|
|
40
|
-
/** Sepolia. */
|
|
41
39
|
[FORK_MAPPING['0x90000069']]: 'sepolia',
|
|
42
|
-
|
|
43
|
-
/** Hoodi. */
|
|
44
40
|
[FORK_MAPPING['0x10000910']]: 'hoodi',
|
|
45
|
-
};
|
|
41
|
+
} as const;
|
|
46
42
|
|
|
47
43
|
/**
|
|
48
44
|
* Node operator data
|
|
@@ -300,9 +296,9 @@ export type ClusterLock = {
|
|
|
300
296
|
};
|
|
301
297
|
|
|
302
298
|
/**
|
|
303
|
-
* Incentives
|
|
299
|
+
* Claimable Obol Incentives
|
|
304
300
|
*/
|
|
305
|
-
export type
|
|
301
|
+
export type ClaimableIncentives = {
|
|
306
302
|
/** Operator Address. */
|
|
307
303
|
operator_address: string;
|
|
308
304
|
|
|
@@ -323,3 +319,27 @@ export type Incentives = {
|
|
|
323
319
|
* String expected to be Ethereum Address
|
|
324
320
|
*/
|
|
325
321
|
export type ETH_ADDRESS = string;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Provider Types
|
|
325
|
+
*/
|
|
326
|
+
export type ProviderType =
|
|
327
|
+
| Provider
|
|
328
|
+
| JsonRpcProvider
|
|
329
|
+
| JsonRpcApiProvider
|
|
330
|
+
| ethers.BrowserProvider;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Safe Wallet Provider Types
|
|
334
|
+
*/
|
|
335
|
+
export type SafeRpcUrl = string;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Signer Types
|
|
339
|
+
*/
|
|
340
|
+
export type SignerType = Signer | JsonRpcSigner | Wallet;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* claimIncentives Response
|
|
344
|
+
*/
|
|
345
|
+
export type ClaimIncentivesResponse = { txHash: string | null };
|
package/src/utils.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ethers
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
2
|
import { DefinitionFlow, PROVIDER_MAP } from './constants';
|
|
3
|
-
import { FORK_NAMES, type ClusterDefinition } from './types';
|
|
3
|
+
import { FORK_NAMES, type ProviderType, type ClusterDefinition } from './types';
|
|
4
4
|
|
|
5
5
|
export const hexWithout0x = (hex: string): string => {
|
|
6
6
|
return hex.slice(2, hex.length);
|
|
@@ -58,14 +58,14 @@ export const definitionFlow = (
|
|
|
58
58
|
|
|
59
59
|
export const findDeployedBytecode = async (
|
|
60
60
|
contractAddress: string,
|
|
61
|
-
provider:
|
|
61
|
+
provider: ProviderType,
|
|
62
62
|
): Promise<string> => {
|
|
63
63
|
return await provider?.getCode(contractAddress);
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
export const isContractAvailable = async (
|
|
67
67
|
contractAddress: string,
|
|
68
|
-
provider:
|
|
68
|
+
provider: ProviderType,
|
|
69
69
|
bytecode?: string,
|
|
70
70
|
): Promise<boolean> => {
|
|
71
71
|
const code = await findDeployedBytecode(contractAddress, provider);
|
|
@@ -76,10 +76,13 @@ export const isContractAvailable = async (
|
|
|
76
76
|
return !!code && code !== '0x' && code !== '0x0';
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
export const getProvider = (
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
export const getProvider = (
|
|
80
|
+
chainId: number,
|
|
81
|
+
rpcUrl?: string,
|
|
82
|
+
): ethers.JsonRpcProvider => {
|
|
83
|
+
const resolvedRpcUrl = rpcUrl ?? PROVIDER_MAP[chainId];
|
|
84
|
+
if (chainId && (!resolvedRpcUrl || resolvedRpcUrl === 'undefined')) {
|
|
82
85
|
throw new Error(`No provider configured for ${FORK_NAMES[chainId]}`);
|
|
83
86
|
}
|
|
84
|
-
return new ethers.JsonRpcProvider(
|
|
87
|
+
return new ethers.JsonRpcProvider(resolvedRpcUrl);
|
|
85
88
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { fromHexString } from '@chainsafe/ssz';
|
|
2
2
|
import elliptic from 'elliptic';
|
|
3
3
|
import { init } from '@chainsafe/bls';
|
|
4
|
-
|
|
5
4
|
import {
|
|
6
5
|
FORK_MAPPING,
|
|
7
6
|
type ClusterDefinition,
|
|
@@ -9,6 +8,7 @@ import {
|
|
|
9
8
|
type DepositData,
|
|
10
9
|
type BuilderRegistrationMessage,
|
|
11
10
|
type DistributedValidator,
|
|
11
|
+
type SafeRpcUrl,
|
|
12
12
|
} from '../types.js';
|
|
13
13
|
import * as semver from 'semver';
|
|
14
14
|
import {
|
|
@@ -167,6 +167,7 @@ const validatePOSTConfigHashSigner = async (
|
|
|
167
167
|
signature: string,
|
|
168
168
|
configHash: string,
|
|
169
169
|
chainId: FORK_MAPPING,
|
|
170
|
+
safeRpcUrl?: SafeRpcUrl,
|
|
170
171
|
): Promise<boolean> => {
|
|
171
172
|
try {
|
|
172
173
|
const data = signCreatorConfigHashPayload(
|
|
@@ -179,6 +180,7 @@ const validatePOSTConfigHashSigner = async (
|
|
|
179
180
|
token: signature,
|
|
180
181
|
data,
|
|
181
182
|
chainId,
|
|
183
|
+
safeRpcUrl,
|
|
182
184
|
});
|
|
183
185
|
} catch (err) {
|
|
184
186
|
throw err;
|
|
@@ -190,6 +192,7 @@ const validatePUTConfigHashSigner = async (
|
|
|
190
192
|
signature: string,
|
|
191
193
|
configHash: string,
|
|
192
194
|
chainId: number,
|
|
195
|
+
safeRpcUrl?: SafeRpcUrl,
|
|
193
196
|
): Promise<boolean> => {
|
|
194
197
|
try {
|
|
195
198
|
const data = signOperatorConfigHashPayload(
|
|
@@ -201,6 +204,7 @@ const validatePUTConfigHashSigner = async (
|
|
|
201
204
|
token: signature,
|
|
202
205
|
data,
|
|
203
206
|
chainId,
|
|
207
|
+
safeRpcUrl,
|
|
204
208
|
});
|
|
205
209
|
} catch (err) {
|
|
206
210
|
throw err;
|
|
@@ -212,6 +216,7 @@ const validateEnrSigner = async (
|
|
|
212
216
|
signature: string,
|
|
213
217
|
payload: string,
|
|
214
218
|
chainId: number,
|
|
219
|
+
safeRpcUrl?: SafeRpcUrl,
|
|
215
220
|
): Promise<boolean> => {
|
|
216
221
|
try {
|
|
217
222
|
const data = signEnrPayload({ enr: payload }, chainId);
|
|
@@ -221,6 +226,7 @@ const validateEnrSigner = async (
|
|
|
221
226
|
token: signature,
|
|
222
227
|
data,
|
|
223
228
|
chainId,
|
|
229
|
+
safeRpcUrl,
|
|
224
230
|
});
|
|
225
231
|
} catch (err) {
|
|
226
232
|
throw err;
|
|
@@ -230,6 +236,7 @@ const validateEnrSigner = async (
|
|
|
230
236
|
const verifyDefinitionSignatures = async (
|
|
231
237
|
clusterDefinition: ClusterDefinition,
|
|
232
238
|
definitionType: DefinitionFlow,
|
|
239
|
+
safeRpcUrl?: SafeRpcUrl,
|
|
233
240
|
): Promise<boolean> => {
|
|
234
241
|
if (definitionType === DefinitionFlow.Charon) {
|
|
235
242
|
return true;
|
|
@@ -239,6 +246,7 @@ const verifyDefinitionSignatures = async (
|
|
|
239
246
|
clusterDefinition.creator.config_signature as string,
|
|
240
247
|
clusterDefinition.config_hash,
|
|
241
248
|
FORK_MAPPING[clusterDefinition.fork_version as keyof typeof FORK_MAPPING],
|
|
249
|
+
safeRpcUrl,
|
|
242
250
|
);
|
|
243
251
|
|
|
244
252
|
if (!isPOSTConfigHashSignerValid) {
|
|
@@ -256,6 +264,7 @@ const verifyDefinitionSignatures = async (
|
|
|
256
264
|
FORK_MAPPING[
|
|
257
265
|
clusterDefinition.fork_version as keyof typeof FORK_MAPPING
|
|
258
266
|
],
|
|
267
|
+
safeRpcUrl,
|
|
259
268
|
);
|
|
260
269
|
|
|
261
270
|
const isENRSignerValid = await validateEnrSigner(
|
|
@@ -265,6 +274,7 @@ const verifyDefinitionSignatures = async (
|
|
|
265
274
|
FORK_MAPPING[
|
|
266
275
|
clusterDefinition.fork_version as keyof typeof FORK_MAPPING
|
|
267
276
|
],
|
|
277
|
+
safeRpcUrl,
|
|
268
278
|
);
|
|
269
279
|
|
|
270
280
|
if (!isPUTConfigHashSignerValid || !isENRSignerValid) {
|
|
@@ -485,6 +495,7 @@ const verifyLockData = async (clusterLock: ClusterLock): Promise<boolean> => {
|
|
|
485
495
|
|
|
486
496
|
export const isValidClusterLock = async (
|
|
487
497
|
clusterLock: ClusterLock,
|
|
498
|
+
safeRpcUrl?: SafeRpcUrl,
|
|
488
499
|
): Promise<boolean> => {
|
|
489
500
|
try {
|
|
490
501
|
const definitionType = definitionFlow(clusterLock.cluster_definition);
|
|
@@ -494,6 +505,7 @@ export const isValidClusterLock = async (
|
|
|
494
505
|
const isValidDefinitionData = await verifyDefinitionSignatures(
|
|
495
506
|
clusterLock.cluster_definition,
|
|
496
507
|
definitionType,
|
|
508
|
+
safeRpcUrl,
|
|
497
509
|
);
|
|
498
510
|
if (!isValidDefinitionData) {
|
|
499
511
|
return false;
|
|
@@ -10,20 +10,23 @@ import { PROVIDER_MAP } from '../constants';
|
|
|
10
10
|
import { hashTypedData } from '@safe-global/protocol-kit/dist/src/utils';
|
|
11
11
|
import { type EIP712TypedData } from '@safe-global/safe-core-sdk-types';
|
|
12
12
|
import { isContractAvailable, getProvider } from '../utils';
|
|
13
|
+
import { type SafeRpcUrl } from '../types';
|
|
13
14
|
|
|
14
15
|
export const validateAddressSignature = async ({
|
|
15
16
|
address,
|
|
16
17
|
token,
|
|
17
18
|
data,
|
|
18
19
|
chainId,
|
|
20
|
+
safeRpcUrl,
|
|
19
21
|
}: {
|
|
20
22
|
address: string;
|
|
21
23
|
token: string;
|
|
22
24
|
data: TypedMessage<any>;
|
|
23
25
|
chainId: number;
|
|
26
|
+
safeRpcUrl?: SafeRpcUrl;
|
|
24
27
|
}): Promise<boolean> => {
|
|
25
28
|
try {
|
|
26
|
-
const provider = getProvider(chainId);
|
|
29
|
+
const provider = getProvider(chainId, safeRpcUrl);
|
|
27
30
|
if (provider) {
|
|
28
31
|
const contractAddress = await isContractAvailable(address, provider);
|
|
29
32
|
if (contractAddress) {
|
|
@@ -32,6 +35,7 @@ export const validateAddressSignature = async ({
|
|
|
32
35
|
data: data as unknown as EIP712TypedData,
|
|
33
36
|
address,
|
|
34
37
|
chainId,
|
|
38
|
+
safeRpcUrl,
|
|
35
39
|
});
|
|
36
40
|
}
|
|
37
41
|
}
|
|
@@ -69,16 +73,19 @@ export const validateSmartContractSignature = async ({
|
|
|
69
73
|
data,
|
|
70
74
|
address,
|
|
71
75
|
chainId,
|
|
76
|
+
safeRpcUrl,
|
|
72
77
|
}: {
|
|
73
78
|
token: string;
|
|
74
79
|
data: EIP712TypedData;
|
|
75
80
|
address: string;
|
|
76
81
|
chainId: number;
|
|
82
|
+
safeRpcUrl?: SafeRpcUrl;
|
|
77
83
|
}): Promise<boolean> => {
|
|
78
84
|
try {
|
|
79
|
-
const
|
|
85
|
+
const safeProvider = safeRpcUrl ?? PROVIDER_MAP[chainId];
|
|
86
|
+
|
|
80
87
|
const protocolKit = await Safe.init({
|
|
81
|
-
provider,
|
|
88
|
+
provider: safeProvider,
|
|
82
89
|
safeAddress: address,
|
|
83
90
|
});
|
|
84
91
|
const messageHash = hashTypedData(data);
|