@obolnetwork/obol-sdk 2.11.9 → 2.11.10
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 +78 -2
- package/dist/browser/src/index.js +412 -294
- package/dist/browser/src/index.js.map +1 -1
- package/dist/cjs/src/index.js +415 -294
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/esm/src/index.js +412 -294
- package/dist/esm/src/index.js.map +1 -1
- package/dist/types/src/bytecodes.d.ts +0 -3
- package/dist/types/src/constants.d.ts +1 -2
- package/dist/types/src/eoa/eoa.d.ts +54 -43
- package/dist/types/src/errors.d.ts +23 -0
- package/dist/types/src/exits/exit.d.ts +16 -19
- package/dist/types/src/incentives/incentives.d.ts +59 -30
- package/dist/types/src/index.d.ts +262 -76
- package/dist/types/src/services.d.ts +22 -8
- package/dist/types/src/splits/splits.d.ts +100 -69
- package/dist/types/src/types.d.ts +63 -25
- package/dist/types/test/fixtures.d.ts +31 -122
- package/package.json +4 -4
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
import type { ProviderType, ExitClusterConfig, ExitValidationPayload, ExitValidationBlob, SignedExitValidationMessage, ExistingExitValidationBlobData, FullExitBlob } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Validates and verifies voluntary exit signatures for Obol distributed validators.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* for distributed validators in an Obol cluster. It handles both partial exit signatures
|
|
7
|
-
* from individual operators and payload signatures that authorize exit operations.
|
|
5
|
+
* Do not instantiate directly; access via `client.exit`.
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
7
|
+
* Available methods:
|
|
8
|
+
* - {@link Exit.verifyPartialExitSignature} – verify a BLS partial exit signature
|
|
9
|
+
* - {@link Exit.verifyExitPayloadSignature} – verify an ECDSA exit payload signature
|
|
10
|
+
* - {@link Exit.validateExitBlobs} – validate exit blobs against cluster config
|
|
11
|
+
* - {@link Exit.recombineExitBlobs} – aggregate partial signatures into a full exit blob
|
|
12
|
+
*
|
|
13
|
+
* All methods are read-only (no on-chain transactions). No signer is required.
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
16
|
* ```typescript
|
|
17
|
-
* const
|
|
17
|
+
* const client = new Client({ chainId: 1 }, signer, provider);
|
|
18
18
|
*
|
|
19
19
|
* // Verify a partial exit signature
|
|
20
|
-
* const isValid = await exit.verifyPartialExitSignature(
|
|
20
|
+
* const isValid = await client.exit.verifyPartialExitSignature(
|
|
21
21
|
* publicShareKey,
|
|
22
22
|
* signedExitMessage,
|
|
23
23
|
* forkVersion,
|
|
24
|
-
* genesisValidatorsRoot
|
|
24
|
+
* genesisValidatorsRoot,
|
|
25
25
|
* );
|
|
26
26
|
*
|
|
27
27
|
* // Validate exit blobs for a cluster
|
|
28
|
-
* const validBlobs = await exit.validateExitBlobs(
|
|
28
|
+
* const validBlobs = await client.exit.validateExitBlobs(
|
|
29
29
|
* clusterConfig,
|
|
30
30
|
* exitsPayload,
|
|
31
31
|
* beaconNodeApiUrl,
|
|
32
|
-
* existingBlobData
|
|
32
|
+
* existingBlobData,
|
|
33
33
|
* );
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
@@ -44,11 +44,8 @@ export declare class Exit {
|
|
|
44
44
|
*
|
|
45
45
|
* @example
|
|
46
46
|
* ```typescript
|
|
47
|
-
*
|
|
48
|
-
* const exit =
|
|
49
|
-
*
|
|
50
|
-
* // For goerli testnet without provider
|
|
51
|
-
* const exit = new Exit(5, null);
|
|
47
|
+
* const client = new Client({ chainId: 1 }, signer, provider);
|
|
48
|
+
* const exit = client.exit; // Access via client, do not instantiate directly
|
|
52
49
|
* ```
|
|
53
50
|
*/
|
|
54
51
|
constructor(chainId: number, provider: ProviderType | undefined | null);
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import { type ClaimableIncentives, type ETH_ADDRESS, type ProviderType, type SignerType, type ClaimIncentivesResponse } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Manages Obol incentive rewards – querying eligibility and claiming from
|
|
4
|
+
* on-chain Merkle Distributor contracts.
|
|
5
|
+
*
|
|
6
|
+
* Do not instantiate directly; access via `client.incentives`.
|
|
7
|
+
*
|
|
6
8
|
* @example
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const client = new Client({ chainId: 560048 }, signer);
|
|
11
|
+
*
|
|
12
|
+
* // Check claimable incentives
|
|
13
|
+
* const data = await client.incentives.getIncentivesByAddress("0xOperator...");
|
|
14
|
+
*
|
|
15
|
+
* // Check if already claimed
|
|
16
|
+
* const claimed = await client.incentives.isClaimed(data.contract_address, data.index);
|
|
17
|
+
*
|
|
18
|
+
* // Claim (sends on-chain transaction)
|
|
19
|
+
* const { txHash } = await client.incentives.claimIncentives("0xOperator...");
|
|
20
|
+
* ```
|
|
9
21
|
*/
|
|
10
22
|
export declare class Incentives {
|
|
11
23
|
private readonly signer;
|
|
@@ -14,44 +26,61 @@ export declare class Incentives {
|
|
|
14
26
|
readonly provider: ProviderType | undefined | null;
|
|
15
27
|
constructor(signer: SignerType | undefined, chainId: number, request: (endpoint: string, options?: RequestInit) => Promise<any>, provider: ProviderType | undefined | null);
|
|
16
28
|
/**
|
|
17
|
-
* Claims Obol incentives from a Merkle Distributor contract
|
|
29
|
+
* Claims Obol incentives from a Merkle Distributor contract for the given address.
|
|
18
30
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
31
|
+
* Automatically fetches incentive data, checks if already claimed, and submits
|
|
32
|
+
* the on-chain claim transaction. Returns `{ txHash: null }` if incentives were
|
|
33
|
+
* already claimed (idempotent).
|
|
21
34
|
*
|
|
22
|
-
*
|
|
35
|
+
* @param address - The operator's Ethereum address to claim incentives for.
|
|
36
|
+
* @returns The transaction hash, or `{ txHash: null }` if already claimed.
|
|
37
|
+
* @throws {SignerRequiredError} If no signer was provided.
|
|
38
|
+
* @throws {Error} If no incentives are found for the address.
|
|
23
39
|
*
|
|
24
|
-
* @
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L281)
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const { txHash } = await client.incentives.claimIncentives("0xOperator...");
|
|
43
|
+
* if (txHash) {
|
|
44
|
+
* console.log("Claimed:", txHash);
|
|
45
|
+
* } else {
|
|
46
|
+
* console.log("Already claimed");
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
34
49
|
*/
|
|
35
50
|
claimIncentives(address: string): Promise<ClaimIncentivesResponse>;
|
|
36
51
|
/**
|
|
37
|
-
*
|
|
52
|
+
* Checks whether incentives have already been claimed for a given operator index.
|
|
38
53
|
*
|
|
39
|
-
*
|
|
40
|
-
* @param {ETH_ADDRESS} index - operator index in merkle tree
|
|
41
|
-
* @returns {Promise<boolean>} true if incentives are already claime
|
|
54
|
+
* Read-only on-chain call – no transaction sent.
|
|
42
55
|
*
|
|
56
|
+
* @param contractAddress - Address of the Merkle Distributor contract.
|
|
57
|
+
* @param index - The operator's index in the Merkle tree (from {@link Incentives.getIncentivesByAddress}).
|
|
58
|
+
* @returns `true` if the incentives at that index have already been claimed.
|
|
43
59
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const claimed = await client.incentives.isClaimed(
|
|
63
|
+
* "0xMerkleDistributor...",
|
|
64
|
+
* 42,
|
|
65
|
+
* );
|
|
66
|
+
* ```
|
|
46
67
|
*/
|
|
47
68
|
isClaimed(contractAddress: ETH_ADDRESS, index: number): Promise<boolean>;
|
|
48
69
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
70
|
+
* Fetches claimable incentive data for an operator address from the Obol API.
|
|
71
|
+
*
|
|
72
|
+
* The returned data includes the Merkle proof, amount, and contract address
|
|
73
|
+
* needed to claim on-chain. This is a read-only API call.
|
|
74
|
+
*
|
|
75
|
+
* @param address - The operator's Ethereum address.
|
|
76
|
+
* @returns Claimable incentive data including amount, Merkle proof, and contract address.
|
|
77
|
+
* @throws {Error} If no incentives are found for the given address (404).
|
|
52
78
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const incentives = await client.incentives.getIncentivesByAddress("0xOperator...");
|
|
82
|
+
* console.log(incentives.amount, incentives.contract_address);
|
|
83
|
+
* ```
|
|
55
84
|
*/
|
|
56
85
|
getIncentivesByAddress(address: string): Promise<ClaimableIncentives>;
|
|
57
86
|
}
|
|
@@ -9,150 +9,336 @@ export * from './services.js';
|
|
|
9
9
|
export * from './verification/signature-validator.js';
|
|
10
10
|
export * from './verification/common.js';
|
|
11
11
|
export * from './constants.js';
|
|
12
|
+
export { ConflictError, SignerRequiredError, UnsupportedChainError, } from './errors.js';
|
|
12
13
|
export { Incentives } from './incentives/incentives.js';
|
|
13
14
|
export { Exit } from './exits/exit.js';
|
|
14
15
|
export { ObolSplits } from './splits/splits.js';
|
|
15
16
|
export { EOA } from './eoa/eoa.js';
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* Primary entrypoint for the Obol SDK. Use this class to create, manage,
|
|
19
|
+
* and activate Distributed Validators via the Obol API.
|
|
20
|
+
*
|
|
21
|
+
* All operations are namespaced under the client instance:
|
|
22
|
+
* - `client.incentives.*` – claim and query Obol incentives
|
|
23
|
+
* - `client.exit.*` – validate and recombine voluntary exit signatures
|
|
24
|
+
* - `client.splits.*` – deploy OVM / SplitV2 reward-splitting contracts
|
|
25
|
+
* - `client.eoa.*` – EOA withdrawals and batch deposits
|
|
26
|
+
*
|
|
27
|
+
* Cluster lifecycle helpers live directly on the client:
|
|
28
|
+
* - {@link Client.acceptObolLatestTermsAndConditions}
|
|
29
|
+
* - {@link Client.createClusterDefinition}
|
|
30
|
+
* - {@link Client.acceptClusterDefinition}
|
|
31
|
+
* - {@link Client.getClusterDefinition}
|
|
32
|
+
* - {@link Client.getClusterLock}
|
|
33
|
+
* - {@link Client.getClusterLockByHash}
|
|
34
|
+
* - {@link Client.createObolRewardsSplit}
|
|
35
|
+
* - {@link Client.createObolTotalSplit}
|
|
36
|
+
* - {@link Client.getOWRTranches}
|
|
37
|
+
*
|
|
38
|
+
* Supported networks (by `chainId`): Mainnet (1), Hoodi (560048),
|
|
39
|
+
* Gnosis (100), Sepolia (11155111).
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { Client } from "@obolnetwork/obol-sdk";
|
|
44
|
+
* import { Wallet } from "ethers";
|
|
45
|
+
*
|
|
46
|
+
* const signer = new Wallet(process.env.PRIVATE_KEY!);
|
|
47
|
+
* const client = new Client({ chainId: 560048 }, signer);
|
|
48
|
+
*
|
|
49
|
+
* // 1. Accept terms (required once before creating/updating data)
|
|
50
|
+
* await client.acceptObolLatestTermsAndConditions();
|
|
51
|
+
*
|
|
52
|
+
* // 2. Create a cluster definition
|
|
53
|
+
* const configHash = await client.createClusterDefinition({
|
|
54
|
+
* name: "my-cluster",
|
|
55
|
+
* operators: [{ address: "0x..." }],
|
|
56
|
+
* validators: [{
|
|
57
|
+
* fee_recipient_address: "0x...",
|
|
58
|
+
* withdrawal_address: "0x...",
|
|
59
|
+
* }],
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* // 3. Retrieve the definition
|
|
63
|
+
* const def = await client.getClusterDefinition(configHash);
|
|
64
|
+
* ```
|
|
18
65
|
*/
|
|
19
66
|
export declare class Client extends Base {
|
|
20
|
-
/**
|
|
21
|
-
* The signer used for signing transactions.
|
|
22
|
-
*/
|
|
23
67
|
private readonly signer;
|
|
24
68
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
69
|
+
* Incentives module – claim and query Obol incentive rewards.
|
|
70
|
+
*
|
|
71
|
+
* @see {@link Incentives}
|
|
27
72
|
*/
|
|
28
73
|
incentives: Incentives;
|
|
29
74
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
75
|
+
* Exit module – verify partial exit signatures and recombine exit blobs
|
|
76
|
+
* for distributed validator voluntary exits.
|
|
77
|
+
*
|
|
78
|
+
* @see {@link Exit}
|
|
32
79
|
*/
|
|
33
80
|
exit: Exit;
|
|
34
81
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
82
|
+
* Splits module – deploy OVM and SplitV2 contracts for reward/principal
|
|
83
|
+
* splitting, request withdrawals, and deposit to OVM contracts.
|
|
84
|
+
*
|
|
85
|
+
* @see {@link ObolSplits}
|
|
37
86
|
*/
|
|
38
87
|
splits: ObolSplits;
|
|
39
88
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
89
|
+
* EOA module – request withdrawals and batch-deposit validators
|
|
90
|
+
* via Externally Owned Account contracts.
|
|
91
|
+
*
|
|
92
|
+
* @see {@link EOA}
|
|
42
93
|
*/
|
|
43
94
|
eoa: EOA;
|
|
44
95
|
/**
|
|
45
|
-
* The blockchain provider
|
|
46
|
-
*
|
|
96
|
+
* The blockchain provider used for on-chain reads.
|
|
97
|
+
* Defaults to `signer.provider` when a signer is supplied.
|
|
47
98
|
*/
|
|
48
99
|
provider: ProviderType | undefined | null;
|
|
49
100
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* @param config
|
|
53
|
-
* @param
|
|
54
|
-
* @
|
|
55
|
-
*
|
|
56
|
-
* An
|
|
57
|
-
*
|
|
101
|
+
* Creates a new Obol SDK client.
|
|
102
|
+
*
|
|
103
|
+
* @param config - Client configuration object.
|
|
104
|
+
* @param config.baseUrl - Obol API base URL. Defaults to `https://api.obol.tech`.
|
|
105
|
+
* @param config.chainId - Target chain ID. Defaults to `560048` (Hoodi).
|
|
106
|
+
* Supported: 1 (Mainnet), 560048 (Hoodi), 100 (Gnosis), 11155111 (Sepolia).
|
|
107
|
+
* @param signer - An ethers `Wallet` or `JsonRpcSigner`. Required for any
|
|
108
|
+
* write operation (creating clusters, deploying splits, claiming incentives).
|
|
109
|
+
* Read-only operations (`getClusterDefinition`, `getClusterLock`) work without a signer.
|
|
110
|
+
* @param provider - An ethers `Provider`. If omitted, falls back to `signer.provider`.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Minimal read-only client (no signer)
|
|
115
|
+
* const readClient = new Client({ chainId: 1 });
|
|
116
|
+
* const def = await readClient.getClusterDefinition(configHash);
|
|
117
|
+
*
|
|
118
|
+
* // Full client with signer for write operations
|
|
119
|
+
* const client = new Client({ chainId: 560048 }, signer);
|
|
120
|
+
* ```
|
|
58
121
|
*/
|
|
59
122
|
constructor(config: {
|
|
60
123
|
baseUrl?: string;
|
|
61
124
|
chainId?: number;
|
|
62
125
|
}, signer?: SignerType, provider?: ProviderType);
|
|
63
126
|
/**
|
|
64
|
-
* Accepts Obol terms and conditions
|
|
65
|
-
*
|
|
66
|
-
*
|
|
127
|
+
* Accepts the latest Obol terms and conditions.
|
|
128
|
+
*
|
|
129
|
+
* **Must be called once** before any write operation
|
|
130
|
+
* (`createClusterDefinition`, `acceptClusterDefinition`, etc.).
|
|
131
|
+
* Calling it again after acceptance throws a {@link ConflictError}.
|
|
132
|
+
*
|
|
133
|
+
* - Requires a `signer` to be provided at client construction.
|
|
134
|
+
* - Signs an EIP-712 typed-data message; no on-chain transaction is sent.
|
|
135
|
+
* - Idempotent per signer address: once accepted, subsequent calls throw `ConflictError`.
|
|
67
136
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
137
|
+
* @returns A success message string from the Obol API.
|
|
138
|
+
* @throws {SignerRequiredError} If no signer was provided to the client.
|
|
139
|
+
* @throws {ConflictError} If the terms were already accepted by this address.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const message = await client.acceptObolLatestTermsAndConditions();
|
|
144
|
+
* console.log(message); // "Terms and conditions accepted successfully"
|
|
145
|
+
* ```
|
|
70
146
|
*/
|
|
71
147
|
acceptObolLatestTermsAndConditions(): Promise<string>;
|
|
72
148
|
/**
|
|
73
|
-
* Deploys OWR and Splitter Proxy.
|
|
149
|
+
* Deploys an Optimistic Withdrawal Recipient (OWR) and a Splitter Proxy contract.
|
|
150
|
+
*
|
|
151
|
+
* Use this when the **principal** goes to a single address and only **rewards**
|
|
152
|
+
* are split among recipients. For splitting both principal and rewards, see
|
|
153
|
+
* {@link Client.createObolTotalSplit}.
|
|
74
154
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
155
|
+
* - Requires a `signer` with ETH to pay deployment gas.
|
|
156
|
+
* - Sends one or more on-chain transactions (irreversible).
|
|
157
|
+
* - Automatically appends the Obol Retroactive Funding (RAF) recipient at the
|
|
158
|
+
* configured percentage (default 1%).
|
|
159
|
+
* - Only supported on Mainnet (1) and Hoodi (560048).
|
|
78
160
|
*
|
|
79
|
-
* @param
|
|
80
|
-
* @returns
|
|
161
|
+
* @param rewardsSplitPayload - Configuration for the OWR and splitter deployment.
|
|
162
|
+
* @returns The deployed OWR address as `withdrawal_address` and the
|
|
163
|
+
* splitter proxy address as `fee_recipient_address`.
|
|
164
|
+
* @throws {SignerRequiredError} If no signer was provided.
|
|
165
|
+
* @throws {UnsupportedChainError} If the chain does not support splitters.
|
|
81
166
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```typescript
|
|
169
|
+
* const { withdrawal_address, fee_recipient_address } =
|
|
170
|
+
* await client.createObolRewardsSplit({
|
|
171
|
+
* splitRecipients: [
|
|
172
|
+
* { account: "0xOperator1...", percentAllocation: 50 },
|
|
173
|
+
* { account: "0xOperator2...", percentAllocation: 49 },
|
|
174
|
+
* ],
|
|
175
|
+
* principalRecipient: "0xPrincipalAddress...",
|
|
176
|
+
* etherAmount: 32,
|
|
177
|
+
* });
|
|
178
|
+
* ```
|
|
84
179
|
*/
|
|
85
180
|
createObolRewardsSplit({ splitRecipients, principalRecipient, etherAmount, ObolRAFSplit, distributorFee, controllerAddress, recoveryAddress, }: RewardsSplitPayload): Promise<ClusterValidator>;
|
|
86
181
|
/**
|
|
87
|
-
* Deploys Splitter Proxy
|
|
182
|
+
* Deploys a Splitter Proxy contract that splits **both principal and rewards**.
|
|
183
|
+
*
|
|
184
|
+
* Unlike {@link Client.createObolRewardsSplit}, this method does not deploy an
|
|
185
|
+
* OWR – the splitter address is used as both `withdrawal_address` and
|
|
186
|
+
* `fee_recipient_address`.
|
|
88
187
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
188
|
+
* - Requires a `signer` with ETH to pay deployment gas.
|
|
189
|
+
* - Sends an on-chain transaction if the splitter is not already deployed (irreversible).
|
|
190
|
+
* - If the predicted splitter is already deployed, returns the existing address without
|
|
191
|
+
* sending a transaction (idempotent).
|
|
192
|
+
* - Automatically appends the Obol RAF recipient.
|
|
193
|
+
* - Only supported on Mainnet (1) and Hoodi (560048).
|
|
92
194
|
*
|
|
93
|
-
* @param
|
|
94
|
-
* @returns
|
|
195
|
+
* @param totalSplitPayload - Configuration for the splitter deployment.
|
|
196
|
+
* @returns The splitter address as both `withdrawal_address` and `fee_recipient_address`.
|
|
197
|
+
* @throws {SignerRequiredError} If no signer was provided.
|
|
198
|
+
* @throws {UnsupportedChainError} If the chain does not support splitters.
|
|
199
|
+
* @throws {Error} If required on-chain factory contracts are unavailable.
|
|
95
200
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* const { withdrawal_address, fee_recipient_address } =
|
|
204
|
+
* await client.createObolTotalSplit({
|
|
205
|
+
* splitRecipients: [
|
|
206
|
+
* { account: "0xOperator1...", percentAllocation: 50 },
|
|
207
|
+
* { account: "0xOperator2...", percentAllocation: 49.9 },
|
|
208
|
+
* ],
|
|
209
|
+
* });
|
|
210
|
+
* // withdrawal_address === fee_recipient_address (same splitter)
|
|
211
|
+
* ```
|
|
98
212
|
*/
|
|
99
213
|
createObolTotalSplit({ splitRecipients, ObolRAFSplit, distributorFee, controllerAddress, }: TotalSplitPayload): Promise<ClusterValidator>;
|
|
100
214
|
/**
|
|
101
|
-
*
|
|
215
|
+
* Reads the tranches of a deployed Optimistic Withdrawal Recipient (OWR) contract.
|
|
102
216
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* and not pushed to version control.
|
|
217
|
+
* Returns the principal recipient, reward recipient, and staked principal amount
|
|
218
|
+
* configured in the OWR. This is a read-only on-chain call (no transaction sent).
|
|
106
219
|
*
|
|
107
|
-
*
|
|
108
|
-
* @returns {Promise<OWRTranches>} owr tranch information about principal and reward reciepient, as well as the principal amount
|
|
220
|
+
* - Requires a `signer` (for provider access).
|
|
109
221
|
*
|
|
222
|
+
* @param owrAddress - The Ethereum address of the deployed OWR contract.
|
|
223
|
+
* @returns The OWR tranche data: `principalRecipient`, `rewardRecipient`, and `amountOfPrincipalStake`.
|
|
224
|
+
* @throws {SignerRequiredError} If no signer was provided.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const tranches = await client.getOWRTranches("0xOWRAddress...");
|
|
229
|
+
* console.log(tranches.principalRecipient);
|
|
230
|
+
* console.log(tranches.rewardRecipient);
|
|
231
|
+
* console.log(tranches.amountOfPrincipalStake);
|
|
232
|
+
* ```
|
|
110
233
|
*/
|
|
111
234
|
getOWRTranches(owrAddress: ETH_ADDRESS): Promise<OWRTranches>;
|
|
112
235
|
/**
|
|
113
|
-
* Creates a cluster definition
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
236
|
+
* Creates a new cluster definition and registers it with the Obol API.
|
|
237
|
+
*
|
|
238
|
+
* A cluster definition describes the operators, validators, and configuration
|
|
239
|
+
* for a Distributed Key Generation (DKG) ceremony. After creation, each operator
|
|
240
|
+
* must call {@link Client.acceptClusterDefinition} to join.
|
|
241
|
+
*
|
|
242
|
+
* - Requires {@link Client.acceptObolLatestTermsAndConditions} to have been called first.
|
|
243
|
+
* - Requires a `signer`.
|
|
244
|
+
* - The `config_hash` returned is the unique identifier for this cluster.
|
|
245
|
+
* - Threshold is automatically set to `ceil(2/3 * operators.length)`.
|
|
246
|
+
* - Creating a duplicate cluster throws a {@link ConflictError}.
|
|
247
|
+
*
|
|
248
|
+
* @param newCluster - The cluster configuration payload.
|
|
249
|
+
* @returns The `config_hash` string that uniquely identifies this cluster definition.
|
|
250
|
+
* @throws {SignerRequiredError} If no signer was provided.
|
|
251
|
+
* @throws {ConflictError} If an identical cluster definition already exists.
|
|
117
252
|
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```typescript
|
|
255
|
+
* const configHash = await client.createClusterDefinition({
|
|
256
|
+
* name: "my-dvt-cluster",
|
|
257
|
+
* operators: [{ address: "0xOp1..." }, { address: "0xOp2..." }],
|
|
258
|
+
* validators: [{
|
|
259
|
+
* fee_recipient_address: "0xFeeRecipient...",
|
|
260
|
+
* withdrawal_address: "0xWithdrawal...",
|
|
261
|
+
* }],
|
|
262
|
+
* });
|
|
263
|
+
* console.log("Cluster created:", configHash);
|
|
264
|
+
* ```
|
|
120
265
|
*/
|
|
121
266
|
createClusterDefinition(newCluster: ClusterPayload): Promise<string>;
|
|
122
267
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
268
|
+
* Accepts (joins) an existing cluster definition as an operator.
|
|
269
|
+
*
|
|
270
|
+
* Each operator in the cluster must call this method with their ENR and the
|
|
271
|
+
* cluster's `config_hash` to signal readiness for the DKG ceremony.
|
|
272
|
+
*
|
|
273
|
+
* - Requires a `signer` (the operator's address is derived from it).
|
|
274
|
+
* - Signs two EIP-712 messages: one for the config hash, one for the ENR.
|
|
275
|
+
* - The operator must be listed in the cluster definition's `operators` array.
|
|
276
|
+
*
|
|
277
|
+
* @param operatorPayload - Operator data. Must include `enr` (Ethereum Node Record)
|
|
278
|
+
* and `version` at minimum.
|
|
279
|
+
* @param configHash - The `config_hash` returned by {@link Client.createClusterDefinition}.
|
|
280
|
+
* @returns The updated cluster definition with the operator's acceptance recorded.
|
|
281
|
+
* @throws {SignerRequiredError} If no signer was provided.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```typescript
|
|
285
|
+
* const updatedDef = await client.acceptClusterDefinition(
|
|
286
|
+
* { enr: "enr:-LK4Q...", version: "v1.10.0" },
|
|
287
|
+
* configHash,
|
|
288
|
+
* );
|
|
289
|
+
* ```
|
|
131
290
|
*/
|
|
132
291
|
acceptClusterDefinition(operatorPayload: OperatorPayload, configHash: string): Promise<ClusterDefinition>;
|
|
133
292
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
293
|
+
* Retrieves a cluster definition by its configuration hash.
|
|
294
|
+
*
|
|
295
|
+
* This is a read-only API call – no signer is required.
|
|
137
296
|
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
297
|
+
* @param configHash - The `config_hash` returned by {@link Client.createClusterDefinition}.
|
|
298
|
+
* @returns The full cluster definition including operators, validators, and metadata.
|
|
299
|
+
* @throws {Error} If no cluster definition exists for the given hash (404).
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const definition = await client.getClusterDefinition(configHash);
|
|
304
|
+
* console.log(definition.name, definition.operators.length);
|
|
305
|
+
* ```
|
|
140
306
|
*/
|
|
141
307
|
getClusterDefinition(configHash: string): Promise<ClusterDefinition>;
|
|
142
308
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
309
|
+
* Retrieves a cluster lock by the cluster's configuration hash.
|
|
310
|
+
*
|
|
311
|
+
* A cluster lock is generated after a successful DKG ceremony and contains
|
|
312
|
+
* the distributed validators, their public key shares, and deposit data.
|
|
313
|
+
* This is a read-only API call – no signer is required.
|
|
146
314
|
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
315
|
+
* @param configHash - The `config_hash` from the cluster definition.
|
|
316
|
+
* @returns The cluster lock including distributed validators and deposit data.
|
|
317
|
+
* @throws {Error} If no lock exists for the given config hash (DKG not yet complete, or not found).
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```typescript
|
|
321
|
+
* const lock = await client.getClusterLock(configHash);
|
|
322
|
+
* console.log(lock.distributed_validators.length);
|
|
323
|
+
* console.log(lock.lock_hash);
|
|
324
|
+
* ```
|
|
149
325
|
*/
|
|
150
326
|
getClusterLock(configHash: string): Promise<ClusterLock>;
|
|
151
327
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
328
|
+
* Retrieves a cluster lock by its lock hash (as opposed to config hash).
|
|
329
|
+
*
|
|
330
|
+
* Use this when you have the `lock_hash` directly rather than the `config_hash`.
|
|
331
|
+
* This is a read-only API call – no signer is required.
|
|
332
|
+
*
|
|
333
|
+
* @param lockHash - The `lock_hash` from a cluster lock.
|
|
334
|
+
* @returns The cluster lock including distributed validators and deposit data.
|
|
335
|
+
* @throws {Error} If no lock exists for the given lock hash (not found).
|
|
155
336
|
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```typescript
|
|
339
|
+
* const lock = await client.getClusterLockByHash(lockHash);
|
|
340
|
+
* console.log(lock.cluster_definition.name);
|
|
341
|
+
* ```
|
|
156
342
|
*/
|
|
157
343
|
getClusterLockByHash(lockHash: string): Promise<ClusterLock>;
|
|
158
344
|
}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
import { type SafeRpcUrl, type ClusterLock } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Verifies
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
3
|
+
* Verifies the cryptographic validity of a cluster lock.
|
|
4
|
+
*
|
|
5
|
+
* Checks all operator signatures, config hashes, and definition hashes within
|
|
6
|
+
* the lock. Supports both EOA and Safe Wallet signatures.
|
|
7
|
+
*
|
|
8
|
+
* This is a standalone utility – it does **not** require a `Client` instance.
|
|
9
|
+
*
|
|
10
|
+
* @param lock - The cluster lock object (e.g. from {@link Client.getClusterLock}).
|
|
11
|
+
* @param safeRpcUrl - Optional RPC URL for Safe Wallet signature verification.
|
|
12
|
+
* If omitted, falls back to the `RPC_MAINNET` / `RPC_HOODI` / etc. env vars.
|
|
13
|
+
* @returns `true` if the lock is cryptographically valid; `false` if invalid
|
|
14
|
+
* (e.g. missing keys, invalid signatures, hash mismatches) or on any error.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { validateClusterLock, Client } from "@obolnetwork/obol-sdk";
|
|
19
|
+
*
|
|
20
|
+
* const configHash = "0x..."; // your cluster config hash
|
|
21
|
+
* const client = new Client({ chainId: 560048 });
|
|
22
|
+
* const lock = await client.getClusterLock(configHash);
|
|
23
|
+
* const isValid = await validateClusterLock(lock);
|
|
24
|
+
* ```
|
|
11
25
|
*/
|
|
12
26
|
export declare const validateClusterLock: (lock: ClusterLock, safeRpcUrl?: SafeRpcUrl) => Promise<boolean>;
|