@obolnetwork/obol-sdk 2.5.1 → 2.7.0
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 +3 -3
- package/dist/cjs/src/constants.js +13 -1
- package/dist/cjs/src/exits/ethUtils.js +57 -0
- package/dist/cjs/src/exits/exit.js +502 -0
- package/dist/cjs/src/exits/verificationHelpers.js +86 -0
- package/dist/cjs/src/{incentiveHelpers.js → incentives/incentiveHelpers.js} +1 -1
- package/dist/cjs/src/{incentives.js → incentives/incentives.js} +3 -3
- package/dist/cjs/src/index.js +22 -4
- package/dist/cjs/src/splits/splitHelpers.js +327 -0
- package/dist/cjs/src/types.js +1 -0
- package/dist/cjs/test/exit/ethUtils.spec.js +83 -0
- package/dist/cjs/test/exit/exit.spec.js +399 -0
- package/dist/cjs/test/exit/verificationHelpers.spec.js +68 -0
- package/dist/cjs/test/{incentives.test.js → incentives/incentives.spec.js} +4 -4
- package/dist/esm/package.json +3 -3
- package/dist/esm/src/constants.js +12 -0
- package/dist/esm/src/exits/ethUtils.js +52 -0
- package/dist/esm/src/exits/exit.js +475 -0
- package/dist/esm/src/exits/verificationHelpers.js +81 -0
- package/dist/esm/src/{incentiveHelpers.js → incentives/incentiveHelpers.js} +1 -1
- package/dist/esm/src/{incentives.js → incentives/incentives.js} +3 -3
- package/dist/esm/src/index.js +20 -3
- package/dist/esm/src/splits/splitHelpers.js +317 -0
- package/dist/esm/src/types.js +1 -0
- package/dist/esm/test/exit/ethUtils.spec.js +81 -0
- package/dist/esm/test/exit/exit.spec.js +374 -0
- package/dist/esm/test/exit/verificationHelpers.spec.js +66 -0
- package/dist/esm/test/{incentives.test.js → incentives/incentives.spec.js} +4 -4
- package/dist/types/src/constants.d.ts +5 -0
- package/dist/types/src/exits/ethUtils.d.ts +13 -0
- package/dist/types/src/exits/exit.d.ts +200 -0
- package/dist/types/src/exits/verificationHelpers.d.ts +20 -0
- package/dist/types/src/{incentiveHelpers.d.ts → incentives/incentiveHelpers.d.ts} +1 -1
- package/dist/types/src/{incentives.d.ts → incentives/incentives.d.ts} +1 -1
- package/dist/types/src/index.d.ts +16 -2
- package/dist/types/src/{splitHelpers.d.ts → splits/splitHelpers.d.ts} +1 -1
- package/dist/types/src/types.d.ts +133 -0
- package/dist/types/test/exit/verificationHelpers.spec.d.ts +1 -0
- package/dist/types/test/incentives/incentives.spec.d.ts +1 -0
- package/package.json +3 -3
- package/src/constants.ts +13 -0
- package/src/exits/ethUtils.ts +49 -0
- package/src/exits/exit.ts +661 -0
- package/src/exits/verificationHelpers.ts +110 -0
- package/src/{incentiveHelpers.ts → incentives/incentiveHelpers.ts} +2 -2
- package/src/{incentives.ts → incentives/incentives.ts} +3 -3
- package/src/index.ts +29 -3
- package/src/splits/splitHelpers.ts +557 -0
- package/src/types.ts +158 -0
- package/dist/cjs/src/splitHelpers.js +0 -187
- package/dist/cjs/test/methods.test.js +0 -418
- package/dist/esm/src/splitHelpers.js +0 -177
- package/dist/esm/test/methods.test.js +0 -393
- package/src/splitHelpers.ts +0 -355
- /package/dist/types/test/{incentives.test.d.ts → exit/ethUtils.spec.d.ts} +0 -0
- /package/dist/types/test/{methods.test.d.ts → exit/exit.spec.d.ts} +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { ProviderType, ExitClusterConfig, ExitValidationPayload, ExitValidationBlob, SignedExitValidationMessage, ExistingExitValidationBlobData, FullExitBlob } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Exit validation and verification class for Obol distributed validators.
|
|
4
|
+
*
|
|
5
|
+
* This class provides functionality to validate and verify voluntary exit signatures
|
|
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.
|
|
8
|
+
*
|
|
9
|
+
* The class supports:
|
|
10
|
+
* - Verification of BLS signatures for partial exit messages
|
|
11
|
+
* - Verification of ECDSA signatures for exit payload authorization
|
|
12
|
+
* - Validation of exit blobs against cluster configuration
|
|
13
|
+
* - Duplicate detection and epoch validation
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const exit = new Exit(1, provider); // Mainnet with provider
|
|
18
|
+
*
|
|
19
|
+
* // Verify a partial exit signature
|
|
20
|
+
* const isValid = await exit.verifyPartialExitSignature(
|
|
21
|
+
* publicShareKey,
|
|
22
|
+
* signedExitMessage,
|
|
23
|
+
* forkVersion,
|
|
24
|
+
* genesisValidatorsRoot
|
|
25
|
+
* );
|
|
26
|
+
*
|
|
27
|
+
* // Validate exit blobs for a cluster
|
|
28
|
+
* const validBlobs = await exit.validateExitBlobs(
|
|
29
|
+
* clusterConfig,
|
|
30
|
+
* exitsPayload,
|
|
31
|
+
* beaconNodeApiUrl,
|
|
32
|
+
* existingBlobData
|
|
33
|
+
* );
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare class Exit {
|
|
37
|
+
readonly chainId: number;
|
|
38
|
+
readonly provider: ProviderType | undefined | null;
|
|
39
|
+
/**
|
|
40
|
+
* Creates a new Exit instance for validator exit operations.
|
|
41
|
+
*
|
|
42
|
+
* @param chainId - The Ethereum chain ID (e.g., 1 for mainnet, 5 for goerli)
|
|
43
|
+
* @param provider - Optional Ethereum provider for blockchain interactions
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // For mainnet with a provider
|
|
48
|
+
* const exit = new Exit(1, provider);
|
|
49
|
+
*
|
|
50
|
+
* // For goerli testnet without provider
|
|
51
|
+
* const exit = new Exit(5, null);
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
constructor(chainId: number, provider: ProviderType | undefined | null);
|
|
55
|
+
/**
|
|
56
|
+
* Safely parse a string integer to number, using BigInt to avoid precision loss
|
|
57
|
+
* for large values beyond JavaScript's safe integer limit (2^53 - 1).
|
|
58
|
+
* Throws an error if the value exceeds the safe range for a 64-bit unsigned integer.
|
|
59
|
+
*/
|
|
60
|
+
private static safeParseInt;
|
|
61
|
+
private static computePartialExitMessageRoot;
|
|
62
|
+
private static computeExitPayloadRoot;
|
|
63
|
+
/**
|
|
64
|
+
* Verifies a partial exit signature from a distributed validator operator.
|
|
65
|
+
*
|
|
66
|
+
* This method validates that a partial exit signature was correctly signed by the
|
|
67
|
+
* operator's share of the distributed validator's private key. It performs BLS
|
|
68
|
+
* signature verification using the appropriate fork version and genesis validators root.
|
|
69
|
+
*
|
|
70
|
+
* @param publicShareKey - The operator's public share key (BLS public key, hex string with or without 0x prefix)
|
|
71
|
+
* @param signedExitMessage - The signed exit message containing the exit details and signature
|
|
72
|
+
* @param forkVersion - The Ethereum fork version (e.g., "0x00000000" for mainnet)
|
|
73
|
+
* @param genesisValidatorsRootString - The genesis validators root for the network (hex string)
|
|
74
|
+
*
|
|
75
|
+
* @returns Promise resolving to true if the signature is valid, false otherwise
|
|
76
|
+
*
|
|
77
|
+
* @throws {Error} When unable to determine the Capella fork version for the given network
|
|
78
|
+
* @throws {Error} When BLS library initialization or verification fails
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const isValid = await exit.verifyPartialExitSignature(
|
|
83
|
+
* "0x1234...abcd", // operator's public share key
|
|
84
|
+
* {
|
|
85
|
+
* message: { epoch: "12345", validator_index: "67890" },
|
|
86
|
+
* signature: "0xabcd...1234"
|
|
87
|
+
* },
|
|
88
|
+
* "0x00000000", // mainnet fork version
|
|
89
|
+
* "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"
|
|
90
|
+
* );
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
verifyPartialExitSignature(publicShareKey: string, signedExitMessage: SignedExitValidationMessage, forkVersion: string, genesisValidatorsRootString: string): Promise<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* Verifies the exit payload signature using the operator's ENR.
|
|
96
|
+
*
|
|
97
|
+
* This method validates that an exit payload was signed by the correct operator
|
|
98
|
+
* using ECDSA signature verification. The signature is verified against the
|
|
99
|
+
* operator's public key extracted from their ENR (Ethereum Node Record).
|
|
100
|
+
*
|
|
101
|
+
* @param enrString - The operator's ENR string containing their identity and public key
|
|
102
|
+
* @param exitsPayload - The exit validation payload containing partial exits and operator signature
|
|
103
|
+
*
|
|
104
|
+
* @returns Promise resolving to true if the payload signature is valid, false otherwise
|
|
105
|
+
*
|
|
106
|
+
* @throws {Error} When the ENR string is invalid or cannot be decoded
|
|
107
|
+
* @throws {Error} When the signature format is invalid (must be 130 hex characters)
|
|
108
|
+
* @throws {Error} When signature verification encounters an error
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const isValid = await exit.verifyExitPayloadSignature(
|
|
113
|
+
* "enr:-LK4QFo_n0dUm4PKejSOXf8JkSWq5EINV0XhG1zY00d...", // operator ENR
|
|
114
|
+
* {
|
|
115
|
+
* partial_exits: [exitBlob1, exitBlob2],
|
|
116
|
+
* share_idx: 1,
|
|
117
|
+
* signature: "0x1234...abcd" // ECDSA signature (130 hex chars)
|
|
118
|
+
* }
|
|
119
|
+
* );
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
verifyExitPayloadSignature(enrString: string, exitsPayload: ExitValidationPayload): Promise<boolean>;
|
|
123
|
+
private validateOperatorAndPayload;
|
|
124
|
+
private getNetworkParameters;
|
|
125
|
+
private findValidatorInCluster;
|
|
126
|
+
private validateExistingBlobData;
|
|
127
|
+
private processExitBlob;
|
|
128
|
+
/**
|
|
129
|
+
* Validates exit blobs against cluster configuration and existing data.
|
|
130
|
+
*
|
|
131
|
+
* This method performs comprehensive validation of exit blobs including:
|
|
132
|
+
* - Operator authorization and payload signature verification
|
|
133
|
+
* - Network parameter validation (genesis root, fork version)
|
|
134
|
+
* - Public key validation against cluster configuration
|
|
135
|
+
* - Partial signature verification for each exit blob
|
|
136
|
+
* - Duplicate detection and epoch progression validation
|
|
137
|
+
* - Signature consistency checks for existing exits
|
|
138
|
+
*
|
|
139
|
+
* @param clusterConfig - The cluster configuration containing operators and distributed validators
|
|
140
|
+
* @param exitsPayload - The exit validation payload with partial exits and operator info
|
|
141
|
+
* @param beaconNodeApiUrl - The beacon node API URL for network parameter retrieval
|
|
142
|
+
* @param existingBlobData - Existing exit blob data for duplicate detection, or null if none exists
|
|
143
|
+
*
|
|
144
|
+
* @returns Promise resolving to an array of validated, non-duplicate exit blobs
|
|
145
|
+
*
|
|
146
|
+
* @throws {Error} When share_idx is invalid or out of bounds for the cluster operators
|
|
147
|
+
* @throws {Error} When payload signature verification fails
|
|
148
|
+
* @throws {Error} When network parameters cannot be retrieved or are invalid
|
|
149
|
+
* @throws {Error} When a public key is not found in the cluster's distributed validators
|
|
150
|
+
* @throws {Error} When a partial exit signature is invalid
|
|
151
|
+
* @throws {Error} When exit epoch validation fails (new epoch not greater than existing)
|
|
152
|
+
* @throws {Error} When validator index mismatches with existing data
|
|
153
|
+
* @throws {Error} When signature mismatches for the same epoch and operator
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const validExitBlobs = await exit.validateExitBlobs(
|
|
158
|
+
* {
|
|
159
|
+
* definition: {
|
|
160
|
+
* operators: [{ enr: "enr:-LK4Q..." }],
|
|
161
|
+
* fork_version: "0x00000000",
|
|
162
|
+
* threshold: 1
|
|
163
|
+
* },
|
|
164
|
+
* distributed_validators: [{
|
|
165
|
+
* distributed_public_key: "0x1234...abcd",
|
|
166
|
+
* public_shares: ["0x5678...efgh"]
|
|
167
|
+
* }]
|
|
168
|
+
* },
|
|
169
|
+
* {
|
|
170
|
+
* partial_exits: [exitBlob],
|
|
171
|
+
* share_idx: 1,
|
|
172
|
+
* signature: "0x1234...abcd"
|
|
173
|
+
* },
|
|
174
|
+
* "http://localhost:5052",
|
|
175
|
+
* existingBlobData // or null for new exits
|
|
176
|
+
* );
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
validateExitBlobs(clusterConfig: ExitClusterConfig, exitsPayload: ExitValidationPayload, beaconNodeApiUrl: string, existingBlobData: ExistingExitValidationBlobData | null): Promise<ExitValidationBlob[]>;
|
|
180
|
+
/**
|
|
181
|
+
* Recombines exit blobs into a single exit blob.
|
|
182
|
+
*
|
|
183
|
+
* This method aggregates partial exit signatures from multiple operators into a single exit blob.
|
|
184
|
+
* It ensures that the signatures are properly ordered and aggregated according to the operator indices.
|
|
185
|
+
*
|
|
186
|
+
* @param exitBlob - The existing exit blob data containing partial exit signatures
|
|
187
|
+
*
|
|
188
|
+
* @returns Promise resolving to a single exit blob with aggregated signatures
|
|
189
|
+
*
|
|
190
|
+
* @throws {Error} When no valid signatures are found for aggregation
|
|
191
|
+
* @throws {Error} When signature length is invalid
|
|
192
|
+
* @throws {Error} When signature parsing fails
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const aggregatedExitBlob = await exit.recombineExitBlobs(existingBlobData);
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
recombineExitBlobs(exitBlob: ExistingExitValidationBlobData): Promise<FullExitBlob>;
|
|
200
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare const GENESIS_VALIDATOR_ROOT_HEX_STRING = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
3
|
+
/**
|
|
4
|
+
* Computes the domain for a given domain type, fork version, and genesis state.
|
|
5
|
+
* https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_domain
|
|
6
|
+
* @param domainType - Uint8Array representing the domain type (e.g., DOMAIN_VOLUNTARY_EXIT).
|
|
7
|
+
* @param forkVersionString - Hex string of the fork version (e.g., Capella fork version).
|
|
8
|
+
* @param genesisValidatorsRootOverride - Optional Uint8Array to override the default genesis validators root.
|
|
9
|
+
* @returns Uint8Array - The 32-byte domain.
|
|
10
|
+
*/
|
|
11
|
+
export declare function computeDomain(domainType: Uint8Array, // Should be 4 bytes
|
|
12
|
+
forkVersionString: string, // Hex string, e.g., '0x03000000'
|
|
13
|
+
genesisValidatorsRootOverride?: Uint8Array): Uint8Array;
|
|
14
|
+
/**
|
|
15
|
+
* Convenience wrapper for computeSigningRoot.
|
|
16
|
+
* @param domain - Uint8Array of the domain.
|
|
17
|
+
* @param messageBuffer - Buffer of the message (SSZ object root).
|
|
18
|
+
* @returns Uint8Array - The signing root.
|
|
19
|
+
*/
|
|
20
|
+
export declare function signingRoot(domain: Uint8Array, messageBuffer: Buffer): Uint8Array;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ProviderType, type SignerType, type ETH_ADDRESS } from '
|
|
1
|
+
import { type ProviderType, type SignerType, type ETH_ADDRESS } from '../types';
|
|
2
2
|
export declare const claimIncentivesFromMerkleDistributor: (incentivesData: {
|
|
3
3
|
signer: SignerType;
|
|
4
4
|
contractAddress: ETH_ADDRESS;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ClaimableIncentives, type ETH_ADDRESS, type ProviderType, type SignerType, type ClaimIncentivesResponse } from '
|
|
1
|
+
import { type ClaimableIncentives, type ETH_ADDRESS, type ProviderType, type SignerType, type ClaimIncentivesResponse } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Incentives can be used for fetching and claiming Obol incentives.
|
|
4
4
|
* @class
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Base } from './base.js';
|
|
2
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';
|
|
3
|
-
import { Incentives } from './incentives.js';
|
|
3
|
+
import { Incentives } from './incentives/incentives.js';
|
|
4
|
+
import { Exit } from './exits/exit.js';
|
|
4
5
|
export * from './types.js';
|
|
5
6
|
export * from './services.js';
|
|
6
7
|
export * from './verification/signature-validator.js';
|
|
7
8
|
export * from './verification/common.js';
|
|
8
9
|
export * from './constants.js';
|
|
9
|
-
export { Incentives } from './incentives.js';
|
|
10
|
+
export { Incentives } from './incentives/incentives.js';
|
|
11
|
+
export { Exit } from './exits/exit.js';
|
|
10
12
|
/**
|
|
11
13
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
12
14
|
*/
|
|
@@ -20,6 +22,11 @@ export declare class Client extends Base {
|
|
|
20
22
|
* @type {Incentives}
|
|
21
23
|
*/
|
|
22
24
|
incentives: Incentives;
|
|
25
|
+
/**
|
|
26
|
+
* The exit module, responsible for managing exit validation.
|
|
27
|
+
* @type {Exit}
|
|
28
|
+
*/
|
|
29
|
+
exit: Exit;
|
|
23
30
|
/**
|
|
24
31
|
* The blockchain provider, used to interact with the network.
|
|
25
32
|
* It can be null, undefined, or a valid provider instance and defaults to the Signer provider if Signer is passed.
|
|
@@ -127,4 +134,11 @@ export declare class Client extends Base {
|
|
|
127
134
|
* [getObolClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L89)
|
|
128
135
|
*/
|
|
129
136
|
getClusterLock(configHash: string): Promise<ClusterLock>;
|
|
137
|
+
/**
|
|
138
|
+
* @param lockHash - The configuration hash in cluster-definition
|
|
139
|
+
* @returns {Promise<ClusterLock>} The matched cluster details (lock) from DB
|
|
140
|
+
* @throws On not found cluster definition or lock.
|
|
141
|
+
*
|
|
142
|
+
*/
|
|
143
|
+
getClusterLockByHash(lockHash: string): Promise<ClusterLock>;
|
|
130
144
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type OWRTranches, type ClusterValidator, type ETH_ADDRESS, type SplitRecipient, type SignerType } from '
|
|
1
|
+
import { type OWRTranches, type ClusterValidator, type ETH_ADDRESS, type SplitRecipient, type SignerType } from '../types';
|
|
2
2
|
type Call = {
|
|
3
3
|
target: ETH_ADDRESS;
|
|
4
4
|
callData: string;
|
|
@@ -254,3 +254,136 @@ export type SignerType = Signer | JsonRpcSigner | Wallet;
|
|
|
254
254
|
export type ClaimIncentivesResponse = {
|
|
255
255
|
txHash: string | null;
|
|
256
256
|
};
|
|
257
|
+
/**
|
|
258
|
+
* Represents the structure of an Ethereum operator for exit validation, primarily their ENR.
|
|
259
|
+
*/
|
|
260
|
+
export interface ExitOperator {
|
|
261
|
+
/** The operator's Ethereum Node Record (ENR). */
|
|
262
|
+
enr: string;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Represents the core definition of a cluster relevant for exit validation.
|
|
266
|
+
*/
|
|
267
|
+
export interface ExitClusterDefinition {
|
|
268
|
+
/** The cluster nodes operators with their ENRs. */
|
|
269
|
+
operators: ExitOperator[];
|
|
270
|
+
/** The cluster fork version. */
|
|
271
|
+
fork_version: string;
|
|
272
|
+
/** The distributed validator threshold. */
|
|
273
|
+
threshold: number;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Represents a distributed validator's information relevant for exit validation.
|
|
277
|
+
*/
|
|
278
|
+
export interface ExitDistributedValidator {
|
|
279
|
+
/** The public key of the distributed validator. */
|
|
280
|
+
distributed_public_key: string;
|
|
281
|
+
/** The public key shares of the distributed validator. */
|
|
282
|
+
public_shares: string[];
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Combined cluster information needed for exit validation in the SDK.
|
|
286
|
+
*/
|
|
287
|
+
export interface ExitClusterConfig {
|
|
288
|
+
/** The cluster definition with operators, fork version and threshold. */
|
|
289
|
+
definition: ExitClusterDefinition;
|
|
290
|
+
/** The cluster distributed validators. */
|
|
291
|
+
distributed_validators: ExitDistributedValidator[];
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Represents the message part of a signed exit for exit validation.
|
|
295
|
+
*/
|
|
296
|
+
export interface ExitValidationMessage {
|
|
297
|
+
/** The epoch at which the validator wishes to exit. */
|
|
298
|
+
epoch: string;
|
|
299
|
+
/** The index of the validator in the beacon chain. */
|
|
300
|
+
validator_index: string;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Represents a signed exit message for exit validation.
|
|
304
|
+
*/
|
|
305
|
+
export interface SignedExitValidationMessage {
|
|
306
|
+
/** The exit message containing epoch and validator index. */
|
|
307
|
+
message: ExitValidationMessage;
|
|
308
|
+
/** BLS signature of the exit message. */
|
|
309
|
+
signature: string;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Represents a single partial exit blob for exit validation.
|
|
313
|
+
*/
|
|
314
|
+
export interface ExitValidationBlob {
|
|
315
|
+
/** The public key of the validator to exit. */
|
|
316
|
+
public_key: string;
|
|
317
|
+
/** The signed exit message for the validator. */
|
|
318
|
+
signed_exit_message: SignedExitValidationMessage;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Represents the overall exit payload structure for exit validation.
|
|
322
|
+
*/
|
|
323
|
+
export interface ExitValidationPayload {
|
|
324
|
+
/** Array of partial exits for validators. */
|
|
325
|
+
partial_exits: ExitValidationBlob[];
|
|
326
|
+
/** Operator's share index (1-based). */
|
|
327
|
+
share_idx: number;
|
|
328
|
+
/** Signature of the ExitValidationPayload by the operator. */
|
|
329
|
+
signature: string;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Represents the data structure for an already existing exit blob for exit validation.
|
|
333
|
+
*/
|
|
334
|
+
export interface ExistingExitValidationBlobData {
|
|
335
|
+
/**
|
|
336
|
+
* The BLS public key of the validator in hex format
|
|
337
|
+
*/
|
|
338
|
+
public_key: string;
|
|
339
|
+
/**
|
|
340
|
+
* The epoch number when the exit is scheduled to occur
|
|
341
|
+
*/
|
|
342
|
+
epoch: string;
|
|
343
|
+
/**
|
|
344
|
+
* The unique index of the validator in the beacon chain
|
|
345
|
+
*/
|
|
346
|
+
validator_index: string;
|
|
347
|
+
/**
|
|
348
|
+
* Array of distributed validator shares exit data, where each share contains
|
|
349
|
+
* the partial exit signature from each operator in the cluster
|
|
350
|
+
*/
|
|
351
|
+
shares_exit_data: Array<Record<string, {
|
|
352
|
+
partial_exit_signature: string;
|
|
353
|
+
}>>;
|
|
354
|
+
}
|
|
355
|
+
export interface FullExitBlob {
|
|
356
|
+
/**
|
|
357
|
+
* The signed voluntary exit message containing the exit details and signature
|
|
358
|
+
*/
|
|
359
|
+
signed_exit_message: {
|
|
360
|
+
/**
|
|
361
|
+
* The voluntary exit message details
|
|
362
|
+
*/
|
|
363
|
+
message: {
|
|
364
|
+
/**
|
|
365
|
+
* The epoch number when the validator exit will be processed
|
|
366
|
+
*/
|
|
367
|
+
epoch: string;
|
|
368
|
+
/**
|
|
369
|
+
* The unique index of the validator requesting to exit
|
|
370
|
+
*/
|
|
371
|
+
validator_index: string;
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* The BLS12-381 hex-encoded signature of the exit message
|
|
375
|
+
*/
|
|
376
|
+
signature: string;
|
|
377
|
+
};
|
|
378
|
+
/** The public key of the validator to exit. */
|
|
379
|
+
public_key: string;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Generic HTTP request function type.
|
|
383
|
+
* Args:
|
|
384
|
+
* url: string - The URL to request.
|
|
385
|
+
* config?: Record<string, any> - Optional request configuration (e.g., method, headers, body for POST).
|
|
386
|
+
* Returns:
|
|
387
|
+
* Promise<any> - The response data.
|
|
388
|
+
*/
|
|
389
|
+
export type HttpRequestFunc = (url: string, config?: Record<string, any>) => Promise<any>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obolnetwork/obol-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
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"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"compile": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json ./tsconfig.types.json",
|
|
16
16
|
"build:clean": "rm -rf ./dist",
|
|
17
17
|
"build": "npm-run-all build:clean compile",
|
|
18
|
-
"test": "jest
|
|
18
|
+
"test": "jest test/**/*.spec.ts --testPathIgnorePatterns=test/sdk-package/",
|
|
19
19
|
"generate-typedoc": "typedoc",
|
|
20
20
|
"npm:publish": "npm publish --tag latest",
|
|
21
21
|
"release": "release-it",
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"^bn.js$": "<rootDir>/node_modules/bn.js",
|
|
131
131
|
"^asn1.js$": "<rootDir>/node_modules/asn1.js",
|
|
132
132
|
"^hash.js$": "<rootDir>/node_modules/hash.js",
|
|
133
|
-
"(
|
|
133
|
+
"^(\\.\\.?\\/.+)\\.js$": "$1"
|
|
134
134
|
},
|
|
135
135
|
"extensionsToTreatAsEsm": [
|
|
136
136
|
".ts"
|
package/src/constants.ts
CHANGED
|
@@ -205,3 +205,16 @@ export const PROVIDER_MAP: Record<number, string> = {
|
|
|
205
205
|
11155111: `${process.env.RPC_SEPOLIA}`, // Sepolia
|
|
206
206
|
100: `${process.env.RPC_GNOSIS}`, // Gnosis
|
|
207
207
|
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Maps base fork versions to their corresponding Capella fork versions.
|
|
211
|
+
* Example: Mainnet Capella fork version.
|
|
212
|
+
*/
|
|
213
|
+
export const CAPELLA_FORK_MAPPING: Record<string, string> = {
|
|
214
|
+
'0x00000000': '0x03000000', // Mainnet
|
|
215
|
+
'0x00001020': '0x03001020', // Goerli
|
|
216
|
+
'0x00000064': '0x03000064', // Gnosis
|
|
217
|
+
'0x90000069': '0x90000072', // Sepolia
|
|
218
|
+
'0x01017000': '0x04017000', // Holesky
|
|
219
|
+
'0x10000910': '0x40000910', // Hoodi
|
|
220
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { CAPELLA_FORK_MAPPING } from '../constants';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves the Capella fork version for a given base fork version.
|
|
5
|
+
* @param fork_version - The base fork version string (e.g., '0x00000000' for mainnet).
|
|
6
|
+
* @returns A promise that resolves to the Capella fork version string, or null if not found.
|
|
7
|
+
*/
|
|
8
|
+
export async function getCapellaFork(
|
|
9
|
+
fork_version: string,
|
|
10
|
+
): Promise<string | null> {
|
|
11
|
+
// Ensure the CAPELLA_FORK_MAPPING uses the base fork_version as key
|
|
12
|
+
if (CAPELLA_FORK_MAPPING[fork_version]) {
|
|
13
|
+
return CAPELLA_FORK_MAPPING[fork_version];
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Fetches the genesis validators root from a beacon node.
|
|
20
|
+
* @param beaconNodeApiUrl - The base URL of the beacon node API (e.g., http://localhost:5052).
|
|
21
|
+
* @returns A promise that resolves to the genesis_validators_root string, or null on error.
|
|
22
|
+
* @throws Will throw an error if the network corresponding to the fork_version is not supported or if the HTTP request fails.
|
|
23
|
+
*/
|
|
24
|
+
export async function getGenesisValidatorsRoot(
|
|
25
|
+
beaconNodeApiUrl: string,
|
|
26
|
+
): Promise<string | null> {
|
|
27
|
+
const genesisEndpoint = `${beaconNodeApiUrl}/eth/v1/beacon/genesis`;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const response = await fetch(genesisEndpoint, {
|
|
31
|
+
method: 'GET',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const json = await response.json();
|
|
35
|
+
|
|
36
|
+
if (json.data?.genesis_validators_root) {
|
|
37
|
+
return json.data.genesis_validators_root;
|
|
38
|
+
}
|
|
39
|
+
console.error('Invalid response structure from genesis endpoint', json);
|
|
40
|
+
return null;
|
|
41
|
+
} catch (e: any) {
|
|
42
|
+
console.error(
|
|
43
|
+
`Error fetching genesis validators root from ${genesisEndpoint}:`,
|
|
44
|
+
e,
|
|
45
|
+
);
|
|
46
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
47
|
+
throw new Error(`Failed to fetch genesis validators root: ${errorMessage}`);
|
|
48
|
+
}
|
|
49
|
+
}
|