@obolnetwork/obol-sdk 2.4.5 → 2.5.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.
Files changed (56) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/package.json +4 -2
  3. package/dist/cjs/src/ajv.js +67 -41
  4. package/dist/cjs/src/constants.js +1 -1
  5. package/dist/cjs/src/incentiveHelpers.js +2 -4
  6. package/dist/cjs/src/incentives.js +1 -1
  7. package/dist/cjs/src/index.js +25 -27
  8. package/dist/cjs/src/schema.js +50 -23
  9. package/dist/cjs/src/services.js +3 -2
  10. package/dist/cjs/src/utils.js +4 -4
  11. package/dist/cjs/src/verification/common.js +12 -9
  12. package/dist/cjs/src/verification/signature-validator.js +6 -5
  13. package/dist/cjs/src/verification/v1.8.0.js +18 -0
  14. package/dist/cjs/test/fixtures.js +125 -17
  15. package/dist/cjs/test/incentives.test.js +2 -2
  16. package/dist/cjs/test/methods.test.js +47 -42
  17. package/dist/esm/package.json +4 -2
  18. package/dist/esm/src/ajv.js +66 -40
  19. package/dist/esm/src/constants.js +1 -1
  20. package/dist/esm/src/incentiveHelpers.js +2 -4
  21. package/dist/esm/src/incentives.js +1 -1
  22. package/dist/esm/src/index.js +26 -28
  23. package/dist/esm/src/schema.js +50 -23
  24. package/dist/esm/src/services.js +3 -2
  25. package/dist/esm/src/utils.js +4 -4
  26. package/dist/esm/src/verification/common.js +12 -9
  27. package/dist/esm/src/verification/signature-validator.js +6 -5
  28. package/dist/esm/src/verification/v1.8.0.js +18 -0
  29. package/dist/esm/test/fixtures.js +124 -16
  30. package/dist/esm/test/incentives.test.js +2 -2
  31. package/dist/esm/test/methods.test.js +48 -43
  32. package/dist/types/src/ajv.d.ts +3 -2
  33. package/dist/types/src/constants.d.ts +1 -1
  34. package/dist/types/src/incentiveHelpers.d.ts +1 -1
  35. package/dist/types/src/incentives.d.ts +2 -2
  36. package/dist/types/src/index.d.ts +1 -0
  37. package/dist/types/src/schema.d.ts +40 -8
  38. package/dist/types/src/services.d.ts +3 -2
  39. package/dist/types/src/types.d.ts +16 -6
  40. package/dist/types/src/utils.d.ts +1 -1
  41. package/dist/types/src/verification/common.d.ts +2 -2
  42. package/dist/types/src/verification/signature-validator.d.ts +5 -2
  43. package/dist/types/test/fixtures.d.ts +78 -11
  44. package/package.json +4 -2
  45. package/src/ajv.ts +91 -52
  46. package/src/constants.ts +1 -1
  47. package/src/incentiveHelpers.ts +1 -5
  48. package/src/incentives.ts +3 -4
  49. package/src/index.ts +37 -35
  50. package/src/schema.ts +45 -22
  51. package/src/services.ts +4 -2
  52. package/src/types.ts +20 -5
  53. package/src/utils.ts +7 -4
  54. package/src/verification/common.ts +13 -1
  55. package/src/verification/signature-validator.ts +10 -3
  56. package/src/verification/v1.8.0.ts +24 -0
@@ -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); // [TODO Hanan], should expect it from signer.provider, or passed in client
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 provider = PROVIDER_MAP[chainId];
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);
@@ -251,6 +251,30 @@ export const verifyDVV1X8 = (clusterLock: ClusterLock): boolean => {
251
251
  pubShares.push(fromHexString(element));
252
252
  }
253
253
 
254
+ // Check deposit amounts match exactly if they are defined
255
+ const depositAmounts = clusterLock.cluster_definition.deposit_amounts;
256
+ if (depositAmounts !== null) {
257
+ const partialDepositAmounts = (
258
+ validator.partial_deposit_data as DepositData[]
259
+ ).map(d => d.amount);
260
+ if (depositAmounts?.length !== partialDepositAmounts.length) {
261
+ return false;
262
+ }
263
+ // Check that both arrays contain exactly the same elements
264
+ const sortedDepositAmounts = [...depositAmounts]
265
+ .map(Number)
266
+ .sort((a, b) => a - b);
267
+ const sortedPartialAmounts = [...partialDepositAmounts]
268
+ .map(Number)
269
+ .sort((a, b) => a - b);
270
+ if (
271
+ !sortedDepositAmounts.every(
272
+ (amount, index) => amount === sortedPartialAmounts[index],
273
+ )
274
+ ) {
275
+ return false;
276
+ }
277
+ }
254
278
  // Deposit Data Verification
255
279
  for (const element of validator.partial_deposit_data as DepositData[]) {
256
280
  const depositData = element;