@obolnetwork/obol-sdk 2.12.1 → 2.12.4

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 (38) hide show
  1. package/README.md +6 -4
  2. package/dist/browser/src/index.js +146 -62
  3. package/dist/browser/src/index.js.map +1 -1
  4. package/dist/cjs/src/index.js +149 -62
  5. package/dist/cjs/src/index.js.map +1 -1
  6. package/dist/cjs/src/verification/clusterLockValidationWorker.js +39 -10
  7. package/dist/cjs/src/verification/clusterLockValidationWorker.js.map +1 -1
  8. package/dist/cjs/src/verification/parallelPool.js +33 -14
  9. package/dist/cjs/src/verification/parallelPool.js.map +1 -1
  10. package/dist/esm/src/{chunk-RYTIXFRX.js → chunk-FGMJVLIN.js} +53 -15
  11. package/dist/esm/src/chunk-FGMJVLIN.js.map +1 -0
  12. package/dist/esm/src/{chunk-5ASVONSJ.js → chunk-YZWJJHPO.js} +9 -7
  13. package/dist/esm/src/chunk-YZWJJHPO.js.map +1 -0
  14. package/dist/esm/src/index.js +56 -7
  15. package/dist/esm/src/index.js.map +1 -1
  16. package/dist/esm/src/verification/clusterLockValidationWorker.js +9 -3
  17. package/dist/esm/src/verification/clusterLockValidationWorker.js.map +1 -1
  18. package/dist/esm/src/verification/parallelPool.js +1 -1
  19. package/dist/types/src/base.d.ts +5 -3
  20. package/dist/types/src/errors.d.ts +22 -4
  21. package/dist/types/src/index.d.ts +5 -6
  22. package/dist/types/src/services.d.ts +6 -3
  23. package/dist/types/src/verification/parallelPool.d.ts +4 -0
  24. package/dist/types/src/verification/validationConcurrency.d.ts +11 -0
  25. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  26. package/package.json +3 -3
  27. package/dist/esm/src/chunk-5ASVONSJ.js.map +0 -1
  28. package/dist/esm/src/chunk-RYTIXFRX.js.map +0 -1
  29. package/dist/types/test/client/ajv.spec.d.ts +0 -1
  30. package/dist/types/test/client/methods.spec.d.ts +0 -18
  31. package/dist/types/test/eoa/eoa.spec.d.ts +0 -1
  32. package/dist/types/test/exit/ethUtils.spec.d.ts +0 -1
  33. package/dist/types/test/exit/exit.spec.d.ts +0 -1
  34. package/dist/types/test/exit/verificationHelpers.spec.d.ts +0 -1
  35. package/dist/types/test/fixtures.d.ts +0 -359
  36. package/dist/types/test/incentives/incentives.spec.d.ts +0 -1
  37. package/dist/types/test/splits/splits.spec.d.ts +0 -1
  38. package/dist/types/test/verification/parallelPool.spec.d.ts +0 -1
package/README.md CHANGED
@@ -39,11 +39,13 @@ Checkout our [docs](https://docs.obol.org/docs/advanced/quickstart-sdk), [exampl
39
39
  ## Terms and Conditions
40
40
  To use obol-sdk and in order to be able to create a cluster definition or accept an invite to join a cluster, you must accept the [latest Obol terms and conditions](https://obol.org/terms.pdf) by calling acceptObolLatestTermsAndConditions.
41
41
 
42
- ## ⚠️ Important Security Notice:
43
- If you're integrating this SDK with a **backend** (e.g., in Node.js), and you store a private key for executing splitter transactions, handle it with extreme caution. Ensure that:
42
+ ## Security
44
43
 
45
- - The private key is securely stored (e.g., in an `.env` file).
46
- - Never commit or push your `.env` file containing the private key to version control.
44
+ **API host:** `baseUrl` must be one of `https://api.obol.tech`, `https://obol-api-nonprod-dev.dev.obol.tech`, or `https://obol-api-nonprod-qa.dev.obol.tech` (no path suffix). Endpoints are still called as `/v1/...` as before. Any other value throws `InvalidBaseUrlError`.
45
+
46
+ **RPC URLs:** Set `RPC_MAINNET`, `RPC_HOODI`, etc. in your own app or pass an explicit provider/RPC to the client. The SDK does not load a `.env` file on import.
47
+
48
+ **Private keys:** If you use a backend signer, store keys securely (KMS, HSM, or env vars your app loads explicitly). Never commit secrets to version control.
47
49
 
48
50
  ## ⚡️ Integration with Safe Wallet
49
51
 
@@ -98,7 +98,7 @@ import { v4 as uuidv4 } from "uuid";
98
98
  // package.json
99
99
  var package_default = {
100
100
  name: "@obolnetwork/obol-sdk",
101
- version: "2.12.1",
101
+ version: "2.12.4",
102
102
  description: "A package for creating Distributed Validators using the Obol API.",
103
103
  bugs: {
104
104
  url: "https://github.com/obolnetwork/obol-sdk/issues"
@@ -113,7 +113,7 @@ var package_default = {
113
113
  "build:clean": "rm -rf ./dist",
114
114
  build: "npm-run-all build:clean build:tsup",
115
115
  "build:tsup": "tsup && tsc -b ./tsconfig.types.json",
116
- test: "NODE_OPTIONS=--experimental-vm-modules jest test/**/**.spec.ts --testPathIgnorePatterns=test/sdk-package/",
116
+ test: "NODE_OPTIONS=--experimental-vm-modules OBOL_SDK_MAX_CONCURRENT_LOCK_VALIDATIONS=0 jest test/**/**.spec.ts --testPathIgnorePatterns=test/sdk-package/",
117
117
  "generate-typedoc": "typedoc",
118
118
  "npm:publish": "npm publish --tag latest",
119
119
  "npm:publish:next": "npm publish --tag next",
@@ -176,7 +176,6 @@ var package_default = {
176
176
  "ajv-formats": "3.0.1",
177
177
  "ajv-keywords": "5.1.0",
178
178
  "cross-fetch": "4.1.0",
179
- dotenv: "17.4.2",
180
179
  elliptic: "6.6.1",
181
180
  ethers: "6.16.0",
182
181
  semver: "7.7.4",
@@ -189,6 +188,7 @@ var package_default = {
189
188
  "@types/node": "24.12.2",
190
189
  "@types/semver": "7.7.1",
191
190
  "@types/uuid": "9.0.8",
191
+ dotenv: "17.4.2",
192
192
  "@typescript-eslint/eslint-plugin": "6.21.0",
193
193
  "@typescript-eslint/parser": "6.21.0",
194
194
  eslint: "8.57.1",
@@ -316,8 +316,6 @@ var MAINNET_SPLIT_V2_FACTORY_BYTECODE = "0x6080604090808252600480361015610015575
316
316
  var HOODI_SPLIT_V2_FACTORY_BYTECODE = "0x6080604090808252600480361015610015575f80fd5b5f3560e01c9182632556fa391461043c5750816380ebf0ab146102be5781639e317f121461027a578163cd6bc1211461023f578163e9889edd1461016d578163f79918b0146100de575063fc6119b11461006d575f80fd5b346100da575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100da576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f9c25250523df26343222fc46de932355b850c97168152f35b5f80fd5b82346100da577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc916080833601126100da5780359267ffffffffffffffff84116100da5760809084360301126100da5761016573ffffffffffffffffffffffffffffffffffffffff916020946101526105e7565b61015a61060a565b91606435930161090f565b915191168152f35b82346100da5760209073ffffffffffffffffffffffffffffffffffffffff6101656101a061019a3661062d565b91610b37565b309061023a7f000000000000000000000000f9c25250523df26343222fc46de932355b850c9790604051916c5af43d3d93803e605757fd5bf36051526044526f593da1005b3d3d3d3d363d3d37363d736030527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6020527060593d8160093d39f336602c57343d527f5f526071600f20916040525f606052565b610b7a565b82346100da576102546101a061019a3661062d565b803b151573ffffffffffffffffffffffffffffffffffffffff8351921682526020820152f35b82346100da5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100da57602091355f525f8252805f20549051908152f35b82346100da577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9181833601126100da5780359267ffffffffffffffff84116100da5760809084360301126100da5761016561039c73ffffffffffffffffffffffffffffffffffffffff9261034a6103766103376105e7565b875192839160209a8b84019601866107c7565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610858565b519020805f525f8652845f205490855191878301528682526103978261083c565b6108c2565b848151910120309061023a7f000000000000000000000000f9c25250523df26343222fc46de932355b850c9790604051916c5af43d3d93803e605757fd5bf36051526044526f593da1005b3d3d3d3d363d3d37363d736030527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6020527060593d8160093d39f336602c57343d527f5f526071600f20916040525f606052565b9083346100da577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060813601126100da5782359067ffffffffffffffff82116100da5760809082850192360301126100da576104976105e7565b6105286104a261060a565b6104e4602097888101906104bb8161034a888a866107c7565b519020805f525f8952865f20908154916001830190558751918a8301528982526103978261083c565b73ffffffffffffffffffffffffffffffffffffffff9281898593519101207f000000000000000000000000f9c25250523df26343222fc46de932355b850c97610aae565b1695863b156100da575f858592610569895194859384937fbaa7fda400000000000000000000000000000000000000000000000000000000855284016107c7565b0381838b5af180156105dd57928795927fb3ec24e9259e438f9917b49f27c0dd89a11b7626cb63e6fc977863c0b26a681b95926105ba956105ce575b508188519586956060875260608701906106f5565b93168a85015216868301520390a251908152f35b6105d7906107fb565b8a6105a5565b86513d5f823e3d90fd5b6024359073ffffffffffffffffffffffffffffffffffffffff821682036100da57565b6044359073ffffffffffffffffffffffffffffffffffffffff821682036100da57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc906060828201126100da576004359167ffffffffffffffff83116100da57826080920301126100da576004019060243573ffffffffffffffffffffffffffffffffffffffff811681036100da579060443590565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156100da57016020813591019167ffffffffffffffff82116100da578160051b360383136100da57565b6080820161070382806106a2565b608085529182905260a08401915f905b80821061078f5750505061072a60208301836106a2565b909284830360208601528183527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82116100da5760609160051b8094602085013760408101356040860152013561ffff81168091036100da5760606020940152010190565b90919283359073ffffffffffffffffffffffffffffffffffffffff82168092036100da57600191815260208091019401920190610713565b9073ffffffffffffffffffffffffffffffffffffffff6107f46020929594956040855260408501906106f5565b9416910152565b67ffffffffffffffff811161080f57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761080f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761080f57604052565b908151915f5b8381106108af575050015f815290565b806020809284010151818501520161089f565b61090d909291926108e160405194859260208401526040830190610899565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283610858565b565b93929161091d838387610b37565b7f000000000000000000000000f9c25250523df26343222fc46de932355b850c976109bb308361023a8490604051916c5af43d3d93803e605757fd5bf36051526044526f593da1005b3d3d3d3d363d3d37363d736030527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6020527060593d8160093d39f336602c57343d527f5f526071600f20916040525f606052565b803b610aa55750906109cc91610aae565b9473ffffffffffffffffffffffffffffffffffffffff9283871694853b156100da57604051947fbaa7fda40000000000000000000000000000000000000000000000000000000086525f8680610a268688600484016107c7565b0381838b5af1948515610a9a577fc4cec5a1846f5c98dc275670618bfecffec4da2e7cba63760ef46f38c75d236e96610a7496610a8b575b50816040519687966080885260808801906106f5565b9416602086015216604084015260608301520390a2565b610a94906107fb565b5f610a5e565b6040513d5f823e3d90fd5b96505050505050565b9190604051926c5af43d3d93803e605757fd5bf36051526044526f593da1005b3d3d3d3d363d3d37363d736030527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6020527060593d8160093d39f336602c57343d527f5f526071600f5ff5916040525f6060528115610b2a57565b63301164255f526004601cfd5b6040519291610b4f9184916108e191602084016107c7565b610b7460206040518093610b668383018097610899565b908152038084520182610858565b51902090565b91909160ff5f5360355260601b60015260155260555f20905f60355256fea2646970667358221220edd55753c55f257991df670fc562cdf54adb62d710125933fc4a0a7afddbc02564736f6c63430008170033";
317
317
 
318
318
  // src/constants.ts
319
- import * as dotenv from "dotenv";
320
- dotenv.config();
321
319
  var CONFLICT_ERROR_MSG = "Conflict";
322
320
  var EIP712_DOMAIN_NAME = "Obol";
323
321
  var EIP712_DOMAIN_VERSION = "1";
@@ -526,40 +524,6 @@ var CAPELLA_FORK_MAPPING = {
526
524
  // Hoodi
527
525
  };
528
526
 
529
- // src/base.ts
530
- var Base = class {
531
- constructor({
532
- baseUrl = DEFAULT_BASE_URL,
533
- chainId = DEFAULT_CHAIN_ID
534
- }) {
535
- this.baseUrl = baseUrl;
536
- this.chainId = chainId;
537
- this.fork_version = FORK_MAPPING[this.chainId];
538
- }
539
- request(endpoint, options) {
540
- return __async(this, null, function* () {
541
- const url = `${this.baseUrl}${endpoint}`;
542
- const config2 = __spreadProps(__spreadValues({}, options), {
543
- headers: __spreadValues({
544
- "Content-Type": "application/json",
545
- "User-Agent": `Obol-SDK/${SDK_VERSION}`
546
- }, options == null ? void 0 : options.headers)
547
- });
548
- try {
549
- const response = yield fetch(url, config2);
550
- if (response.ok) {
551
- return yield response.json();
552
- } else {
553
- const errorResponse = yield response.json();
554
- throw errorResponse;
555
- }
556
- } catch (e) {
557
- throw e;
558
- }
559
- });
560
- }
561
- };
562
-
563
527
  // src/errors.ts
564
528
  var ConflictError = class _ConflictError extends Error {
565
529
  constructor() {
@@ -582,9 +546,17 @@ var UnsupportedChainError = class _UnsupportedChainError extends Error {
582
546
  Object.setPrototypeOf(this, _UnsupportedChainError.prototype);
583
547
  }
584
548
  };
549
+ var InvalidBaseUrlError = class _InvalidBaseUrlError extends Error {
550
+ constructor(message2) {
551
+ super(message2);
552
+ this.name = "InvalidBaseUrlError";
553
+ Object.setPrototypeOf(this, _InvalidBaseUrlError.prototype);
554
+ }
555
+ };
585
556
  var ClusterLockValidationTimeoutError = class _ClusterLockValidationTimeoutError extends Error {
586
557
  /**
587
- * @param timeoutMs - Same value as SDK whole-lock validation worker timeout.
558
+ * @param timeoutMs - Worker deadline that was exceeded (`VALIDATION_WORKER_TIMEOUT_MS`
559
+ * for the whole-lock worker, `WORKER_TIMEOUT_MS` for per-chunk BLS workers).
588
560
  */
589
561
  constructor(timeoutMs) {
590
562
  super(
@@ -595,6 +567,68 @@ var ClusterLockValidationTimeoutError = class _ClusterLockValidationTimeoutError
595
567
  Object.setPrototypeOf(this, _ClusterLockValidationTimeoutError.prototype);
596
568
  }
597
569
  };
570
+ var ClusterLockValidationBusyError = class _ClusterLockValidationBusyError extends Error {
571
+ constructor(maxConcurrent) {
572
+ super(
573
+ `Too many cluster lock validations in progress (limit: ${maxConcurrent}). Retry later.`
574
+ );
575
+ this.maxConcurrent = maxConcurrent;
576
+ this.name = "ClusterLockValidationBusyError";
577
+ Object.setPrototypeOf(this, _ClusterLockValidationBusyError.prototype);
578
+ }
579
+ };
580
+
581
+ // src/base.ts
582
+ var ALLOWED_OBOL_API_BASE_URLS = [
583
+ DEFAULT_BASE_URL,
584
+ "https://obol-api-nonprod-dev.dev.obol.tech",
585
+ "https://obol-api-nonprod-qa.dev.obol.tech"
586
+ ];
587
+ var ALLOWED_BASE_URLS = new Set(ALLOWED_OBOL_API_BASE_URLS);
588
+ function assertAllowedBaseUrl(baseUrl) {
589
+ let candidate = baseUrl.trim();
590
+ while (candidate.endsWith("/")) {
591
+ candidate = candidate.slice(0, -1);
592
+ }
593
+ if (!ALLOWED_BASE_URLS.has(candidate)) {
594
+ throw new InvalidBaseUrlError(
595
+ `baseUrl must be one of: ${ALLOWED_OBOL_API_BASE_URLS.join(", ")}`
596
+ );
597
+ }
598
+ return candidate;
599
+ }
600
+ var Base = class {
601
+ constructor({
602
+ baseUrl = DEFAULT_BASE_URL,
603
+ chainId = DEFAULT_CHAIN_ID
604
+ }) {
605
+ this.baseUrl = assertAllowedBaseUrl(baseUrl);
606
+ this.chainId = chainId;
607
+ this.fork_version = FORK_MAPPING[this.chainId];
608
+ }
609
+ request(endpoint, options) {
610
+ return __async(this, null, function* () {
611
+ const url = `${this.baseUrl}${endpoint}`;
612
+ const config = __spreadProps(__spreadValues({}, options), {
613
+ headers: __spreadValues({
614
+ "Content-Type": "application/json",
615
+ "User-Agent": `Obol-SDK/${SDK_VERSION}`
616
+ }, options == null ? void 0 : options.headers)
617
+ });
618
+ try {
619
+ const response = yield fetch(url, config);
620
+ if (response.ok) {
621
+ return yield response.json();
622
+ } else {
623
+ const errorResponse = yield response.json();
624
+ throw errorResponse;
625
+ }
626
+ } catch (e) {
627
+ throw e;
628
+ }
629
+ });
630
+ }
631
+ };
598
632
 
599
633
  // src/verification/common.ts
600
634
  import { fromHexString as fromHexString6 } from "@chainsafe/ssz";
@@ -5254,6 +5288,9 @@ var MIN_KEYS_PER_WORKER_AGG = 100;
5254
5288
  var MIN_VALIDATORS_FOR_VALIDATION_WORKER = 50;
5255
5289
  var VALIDATION_WORKER_TIMEOUT_MS = 12e4;
5256
5290
  var WORKER_TIMEOUT_MS = 6e4;
5291
+ function isValidationTimeoutReply(msg) {
5292
+ return typeof msg === "object" && msg !== null && "validationTimeoutMs" in msg && typeof msg.validationTimeoutMs === "number";
5293
+ }
5257
5294
  var MAX_CONCURRENT_WORKERS_CAP = 8;
5258
5295
  function maxConcurrentWorkers(numWorkers) {
5259
5296
  return Math.min(numWorkers, MAX_CONCURRENT_WORKERS_CAP);
@@ -5350,7 +5387,7 @@ function verifySharesSync(shares, distributedKeys, threshold) {
5350
5387
  }
5351
5388
  function runWorkerAggregatePubkeys(wt, workerFile, data) {
5352
5389
  return __async(this, null, function* () {
5353
- return yield new Promise((resolve) => {
5390
+ return yield new Promise((resolve, reject) => {
5354
5391
  let settled = false;
5355
5392
  const worker = new wt.Worker(workerFile, { workerData: data });
5356
5393
  const finish = (result) => {
@@ -5361,7 +5398,11 @@ function runWorkerAggregatePubkeys(wt, workerFile, data) {
5361
5398
  resolve(result);
5362
5399
  };
5363
5400
  const timer = setTimeout(() => {
5364
- finish(null);
5401
+ if (settled) return;
5402
+ settled = true;
5403
+ clearTimeout(timer);
5404
+ worker.terminate();
5405
+ reject(new ClusterLockValidationTimeoutError(WORKER_TIMEOUT_MS));
5365
5406
  }, WORKER_TIMEOUT_MS);
5366
5407
  worker.once("message", (msg) => {
5367
5408
  finish(msg instanceof Uint8Array ? msg : null);
@@ -5377,7 +5418,7 @@ function runWorkerAggregatePubkeys(wt, workerFile, data) {
5377
5418
  }
5378
5419
  function runWorker(wt, workerFile, data) {
5379
5420
  return __async(this, null, function* () {
5380
- return yield new Promise((resolve) => {
5421
+ return yield new Promise((resolve, reject) => {
5381
5422
  let settled = false;
5382
5423
  const worker = new wt.Worker(workerFile, { workerData: data });
5383
5424
  const finish = (result) => {
@@ -5388,7 +5429,11 @@ function runWorker(wt, workerFile, data) {
5388
5429
  resolve(result);
5389
5430
  };
5390
5431
  const timer = setTimeout(() => {
5391
- finish(false);
5432
+ if (settled) return;
5433
+ settled = true;
5434
+ clearTimeout(timer);
5435
+ worker.terminate();
5436
+ reject(new ClusterLockValidationTimeoutError(WORKER_TIMEOUT_MS));
5392
5437
  }, WORKER_TIMEOUT_MS);
5393
5438
  worker.once("message", (msg) => {
5394
5439
  finish(msg === true);
@@ -5532,15 +5577,7 @@ function validateClusterLockInWorker(lock, safeRpcUrl) {
5532
5577
  const worker = new wt.Worker(workerFile, {
5533
5578
  workerData: { lock, safeRpcUrl }
5534
5579
  });
5535
- let timer;
5536
- const finish = (result) => {
5537
- if (settled) return;
5538
- settled = true;
5539
- clearTimeout(timer);
5540
- worker.terminate();
5541
- resolve(result);
5542
- };
5543
- timer = setTimeout(() => {
5580
+ const timer = setTimeout(() => {
5544
5581
  if (settled) return;
5545
5582
  settled = true;
5546
5583
  clearTimeout(timer);
@@ -5549,7 +5586,22 @@ function validateClusterLockInWorker(lock, safeRpcUrl) {
5549
5586
  new ClusterLockValidationTimeoutError(VALIDATION_WORKER_TIMEOUT_MS)
5550
5587
  );
5551
5588
  }, VALIDATION_WORKER_TIMEOUT_MS);
5589
+ const finish = (result) => {
5590
+ if (settled) return;
5591
+ settled = true;
5592
+ clearTimeout(timer);
5593
+ worker.terminate();
5594
+ resolve(result);
5595
+ };
5552
5596
  worker.once("message", (msg) => {
5597
+ if (isValidationTimeoutReply(msg)) {
5598
+ if (settled) return;
5599
+ settled = true;
5600
+ clearTimeout(timer);
5601
+ worker.terminate();
5602
+ reject(new ClusterLockValidationTimeoutError(msg.validationTimeoutMs));
5603
+ return;
5604
+ }
5553
5605
  finish(msg === true);
5554
5606
  });
5555
5607
  worker.once("error", () => {
@@ -16174,6 +16226,9 @@ var isValidClusterLock = (clusterLock, safeRpcUrl) => __async(null, null, functi
16174
16226
  }
16175
16227
  return true;
16176
16228
  } catch (err) {
16229
+ if (err instanceof ClusterLockValidationTimeoutError) {
16230
+ throw err;
16231
+ }
16177
16232
  return false;
16178
16233
  }
16179
16234
  });
@@ -19532,11 +19587,11 @@ var encodeCreateSplitV2DeterministicTxData = (splitParams, splitOwnerAddress, sa
19532
19587
  );
19533
19588
  };
19534
19589
  var getChainConfig = (chainId) => {
19535
- const config2 = CHAIN_CONFIGURATION[chainId];
19536
- if (!config2) {
19590
+ const config = CHAIN_CONFIGURATION[chainId];
19591
+ if (!config) {
19537
19592
  throw new Error(`Chain configuration not found for chain ID ${chainId}`);
19538
19593
  }
19539
- return config2;
19594
+ return config;
19540
19595
  };
19541
19596
  var requestWithdrawalFromOVM = (_0) => __async(null, [_0], function* ({
19542
19597
  ovmAddress,
@@ -21114,15 +21169,40 @@ var EOA = class {
21114
21169
  }
21115
21170
  };
21116
21171
 
21172
+ // src/verification/validationConcurrency.ts
21173
+ function getMaxConcurrentLockValidations() {
21174
+ const raw = define_process_env_default.OBOL_SDK_MAX_CONCURRENT_LOCK_VALIDATIONS;
21175
+ if (raw === "0") return 0;
21176
+ if (raw !== void 0 && raw !== "") {
21177
+ const n = Number.parseInt(raw, 10);
21178
+ if (Number.isFinite(n) && n > 0) return n;
21179
+ }
21180
+ return 2;
21181
+ }
21182
+ var activeValidations = 0;
21183
+ function withLockValidationConcurrency(fn) {
21184
+ return __async(this, null, function* () {
21185
+ const max = getMaxConcurrentLockValidations();
21186
+ if (max === 0) return yield fn();
21187
+ if (activeValidations >= max) {
21188
+ throw new ClusterLockValidationBusyError(max);
21189
+ }
21190
+ activeValidations++;
21191
+ try {
21192
+ return yield fn();
21193
+ } finally {
21194
+ activeValidations--;
21195
+ }
21196
+ });
21197
+ }
21198
+
21117
21199
  // src/services.ts
21118
21200
  var validateClusterLock = (lock, safeRpcUrl) => __async(null, null, function* () {
21119
- try {
21201
+ return yield withLockValidationConcurrency(() => __async(null, null, function* () {
21120
21202
  const inWorker = yield validateClusterLockInWorker(lock, safeRpcUrl);
21121
21203
  if (inWorker !== null) return inWorker;
21122
21204
  return yield isValidClusterLock(lock, safeRpcUrl);
21123
- } catch (err) {
21124
- throw err;
21125
- }
21205
+ }));
21126
21206
  });
21127
21207
 
21128
21208
  // src/index.ts
@@ -21132,6 +21212,7 @@ var Client = class extends Base {
21132
21212
  *
21133
21213
  * @param config - Client configuration object.
21134
21214
  * @param config.baseUrl - Obol API base URL. Defaults to `https://api.obol.tech`.
21215
+ * Must match one of {@link ALLOWED_OBOL_API_BASE_URLS} (API paths use `/v1/...` separately).
21135
21216
  * @param config.chainId - Target chain ID. Defaults to `560048` (Hoodi).
21136
21217
  * Supported: 1 (Mainnet), 560048 (Hoodi), 100 (Gnosis), 11155111 (Sepolia).
21137
21218
  * @param signer - An ethers `Wallet` or `JsonRpcSigner`. Required for any
@@ -21149,8 +21230,8 @@ var Client = class extends Base {
21149
21230
  * const client = new Client({ chainId: 560048 }, signer);
21150
21231
  * ```
21151
21232
  */
21152
- constructor(config2, signer, provider) {
21153
- super(config2);
21233
+ constructor(config, signer, provider) {
21234
+ super(config);
21154
21235
  this.signer = signer;
21155
21236
  this.provider = provider != null ? provider : signer && "provider" in signer ? signer.provider : void 0;
21156
21237
  this.incentives = new Incentives(
@@ -21712,12 +21793,14 @@ var Client = class extends Base {
21712
21793
  }
21713
21794
  };
21714
21795
  export {
21796
+ ALLOWED_OBOL_API_BASE_URLS,
21715
21797
  AVAILABLE_SPLITTER_CHAINS,
21716
21798
  CAPELLA_FORK_MAPPING,
21717
21799
  CHAIN_CONFIGURATION,
21718
21800
  CONFIG_VERSION,
21719
21801
  CONFLICT_ERROR_MSG,
21720
21802
  Client,
21803
+ ClusterLockValidationBusyError,
21721
21804
  ClusterLockValidationTimeoutError,
21722
21805
  ConflictError,
21723
21806
  CreatorConfigHashSigningTypes,
@@ -21744,6 +21827,7 @@ export {
21744
21827
  FORK_NAMES,
21745
21828
  GENESIS_VALIDATOR_ROOT,
21746
21829
  Incentives,
21830
+ InvalidBaseUrlError,
21747
21831
  OBOL_SDK_EMAIL,
21748
21832
  ObolSplits,
21749
21833
  OperatorConfigHashSigningTypes,