@unicitylabs/sphere-sdk 0.14.3 → 0.14.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.
@@ -42,6 +42,7 @@ var import_CertificationResponse = require("@unicitylabs/state-transition-sdk/li
42
42
  var import_StateId = require("@unicitylabs/state-transition-sdk/lib/api/StateId.js");
43
43
  var import_InclusionProof = require("@unicitylabs/state-transition-sdk/lib/api/InclusionProof.js");
44
44
  var import_InclusionProofResponse = require("@unicitylabs/state-transition-sdk/lib/api/InclusionProofResponse.js");
45
+ var import_JsonRpcNetworkError = require("@unicitylabs/state-transition-sdk/lib/api/json-rpc/JsonRpcNetworkError.js");
45
46
  var import_RootTrustBase = require("@unicitylabs/state-transition-sdk/lib/api/bft/RootTrustBase.js");
46
47
  var import_InclusionProofUtils = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils.js");
47
48
  var import_InclusionProofVerificationRule = require("@unicitylabs/state-transition-sdk/lib/transaction/verification/rule/InclusionProofVerificationRule.js");
@@ -319,6 +320,86 @@ function decodeSpherePaymentData(bytes) {
319
320
  return Promise.resolve(SpherePaymentData.fromCBOR(bytes));
320
321
  }
321
322
 
323
+ // token-engine/proof-wait.ts
324
+ var DEFAULT_PROOF_TIMEOUT_MS = 1e4;
325
+ function resolveProofTimeoutMs(configured) {
326
+ if (configured === void 0) return DEFAULT_PROOF_TIMEOUT_MS;
327
+ if (!Number.isFinite(configured) || configured <= 0) {
328
+ throw new SphereError(
329
+ `proofTimeoutMs must be a positive number of milliseconds (got ${String(configured)}); an unbounded inclusion-proof wait is not supported`,
330
+ "INVALID_CONFIG"
331
+ );
332
+ }
333
+ return configured;
334
+ }
335
+ function lateDeliveringSignal(signal) {
336
+ return new Proxy(signal, {
337
+ get(target, prop) {
338
+ if (prop === "addEventListener") {
339
+ return (type, listener, options) => {
340
+ if (type === "abort" && target.aborted) {
341
+ queueMicrotask(() => {
342
+ listener.call(target, new Event("abort"));
343
+ });
344
+ return;
345
+ }
346
+ target.addEventListener(type, listener, options);
347
+ };
348
+ }
349
+ const value = Reflect.get(target, prop, target);
350
+ return typeof value === "function" ? value.bind(target) : value;
351
+ }
352
+ });
353
+ }
354
+ function rejectOnAbort(signal) {
355
+ return new Promise((_resolve, reject) => {
356
+ if (signal.aborted) {
357
+ reject(signal.reason);
358
+ return;
359
+ }
360
+ signal.addEventListener(
361
+ "abort",
362
+ () => {
363
+ reject(signal.reason);
364
+ },
365
+ { once: true }
366
+ );
367
+ });
368
+ }
369
+ async function awaitProofBounded(deps, transaction, external) {
370
+ const controller = new AbortController();
371
+ const relayAbort = () => {
372
+ controller.abort(external?.reason);
373
+ };
374
+ if (external !== void 0) {
375
+ if (external.aborted) relayAbort();
376
+ else external.addEventListener("abort", relayAbort, { once: true });
377
+ }
378
+ const timer = setTimeout(() => {
379
+ controller.abort(
380
+ new SphereError(
381
+ `inclusion proof not confirmed within ${String(deps.timeoutMs)} ms`,
382
+ "AGGREGATOR_ERROR"
383
+ )
384
+ );
385
+ }, deps.timeoutMs);
386
+ const wait = (0, import_InclusionProofUtils.waitInclusionProof)(
387
+ deps.client,
388
+ deps.trustBase,
389
+ deps.predicateVerifier,
390
+ transaction,
391
+ lateDeliveringSignal(controller.signal),
392
+ deps.intervalMs
393
+ );
394
+ wait.catch(() => void 0);
395
+ try {
396
+ return await Promise.race([wait, rejectOnAbort(controller.signal)]);
397
+ } finally {
398
+ clearTimeout(timer);
399
+ external?.removeEventListener("abort", relayAbort);
400
+ }
401
+ }
402
+
322
403
  // core/uuid.ts
323
404
  function randomUUID() {
324
405
  const c = globalThis.crypto;
@@ -976,11 +1057,13 @@ var SphereTokenEngine = class {
976
1057
  constructor(deps) {
977
1058
  this.deps = deps;
978
1059
  this.privateKeyHex = import_HexConverter.HexConverter.encode(deps.privateKey);
1060
+ this.proofTimeoutMs = resolveProofTimeoutMs(deps.proofTimeoutMs);
979
1061
  }
980
1062
  /** F13 advertisement: mint under a (transferId, opIndex) seed is idempotent-recoverable — a same-seed re-call converges, never double-mints. */
981
1063
  deterministicMint = true;
982
1064
  /** Hex form of the wallet key — deriveRealization's ikm input (Part E.1). */
983
1065
  privateKeyHex;
1066
+ proofTimeoutMs;
984
1067
  // ── identity ────────────────────────────────────────────────────────────────
985
1068
  getIdentity() {
986
1069
  return { chainPubkey: new Uint8Array(this.deps.signingService.publicKey) };
@@ -1323,14 +1406,17 @@ var SphereTokenEngine = class {
1323
1406
  submitError = err ?? new SphereError(`${failLabel}: submit failed`, failCode);
1324
1407
  }
1325
1408
  try {
1326
- return await (0, import_InclusionProofUtils.waitInclusionProof)(
1327
- this.deps.client,
1328
- this.deps.trustBase,
1329
- this.deps.predicateVerifier,
1409
+ return await awaitProofBounded(
1410
+ {
1411
+ client: this.deps.client,
1412
+ trustBase: this.deps.trustBase,
1413
+ predicateVerifier: this.deps.predicateVerifier,
1414
+ timeoutMs: this.proofTimeoutMs,
1415
+ intervalMs: this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
1416
+ // #683
1417
+ },
1330
1418
  transaction,
1331
- options?.signal,
1332
- this.deps.proofPollIntervalMs ?? DEFAULT_PROOF_POLL_INTERVAL_MS
1333
- // #683 finer poll cadence
1419
+ options?.signal
1334
1420
  );
1335
1421
  } catch (err) {
1336
1422
  if (err instanceof Error && err.message === `Invalid inclusion proof status: ${import_InclusionProofVerificationRule.InclusionProofVerificationStatus.TRANSACTION_HASH_MISMATCH}`) {
@@ -1346,6 +1432,13 @@ var SphereTokenEngine = class {
1346
1432
  );
1347
1433
  }
1348
1434
  }
1435
+ /**
1436
+ * One inclusion-proof wait, with the deadline OWNED here (#739). The SDK's own
1437
+ * default deadline is unreliable — see lateDeliveringSignal — and a lost one
1438
+ * means an op that never settles, which also wedges PaymentsFacade.stop().
1439
+ * A deadline hit throws, and the caller maps that to ProofUnconfirmedError
1440
+ * (keep-open), which is the correct posture: the spend may be on-chain.
1441
+ */
1349
1442
  /** Fail fast if this engine's key does not own the token's current state. */
1350
1443
  assertOwned(token) {
1351
1444
  if (!this.isOwnedBy(token, this.deps.signingService.publicKey)) {
@@ -1445,6 +1538,8 @@ async function createSphereTokenEngine(config) {
1445
1538
  networkId: trustBase.networkId,
1446
1539
  // #683: forward the (optional) proof-poll cadence; undefined → the engine default.
1447
1540
  proofPollIntervalMs: config.proofPollIntervalMs,
1541
+ proofTimeoutMs: config.proofTimeoutMs,
1542
+ // #739: was declared but never wired
1448
1543
  // Opt-in parallel verification (2.0.2). Absent → the sequential verifier.
1449
1544
  ...config.verification ? { tokenVerifier: createWorkerTokenVerifier(config.verification) } : {}
1450
1545
  };