@unicitylabs/sphere-sdk 0.14.9 → 0.14.11-dev.1

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 (35) hide show
  1. package/dist/connect/index.cjs +1 -1
  2. package/dist/connect/index.cjs.map +1 -1
  3. package/dist/connect/index.js +1 -1
  4. package/dist/connect/index.js.map +1 -1
  5. package/dist/core/index.cjs +156 -22
  6. package/dist/core/index.cjs.map +1 -1
  7. package/dist/core/index.d.cts +2 -0
  8. package/dist/core/index.d.ts +2 -0
  9. package/dist/core/index.js +156 -22
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/impl/browser/connect/index.cjs +1 -1
  12. package/dist/impl/browser/connect/index.cjs.map +1 -1
  13. package/dist/impl/browser/connect/index.js +1 -1
  14. package/dist/impl/browser/connect/index.js.map +1 -1
  15. package/dist/impl/wallet-api-v2/index.cjs +4 -0
  16. package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
  17. package/dist/impl/wallet-api-v2/index.js +4 -0
  18. package/dist/impl/wallet-api-v2/index.js.map +1 -1
  19. package/dist/index.cjs +156 -22
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +2 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +156 -22
  24. package/dist/index.js.map +1 -1
  25. package/dist/modules/payments-v2/index.cjs +143 -16
  26. package/dist/modules/payments-v2/index.cjs.map +1 -1
  27. package/dist/modules/payments-v2/index.d.cts +6 -2
  28. package/dist/modules/payments-v2/index.d.ts +6 -2
  29. package/dist/modules/payments-v2/index.js +143 -16
  30. package/dist/modules/payments-v2/index.js.map +1 -1
  31. package/dist/token-engine/index.cjs +17 -6
  32. package/dist/token-engine/index.cjs.map +1 -1
  33. package/dist/token-engine/index.js +17 -6
  34. package/dist/token-engine/index.js.map +1 -1
  35. package/package.json +2 -2
@@ -519,6 +519,10 @@ var import_StateMask = require("@unicitylabs/state-transition-sdk/lib/transactio
519
519
  var import_MintJustificationVerifierService = require("@unicitylabs/state-transition-sdk/lib/transaction/verification/MintJustificationVerifierService.js");
520
520
  var import_TokenIssuanceVerifierService = require("@unicitylabs/state-transition-sdk/lib/transaction/verification/TokenIssuanceVerifierService.js");
521
521
  var import_VerificationContext = require("@unicitylabs/state-transition-sdk/lib/transaction/verification/VerificationContext.js");
522
+ var import_UnicityCertificateVerifier = require("@unicitylabs/state-transition-sdk/lib/api/bft/verification/UnicityCertificateVerifier.js");
523
+ var import_UnicitySealQuorumSignaturesVerificationRule = require("@unicitylabs/state-transition-sdk/lib/api/bft/verification/rule/UnicitySealQuorumSignaturesVerificationRule.js");
524
+ var import_VerifiedSealCache = require("@unicitylabs/state-transition-sdk/lib/api/bft/verification/VerifiedSealCache.js");
525
+ var import_Secp256k1SignatureVerifier = require("@unicitylabs/state-transition-sdk/lib/crypto/secp256k1/Secp256k1SignatureVerifier.js");
522
526
  var import_WorkerTokenVerifier = require("@unicitylabs/state-transition-sdk/lib/transaction/verification/worker/WorkerTokenVerifier.js");
523
527
  var import_EncodedPredicate = require("@unicitylabs/state-transition-sdk/lib/predicate/EncodedPredicate.js");
524
528
  var import_SignaturePredicate = require("@unicitylabs/state-transition-sdk/lib/predicate/builtin/SignaturePredicate.js");
@@ -1641,6 +1645,90 @@ async function splitOpIndex(deps, envelope) {
1641
1645
  return Array.isArray(payload.direct) ? payload.direct.length : 0;
1642
1646
  }
1643
1647
 
1648
+ // modules/payments-v2/mint-params.ts
1649
+ function mintParams(recipientPubkey, coinId, amount) {
1650
+ return { recipientPubkey, value: { assets: [{ coinId, amount }] } };
1651
+ }
1652
+
1653
+ // modules/payments-v2/prewarm-cache.ts
1654
+ var PrewarmCache = class _PrewarmCache {
1655
+ entries = /* @__PURE__ */ new Map();
1656
+ generation = 0;
1657
+ static key(tokenId, stateHash) {
1658
+ return `${tokenId}:${stateHash}`;
1659
+ }
1660
+ /** Claim the cache for a warm about to start; supersedes any warm already running. */
1661
+ begin() {
1662
+ this.entries.clear();
1663
+ this.generation += 1;
1664
+ return this.generation;
1665
+ }
1666
+ /**
1667
+ * Publish a warm's result, unless it was cancelled or superseded while its
1668
+ * fetch was in flight — a cancel that only cleared what had landed so far
1669
+ * would be undone by the continuation of the very warm it cancelled.
1670
+ */
1671
+ commit(generation, warmed) {
1672
+ if (generation !== this.generation) return;
1673
+ for (const [tokenId, stateHash, bytes] of warmed) {
1674
+ this.entries.set(_PrewarmCache.key(tokenId, stateHash), bytes);
1675
+ }
1676
+ }
1677
+ get(tokenId, stateHash) {
1678
+ if (stateHash === void 0) return void 0;
1679
+ return this.entries.get(_PrewarmCache.key(tokenId, stateHash));
1680
+ }
1681
+ clear() {
1682
+ this.entries.clear();
1683
+ this.generation += 1;
1684
+ }
1685
+ get size() {
1686
+ return this.entries.size;
1687
+ }
1688
+ };
1689
+ async function warmSendSources(deps, request) {
1690
+ const ids = deps.queue.previewSelection(request);
1691
+ if (ids.length === 0) return;
1692
+ const generation = deps.cache.begin();
1693
+ const at = new Map(ids.map((id) => [id, deps.view.stateHashOf(id)]));
1694
+ let blobs;
1695
+ try {
1696
+ blobs = await deps.storagePort.getBlobs([...ids]);
1697
+ } catch {
1698
+ return;
1699
+ }
1700
+ const warmed = [];
1701
+ for (const [tokenId, bytes] of blobs) {
1702
+ const stateHash = at.get(tokenId);
1703
+ if (stateHash !== void 0) warmed.push([tokenId, stateHash, bytes]);
1704
+ }
1705
+ deps.cache.commit(generation, warmed);
1706
+ }
1707
+ async function takeSourceBlobs(deps, sourceIds) {
1708
+ const blobs = /* @__PURE__ */ new Map();
1709
+ const missing = [];
1710
+ let trustCache = deps.cache.size > 0;
1711
+ if (trustCache) {
1712
+ try {
1713
+ await deps.view.delta();
1714
+ } catch {
1715
+ trustCache = false;
1716
+ }
1717
+ }
1718
+ for (const tokenId of sourceIds) {
1719
+ const warm = trustCache ? deps.cache.get(tokenId, deps.view.stateHashOf(tokenId)) : void 0;
1720
+ if (warm === void 0) missing.push(tokenId);
1721
+ else blobs.set(tokenId, warm);
1722
+ }
1723
+ deps.cache.clear();
1724
+ if (missing.length > 0) {
1725
+ for (const [tokenId, bytes] of await deps.storagePort.getBlobs(missing)) {
1726
+ blobs.set(tokenId, bytes);
1727
+ }
1728
+ }
1729
+ return blobs;
1730
+ }
1731
+
1644
1732
  // modules/payments-v2/inventory/presentation.ts
1645
1733
  function toToken(tokenId, snapshot, asset, registry, flags) {
1646
1734
  const iconUrl = registry.getIconUrl(asset.coinId);
@@ -1727,6 +1815,13 @@ function priceOne(asset, quote) {
1727
1815
  fiatValueEur: quote.priceEur != null ? human * quote.priceEur : null
1728
1816
  };
1729
1817
  }
1818
+ function transferringToken(tokenId, coinId, amount, registry, now) {
1819
+ const snapshot = { assets: [], createdAt: now, updatedAt: now };
1820
+ return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, registry, {
1821
+ transferring: true,
1822
+ suspectedSpent: false
1823
+ });
1824
+ }
1730
1825
 
1731
1826
  // modules/payments-v2/machine/payload.ts
1732
1827
  function buildPayload(recipientPubkey, request, spend, spentStates) {
@@ -2815,6 +2910,15 @@ var InventoryView = class {
2815
2910
  }
2816
2911
  return out;
2817
2912
  }
2913
+ /**
2914
+ * Current mirrored state of an ACTIVE token, or undefined when it is unknown
2915
+ * or tombstoned. Exists so a cached blob can be state-scoped (F6): a blob is
2916
+ * only reusable while the token still sits at the state it was fetched at.
2917
+ */
2918
+ stateHashOf(tokenId) {
2919
+ const entry = this.mirror.get(tokenId);
2920
+ return entry !== void 0 && entry.status === "active" ? entry.stateHash : void 0;
2921
+ }
2818
2922
  tokens(registry, filter) {
2819
2923
  const out = [];
2820
2924
  for (const [tokenId, entry] of this.mirror) {
@@ -3826,6 +3930,31 @@ var SpendQueue = class {
3826
3930
  }
3827
3931
  return { kind: "queued", settled: this.enqueue(reservationId, request.coinId, amount) };
3828
3932
  }
3933
+ /**
3934
+ * The sources `plan()` WOULD pick right now, reserving nothing and queueing
3935
+ * nothing — a read-only probe used to warm blobs while the user is still
3936
+ * looking at the confirm screen.
3937
+ *
3938
+ * Deliberately side-effect free: reserving here would pin the user's balance
3939
+ * across think-time and strand it if they never press send. The consequence is
3940
+ * that the real `plan()` may pick differently (inventory moves, another send
3941
+ * reserves first); callers must treat the result as a HINT and tolerate a miss,
3942
+ * never as a commitment that these sources will be spent.
3943
+ */
3944
+ previewSelection(request) {
3945
+ if (this.destroyed) return [];
3946
+ let amount;
3947
+ try {
3948
+ amount = parseAmount(request.amount);
3949
+ } catch {
3950
+ return [];
3951
+ }
3952
+ const { freeView, freeTotal } = this.freeView(request.coinId);
3953
+ if (freeTotal < amount) return [];
3954
+ const plan = selectCoins(freeView, amount, { workBudget: this.deps.workBudget });
3955
+ if (plan === null) return [];
3956
+ return [...plan.direct, ...plan.split !== void 0 ? [plan.split.tokenId] : []];
3957
+ }
3829
3958
  // Coverage math: free + Σ declared expected change of in-flight sends —
3830
3959
  // never the full amount of in-flight sources (§5.3).
3831
3960
  declareExpectedChange(transferId, coinId, amount) {
@@ -4175,6 +4304,7 @@ var PaymentsFacade = class {
4175
4304
  now: () => this.nowMs()
4176
4305
  });
4177
4306
  }
4307
+ prewarmed = new PrewarmCache();
4178
4308
  view;
4179
4309
  ledger;
4180
4310
  queue;
@@ -4268,6 +4398,15 @@ var PaymentsFacade = class {
4268
4398
  return derivePendingTransfers(this.machineStores, this.machineDeps.decryptPayload);
4269
4399
  }
4270
4400
  // ── money movement ─────────────────────────────────────────────────────────
4401
+ async prewarmSend(request) {
4402
+ await warmSendSources(this.warmDeps(), request);
4403
+ }
4404
+ discardPrewarm() {
4405
+ this.prewarmed.clear();
4406
+ }
4407
+ warmDeps() {
4408
+ return { queue: this.queue, view: this.view, storagePort: this.deps.storagePort, cache: this.prewarmed };
4409
+ }
4271
4410
  send(request) {
4272
4411
  return this.track(this.sendOutcome(request));
4273
4412
  }
@@ -4477,7 +4616,7 @@ var PaymentsFacade = class {
4477
4616
  }
4478
4617
  async materialize(transferId, recipientPubkey, request, spend, sourceIds) {
4479
4618
  const engine = this.engine();
4480
- const blobs = await this.deps.storagePort.getBlobs([...sourceIds]);
4619
+ const blobs = await takeSourceBlobs(this.warmDeps(), sourceIds);
4481
4620
  const sources = /* @__PURE__ */ new Map();
4482
4621
  const sourceTokens = [];
4483
4622
  const spentStates = {};
@@ -4490,7 +4629,7 @@ var PaymentsFacade = class {
4490
4629
  const keys = await engine.deliveryKeys(bytes);
4491
4630
  spentStates[tokenId] = { local: keys.stateHash, protocol: keys.stateHash };
4492
4631
  sources.set(tokenId, token);
4493
- sourceTokens.push(this.toUiToken(tokenId, request.coinId, engine.balanceOf(token, request.coinId)));
4632
+ sourceTokens.push(transferringToken(tokenId, request.coinId, engine.balanceOf(token, request.coinId), this.deps.registry, this.nowMs()));
4494
4633
  }
4495
4634
  const payload = buildPayload(recipientPubkey, request, spend, spentStates);
4496
4635
  const plan = {
@@ -4634,7 +4773,7 @@ var PaymentsFacade = class {
4634
4773
  await this.machineStores.mintJournal.upsert(entry);
4635
4774
  let token;
4636
4775
  try {
4637
- token = await engine.mint(this.mintParams(coinId, amount), { transferId: mintId });
4776
+ token = await engine.mint(mintParams(this.ownPubkeyBytes, coinId, amount), { transferId: mintId });
4638
4777
  } catch (err) {
4639
4778
  this.heartbeat.arm();
4640
4779
  return { success: false, error: messageOf(err) };
@@ -4693,7 +4832,7 @@ var PaymentsFacade = class {
4693
4832
  });
4694
4833
  return false;
4695
4834
  }
4696
- const token = await engine.mint(this.mintParams(entry.coinId, BigInt(entry.amount)), {
4835
+ const token = await engine.mint(mintParams(this.ownPubkeyBytes, entry.coinId, BigInt(entry.amount)), {
4697
4836
  transferId: entry.mintId
4698
4837
  });
4699
4838
  if (token.blob.tokenId !== entry.tokenId) {
@@ -4702,12 +4841,6 @@ var PaymentsFacade = class {
4702
4841
  await this.finalizeMint(engine, entry.mintId, token, entry.coinId, entry.amount);
4703
4842
  return true;
4704
4843
  }
4705
- mintParams(coinId, amount) {
4706
- return {
4707
- recipientPubkey: this.ownPubkeyBytes,
4708
- value: { assets: [{ coinId, amount }] }
4709
- };
4710
- }
4711
4844
  async tokenInServerInventory(tokenId) {
4712
4845
  let page = await this.deps.storagePort.listInventory();
4713
4846
  for (let i = 0; i < INVENTORY_SCAN_PAGE_LIMIT; i++) {
@@ -4736,12 +4869,6 @@ var PaymentsFacade = class {
4736
4869
  page = await this.deps.storagePort.listInventory(page.cursor);
4737
4870
  }
4738
4871
  }
4739
- toUiToken(tokenId, coinId, amount) {
4740
- const now = this.nowMs();
4741
- const snapshot = { assets: [], createdAt: now, updatedAt: now };
4742
- const flags = { transferring: true, suspectedSpent: false };
4743
- return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, this.deps.registry, flags);
4744
- }
4745
4872
  track(op) {
4746
4873
  const settled = op.then(() => void 0, () => void 0);
4747
4874
  this.pendingOps.add(settled);