@unicitylabs/sphere-sdk 0.14.10 → 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.
- package/dist/connect/index.cjs +1 -1
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +1 -1
- package/dist/connect/index.js.map +1 -1
- package/dist/core/index.cjs +139 -16
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +139 -16
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +1 -1
- package/dist/impl/browser/connect/index.cjs.map +1 -1
- package/dist/impl/browser/connect/index.js +1 -1
- package/dist/impl/browser/connect/index.js.map +1 -1
- package/dist/index.cjs +139 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +139 -16
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +139 -16
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.d.cts +6 -2
- package/dist/modules/payments-v2/index.d.ts +6 -2
- package/dist/modules/payments-v2/index.js +139 -16
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1645,6 +1645,90 @@ async function splitOpIndex(deps, envelope) {
|
|
|
1645
1645
|
return Array.isArray(payload.direct) ? payload.direct.length : 0;
|
|
1646
1646
|
}
|
|
1647
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
|
+
|
|
1648
1732
|
// modules/payments-v2/inventory/presentation.ts
|
|
1649
1733
|
function toToken(tokenId, snapshot, asset, registry, flags) {
|
|
1650
1734
|
const iconUrl = registry.getIconUrl(asset.coinId);
|
|
@@ -1731,6 +1815,13 @@ function priceOne(asset, quote) {
|
|
|
1731
1815
|
fiatValueEur: quote.priceEur != null ? human * quote.priceEur : null
|
|
1732
1816
|
};
|
|
1733
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
|
+
}
|
|
1734
1825
|
|
|
1735
1826
|
// modules/payments-v2/machine/payload.ts
|
|
1736
1827
|
function buildPayload(recipientPubkey, request, spend, spentStates) {
|
|
@@ -2819,6 +2910,15 @@ var InventoryView = class {
|
|
|
2819
2910
|
}
|
|
2820
2911
|
return out;
|
|
2821
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
|
+
}
|
|
2822
2922
|
tokens(registry, filter) {
|
|
2823
2923
|
const out = [];
|
|
2824
2924
|
for (const [tokenId, entry] of this.mirror) {
|
|
@@ -3830,6 +3930,31 @@ var SpendQueue = class {
|
|
|
3830
3930
|
}
|
|
3831
3931
|
return { kind: "queued", settled: this.enqueue(reservationId, request.coinId, amount) };
|
|
3832
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
|
+
}
|
|
3833
3958
|
// Coverage math: free + Σ declared expected change of in-flight sends —
|
|
3834
3959
|
// never the full amount of in-flight sources (§5.3).
|
|
3835
3960
|
declareExpectedChange(transferId, coinId, amount) {
|
|
@@ -4179,6 +4304,7 @@ var PaymentsFacade = class {
|
|
|
4179
4304
|
now: () => this.nowMs()
|
|
4180
4305
|
});
|
|
4181
4306
|
}
|
|
4307
|
+
prewarmed = new PrewarmCache();
|
|
4182
4308
|
view;
|
|
4183
4309
|
ledger;
|
|
4184
4310
|
queue;
|
|
@@ -4272,6 +4398,15 @@ var PaymentsFacade = class {
|
|
|
4272
4398
|
return derivePendingTransfers(this.machineStores, this.machineDeps.decryptPayload);
|
|
4273
4399
|
}
|
|
4274
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
|
+
}
|
|
4275
4410
|
send(request) {
|
|
4276
4411
|
return this.track(this.sendOutcome(request));
|
|
4277
4412
|
}
|
|
@@ -4481,7 +4616,7 @@ var PaymentsFacade = class {
|
|
|
4481
4616
|
}
|
|
4482
4617
|
async materialize(transferId, recipientPubkey, request, spend, sourceIds) {
|
|
4483
4618
|
const engine = this.engine();
|
|
4484
|
-
const blobs = await this.
|
|
4619
|
+
const blobs = await takeSourceBlobs(this.warmDeps(), sourceIds);
|
|
4485
4620
|
const sources = /* @__PURE__ */ new Map();
|
|
4486
4621
|
const sourceTokens = [];
|
|
4487
4622
|
const spentStates = {};
|
|
@@ -4494,7 +4629,7 @@ var PaymentsFacade = class {
|
|
|
4494
4629
|
const keys = await engine.deliveryKeys(bytes);
|
|
4495
4630
|
spentStates[tokenId] = { local: keys.stateHash, protocol: keys.stateHash };
|
|
4496
4631
|
sources.set(tokenId, token);
|
|
4497
|
-
sourceTokens.push(
|
|
4632
|
+
sourceTokens.push(transferringToken(tokenId, request.coinId, engine.balanceOf(token, request.coinId), this.deps.registry, this.nowMs()));
|
|
4498
4633
|
}
|
|
4499
4634
|
const payload = buildPayload(recipientPubkey, request, spend, spentStates);
|
|
4500
4635
|
const plan = {
|
|
@@ -4638,7 +4773,7 @@ var PaymentsFacade = class {
|
|
|
4638
4773
|
await this.machineStores.mintJournal.upsert(entry);
|
|
4639
4774
|
let token;
|
|
4640
4775
|
try {
|
|
4641
|
-
token = await engine.mint(this.
|
|
4776
|
+
token = await engine.mint(mintParams(this.ownPubkeyBytes, coinId, amount), { transferId: mintId });
|
|
4642
4777
|
} catch (err) {
|
|
4643
4778
|
this.heartbeat.arm();
|
|
4644
4779
|
return { success: false, error: messageOf(err) };
|
|
@@ -4697,7 +4832,7 @@ var PaymentsFacade = class {
|
|
|
4697
4832
|
});
|
|
4698
4833
|
return false;
|
|
4699
4834
|
}
|
|
4700
|
-
const token = await engine.mint(this.
|
|
4835
|
+
const token = await engine.mint(mintParams(this.ownPubkeyBytes, entry.coinId, BigInt(entry.amount)), {
|
|
4701
4836
|
transferId: entry.mintId
|
|
4702
4837
|
});
|
|
4703
4838
|
if (token.blob.tokenId !== entry.tokenId) {
|
|
@@ -4706,12 +4841,6 @@ var PaymentsFacade = class {
|
|
|
4706
4841
|
await this.finalizeMint(engine, entry.mintId, token, entry.coinId, entry.amount);
|
|
4707
4842
|
return true;
|
|
4708
4843
|
}
|
|
4709
|
-
mintParams(coinId, amount) {
|
|
4710
|
-
return {
|
|
4711
|
-
recipientPubkey: this.ownPubkeyBytes,
|
|
4712
|
-
value: { assets: [{ coinId, amount }] }
|
|
4713
|
-
};
|
|
4714
|
-
}
|
|
4715
4844
|
async tokenInServerInventory(tokenId) {
|
|
4716
4845
|
let page = await this.deps.storagePort.listInventory();
|
|
4717
4846
|
for (let i = 0; i < INVENTORY_SCAN_PAGE_LIMIT; i++) {
|
|
@@ -4740,12 +4869,6 @@ var PaymentsFacade = class {
|
|
|
4740
4869
|
page = await this.deps.storagePort.listInventory(page.cursor);
|
|
4741
4870
|
}
|
|
4742
4871
|
}
|
|
4743
|
-
toUiToken(tokenId, coinId, amount) {
|
|
4744
|
-
const now = this.nowMs();
|
|
4745
|
-
const snapshot = { assets: [], createdAt: now, updatedAt: now };
|
|
4746
|
-
const flags = { transferring: true, suspectedSpent: false };
|
|
4747
|
-
return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, this.deps.registry, flags);
|
|
4748
|
-
}
|
|
4749
4872
|
track(op) {
|
|
4750
4873
|
const settled = op.then(() => void 0, () => void 0);
|
|
4751
4874
|
this.pendingOps.add(settled);
|