@unicitylabs/sphere-sdk 0.17.0 → 0.17.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 +170 -141
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +4 -2
- package/dist/core/index.d.ts +4 -2
- package/dist/core/index.js +170 -141
- 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 +170 -141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +170 -141
- package/dist/index.js.map +1 -1
- package/dist/modules/payments-v2/index.cjs +243 -214
- package/dist/modules/payments-v2/index.cjs.map +1 -1
- package/dist/modules/payments-v2/index.d.cts +13 -11
- package/dist/modules/payments-v2/index.d.ts +13 -11
- package/dist/modules/payments-v2/index.js +243 -214
- package/dist/modules/payments-v2/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -785,71 +785,15 @@ function createMachineStores(kv) {
|
|
|
785
785
|
};
|
|
786
786
|
}
|
|
787
787
|
|
|
788
|
-
//
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
import { JsonRpcNetworkError } from "@unicitylabs/state-transition-sdk/lib/api/json-rpc/JsonRpcNetworkError.js";
|
|
798
|
-
import { RootTrustBase } from "@unicitylabs/state-transition-sdk/lib/api/bft/RootTrustBase.js";
|
|
799
|
-
import { waitInclusionProof } from "@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils.js";
|
|
800
|
-
import { InclusionProofVerificationStatus } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/rule/InclusionProofVerificationRule.js";
|
|
801
|
-
import { Token } from "@unicitylabs/state-transition-sdk/lib/transaction/Token.js";
|
|
802
|
-
import { MintTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/MintTransaction.js";
|
|
803
|
-
import { TransferTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/TransferTransaction.js";
|
|
804
|
-
import { CertifiedMintTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/CertifiedMintTransaction.js";
|
|
805
|
-
import { CertifiedTransferTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/CertifiedTransferTransaction.js";
|
|
806
|
-
import { TokenId } from "@unicitylabs/state-transition-sdk/lib/transaction/TokenId.js";
|
|
807
|
-
import { TokenType } from "@unicitylabs/state-transition-sdk/lib/transaction/TokenType.js";
|
|
808
|
-
import { TokenSalt } from "@unicitylabs/state-transition-sdk/lib/transaction/TokenSalt.js";
|
|
809
|
-
import { StateMask } from "@unicitylabs/state-transition-sdk/lib/transaction/StateMask.js";
|
|
810
|
-
import { MintJustificationVerifierService } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/MintJustificationVerifierService.js";
|
|
811
|
-
import { TokenIssuanceVerifierService } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/TokenIssuanceVerifierService.js";
|
|
812
|
-
import { VerificationContext } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/VerificationContext.js";
|
|
813
|
-
import { UnicityCertificateVerifier } from "@unicitylabs/state-transition-sdk/lib/api/bft/verification/UnicityCertificateVerifier.js";
|
|
814
|
-
import { UnicitySealQuorumSignaturesVerificationRule } from "@unicitylabs/state-transition-sdk/lib/api/bft/verification/rule/UnicitySealQuorumSignaturesVerificationRule.js";
|
|
815
|
-
import { VerifiedSealCache } from "@unicitylabs/state-transition-sdk/lib/api/bft/verification/VerifiedSealCache.js";
|
|
816
|
-
import { Secp256k1SignatureVerifier } from "@unicitylabs/state-transition-sdk/lib/crypto/secp256k1/Secp256k1SignatureVerifier.js";
|
|
817
|
-
import { WorkerTokenVerifier } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/worker/WorkerTokenVerifier.js";
|
|
818
|
-
import { EncodedPredicate } from "@unicitylabs/state-transition-sdk/lib/predicate/EncodedPredicate.js";
|
|
819
|
-
import { SignaturePredicate } from "@unicitylabs/state-transition-sdk/lib/predicate/builtin/SignaturePredicate.js";
|
|
820
|
-
import { SignaturePredicateUnlockScript } from "@unicitylabs/state-transition-sdk/lib/predicate/builtin/SignaturePredicateUnlockScript.js";
|
|
821
|
-
import { BurnPredicate } from "@unicitylabs/state-transition-sdk/lib/predicate/builtin/BurnPredicate.js";
|
|
822
|
-
import { PredicateVerifierService } from "@unicitylabs/state-transition-sdk/lib/predicate/verification/PredicateVerifierService.js";
|
|
823
|
-
import { SigningService } from "@unicitylabs/state-transition-sdk/lib/crypto/secp256k1/SigningService.js";
|
|
824
|
-
import { Signature } from "@unicitylabs/state-transition-sdk/lib/crypto/secp256k1/Signature.js";
|
|
825
|
-
import { MintSigningService } from "@unicitylabs/state-transition-sdk/lib/crypto/MintSigningService.js";
|
|
826
|
-
import { HashAlgorithm } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/HashAlgorithm.js";
|
|
827
|
-
import { DataHash } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/DataHash.js";
|
|
828
|
-
import { DataHasher } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/DataHasher.js";
|
|
829
|
-
import { DataHasherFactory } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/DataHasherFactory.js";
|
|
830
|
-
import { CborSerializer } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborSerializer.js";
|
|
831
|
-
import { CborDeserializer } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborDeserializer.js";
|
|
832
|
-
import { CborError } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborError.js";
|
|
833
|
-
import { CborReader } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborReader.js";
|
|
834
|
-
import { MajorType } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/MajorType.js";
|
|
835
|
-
import { Asset } from "@unicitylabs/state-transition-sdk/lib/payment/asset/Asset.js";
|
|
836
|
-
import { AssetId } from "@unicitylabs/state-transition-sdk/lib/payment/asset/AssetId.js";
|
|
837
|
-
import { PaymentAssetCollection } from "@unicitylabs/state-transition-sdk/lib/payment/asset/PaymentAssetCollection.js";
|
|
838
|
-
import { TokenSplit } from "@unicitylabs/state-transition-sdk/lib/payment/TokenSplit.js";
|
|
839
|
-
import { SplitTokenRequest } from "@unicitylabs/state-transition-sdk/lib/payment/SplitTokenRequest.js";
|
|
840
|
-
import { SplitToken } from "@unicitylabs/state-transition-sdk/lib/payment/SplitToken.js";
|
|
841
|
-
import { SplitAllocationProof } from "@unicitylabs/state-transition-sdk/lib/payment/SplitAllocationProof.js";
|
|
842
|
-
import { SplitMintJustification } from "@unicitylabs/state-transition-sdk/lib/payment/SplitMintJustification.js";
|
|
843
|
-
import { SplitMintJustificationVerifier } from "@unicitylabs/state-transition-sdk/lib/payment/SplitMintJustificationVerifier.js";
|
|
844
|
-
import { VerificationStatus } from "@unicitylabs/state-transition-sdk/lib/verification/VerificationStatus.js";
|
|
845
|
-
import { VerificationResult } from "@unicitylabs/state-transition-sdk/lib/verification/VerificationResult.js";
|
|
846
|
-
import { HexConverter } from "@unicitylabs/state-transition-sdk/lib/util/HexConverter.js";
|
|
847
|
-
import { BigintConverter } from "@unicitylabs/state-transition-sdk/lib/util/BigintConverter.js";
|
|
848
|
-
import { BitString } from "@unicitylabs/state-transition-sdk/lib/util/BitString.js";
|
|
849
|
-
|
|
850
|
-
// token-engine/value-envelope.ts
|
|
851
|
-
function isCoinlessEnvelope(envelope) {
|
|
852
|
-
return envelope.startsWith("none_");
|
|
788
|
+
// modules/payments-v2/machine/payload-view.ts
|
|
789
|
+
function isWholeIntent(p) {
|
|
790
|
+
return p.kind === "whole" || p.kind === "coinless";
|
|
791
|
+
}
|
|
792
|
+
function splitOf(p) {
|
|
793
|
+
return p.kind === "coin" ? p.split : void 0;
|
|
794
|
+
}
|
|
795
|
+
function coinIdOf(p) {
|
|
796
|
+
return p.kind === "coin" ? p.coinId : void 0;
|
|
853
797
|
}
|
|
854
798
|
|
|
855
799
|
// token-engine/errors.ts
|
|
@@ -891,14 +835,6 @@ var CheckpointTrustbaseMismatchError = class extends SphereError {
|
|
|
891
835
|
}
|
|
892
836
|
};
|
|
893
837
|
|
|
894
|
-
// modules/payments-v2/machine/payload-view.ts
|
|
895
|
-
function splitOf(p) {
|
|
896
|
-
return p.kind === "coin" ? p.split : void 0;
|
|
897
|
-
}
|
|
898
|
-
function coinIdOf(p) {
|
|
899
|
-
return p.kind === "coin" ? p.coinId : void 0;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
838
|
// modules/payments-v2/machine/TransferMachine.ts
|
|
903
839
|
var CERTIFY_WIDTH = 20;
|
|
904
840
|
var KEEP_OPEN_CODES = /* @__PURE__ */ new Set([
|
|
@@ -1260,7 +1196,14 @@ var TransferMachine = class {
|
|
|
1260
1196
|
try {
|
|
1261
1197
|
const coinId = coinIdOf(payload);
|
|
1262
1198
|
const committedAmount = coinId === void 0 ? "0" : await this.settledAmount(engine, coinId, committed);
|
|
1263
|
-
await this.
|
|
1199
|
+
const committedAssets = coinId === void 0 ? await this.settledAssets(engine, committed) : void 0;
|
|
1200
|
+
await this.deps.recordHistory?.({
|
|
1201
|
+
transferId,
|
|
1202
|
+
payload,
|
|
1203
|
+
phase,
|
|
1204
|
+
committedAmount,
|
|
1205
|
+
...committedAssets !== void 0 ? { committedAssets } : {}
|
|
1206
|
+
});
|
|
1264
1207
|
} catch {
|
|
1265
1208
|
}
|
|
1266
1209
|
try {
|
|
@@ -1274,6 +1217,18 @@ var TransferMachine = class {
|
|
|
1274
1217
|
* a journal-rehydrated resume leg has no source token, but every committed
|
|
1275
1218
|
* leg carries its recipient blob, so the outcome-derived rule is uniform).
|
|
1276
1219
|
*/
|
|
1220
|
+
/** Every asset across the certified recipient blobs — the whole-spend twin of settledAmount. */
|
|
1221
|
+
async settledAssets(engine, committed) {
|
|
1222
|
+
const total = /* @__PURE__ */ new Map();
|
|
1223
|
+
for (const outcome of committed) {
|
|
1224
|
+
if (outcome.recipientBlob === void 0) continue;
|
|
1225
|
+
const token = await engine.decodeToken({ tokenId: "", token: outcome.recipientBlob });
|
|
1226
|
+
for (const asset of engine.readValue(token)?.assets ?? []) {
|
|
1227
|
+
total.set(asset.coinId, (total.get(asset.coinId) ?? 0n) + asset.amount);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return [...total].map(([coinId, amount]) => ({ coinId, amount: amount.toString() }));
|
|
1231
|
+
}
|
|
1277
1232
|
async settledAmount(engine, coinId, committed) {
|
|
1278
1233
|
let total = 0n;
|
|
1279
1234
|
for (const outcome of committed) {
|
|
@@ -1413,7 +1368,7 @@ async function runOne(ctx, job, report) {
|
|
|
1413
1368
|
report.failed.push(job.transferId);
|
|
1414
1369
|
return;
|
|
1415
1370
|
}
|
|
1416
|
-
if (job.payload.
|
|
1371
|
+
if (isWholeIntent(job.payload) && token.valueEnvelope === "bare_collection") {
|
|
1417
1372
|
logger.warn(
|
|
1418
1373
|
"PaymentsV2",
|
|
1419
1374
|
`resume: token intent ${job.transferId} names a source carrying coin value \u2014 refusing`
|
|
@@ -1461,7 +1416,7 @@ function validateCoinPayload(c) {
|
|
|
1461
1416
|
}
|
|
1462
1417
|
return { ...c, kind: "coin" };
|
|
1463
1418
|
}
|
|
1464
|
-
function
|
|
1419
|
+
function validateWholePayload(p) {
|
|
1465
1420
|
if (p.direct?.length !== 1 || typeof p.direct[0] !== "string" || p.direct[0] === "") {
|
|
1466
1421
|
throw new SphereError(
|
|
1467
1422
|
"token intent payload must name exactly one source token",
|
|
@@ -1471,7 +1426,7 @@ function validateCoinlessPayload(p) {
|
|
|
1471
1426
|
if (p.split !== void 0) {
|
|
1472
1427
|
throw new SphereError("token intent payload cannot carry a split", "VALIDATION_ERROR");
|
|
1473
1428
|
}
|
|
1474
|
-
return { ...p, kind: "
|
|
1429
|
+
return { ...p, kind: "whole", direct: [p.direct[0]] };
|
|
1475
1430
|
}
|
|
1476
1431
|
function validatePayload(raw) {
|
|
1477
1432
|
const p = raw !== null && typeof raw === "object" ? raw : null;
|
|
@@ -1485,13 +1440,13 @@ function validatePayload(raw) {
|
|
|
1485
1440
|
throw new SphereError("intent payload is missing recipient", "VALIDATION_ERROR");
|
|
1486
1441
|
}
|
|
1487
1442
|
const kind = p.kind ?? "coin";
|
|
1488
|
-
if (kind !== "coin" && kind !== "coinless") {
|
|
1443
|
+
if (kind !== "coin" && kind !== "whole" && kind !== "coinless") {
|
|
1489
1444
|
throw new SphereError(
|
|
1490
1445
|
`unsupported intent kind '${String(kind)}' \u2014 not resumable by this client`,
|
|
1491
1446
|
"VALIDATION_ERROR"
|
|
1492
1447
|
);
|
|
1493
1448
|
}
|
|
1494
|
-
return kind === "
|
|
1449
|
+
return kind === "coin" ? validateCoinPayload(p) : validateWholePayload(p);
|
|
1495
1450
|
}
|
|
1496
1451
|
|
|
1497
1452
|
// modules/payments-v2/convergence.ts
|
|
@@ -1704,8 +1659,9 @@ async function openRow(entry, journal, decryptPayload) {
|
|
|
1704
1659
|
};
|
|
1705
1660
|
}
|
|
1706
1661
|
function subject(payload) {
|
|
1707
|
-
|
|
1708
|
-
|
|
1662
|
+
const rawKind = payload?.kind;
|
|
1663
|
+
if (rawKind === "whole" || rawKind === "coinless") {
|
|
1664
|
+
const tokenId = payload?.direct?.[0];
|
|
1709
1665
|
return { coinId: "", amount: "", ...typeof tokenId === "string" ? { tokenId } : {} };
|
|
1710
1666
|
}
|
|
1711
1667
|
const coin = payload;
|
|
@@ -1778,10 +1734,10 @@ function buildPayload(recipientPubkey, request, spend, spentStates) {
|
|
|
1778
1734
|
function messageOf(err) {
|
|
1779
1735
|
return err instanceof Error ? err.message : String(err);
|
|
1780
1736
|
}
|
|
1781
|
-
function
|
|
1737
|
+
function buildWholePayload(recipientPubkey, request, spentStates) {
|
|
1782
1738
|
return {
|
|
1783
1739
|
v: 2,
|
|
1784
|
-
kind: "
|
|
1740
|
+
kind: "whole",
|
|
1785
1741
|
recipient: recipientPubkey,
|
|
1786
1742
|
...request.memo !== void 0 ? { memo: request.memo } : {},
|
|
1787
1743
|
direct: [request.tokenId],
|
|
@@ -1850,8 +1806,102 @@ async function finalizeMint(deps, mintId, token, coinId, amount) {
|
|
|
1850
1806
|
deps.refreshView();
|
|
1851
1807
|
}
|
|
1852
1808
|
|
|
1853
|
-
// modules/payments-v2/
|
|
1854
|
-
|
|
1809
|
+
// modules/payments-v2/inventory/presentation.ts
|
|
1810
|
+
function toToken(tokenId, snapshot, asset, registry, flags) {
|
|
1811
|
+
const iconUrl = registry.getIconUrl(asset.coinId);
|
|
1812
|
+
return {
|
|
1813
|
+
id: tokenId,
|
|
1814
|
+
coinId: asset.coinId,
|
|
1815
|
+
symbol: registry.getSymbol(asset.coinId),
|
|
1816
|
+
name: registry.getName(asset.coinId),
|
|
1817
|
+
decimals: registry.getDecimals(asset.coinId),
|
|
1818
|
+
...iconUrl !== null ? { iconUrl } : {},
|
|
1819
|
+
amount: asset.amount,
|
|
1820
|
+
status: flags.transferring ? "transferring" : "confirmed",
|
|
1821
|
+
createdAt: snapshot.createdAt,
|
|
1822
|
+
updatedAt: snapshot.updatedAt,
|
|
1823
|
+
lazy: true,
|
|
1824
|
+
...flags.suspectedSpent ? { suspectedSpent: true } : {}
|
|
1825
|
+
};
|
|
1826
|
+
}
|
|
1827
|
+
function aggregateAssets(entries, isTransferring, registry) {
|
|
1828
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1829
|
+
for (const [tokenId, entry] of entries) {
|
|
1830
|
+
const moving = isTransferring(tokenId);
|
|
1831
|
+
for (const asset of entry.assets) {
|
|
1832
|
+
let group = groups.get(asset.coinId);
|
|
1833
|
+
if (!group) {
|
|
1834
|
+
group = { total: 0n, count: 0, transferring: 0n, transferringCount: 0 };
|
|
1835
|
+
groups.set(asset.coinId, group);
|
|
1836
|
+
}
|
|
1837
|
+
if (moving) {
|
|
1838
|
+
group.transferring += BigInt(asset.amount);
|
|
1839
|
+
group.transferringCount += 1;
|
|
1840
|
+
} else {
|
|
1841
|
+
group.total += BigInt(asset.amount);
|
|
1842
|
+
group.count += 1;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
return [...groups].map(([coinId, totals]) => toAsset(coinId, totals, registry));
|
|
1847
|
+
}
|
|
1848
|
+
function toAsset(coinId, totals, registry) {
|
|
1849
|
+
const iconUrl = registry.getIconUrl(coinId);
|
|
1850
|
+
return {
|
|
1851
|
+
coinId,
|
|
1852
|
+
symbol: registry.getSymbol(coinId),
|
|
1853
|
+
name: registry.getName(coinId),
|
|
1854
|
+
decimals: registry.getDecimals(coinId),
|
|
1855
|
+
...iconUrl !== null ? { iconUrl } : {},
|
|
1856
|
+
totalAmount: totals.total.toString(),
|
|
1857
|
+
tokenCount: totals.count,
|
|
1858
|
+
confirmedAmount: totals.total.toString(),
|
|
1859
|
+
unconfirmedAmount: "0",
|
|
1860
|
+
confirmedTokenCount: totals.count,
|
|
1861
|
+
unconfirmedTokenCount: 0,
|
|
1862
|
+
transferringTokenCount: totals.transferringCount,
|
|
1863
|
+
transferringAmount: totals.transferring.toString(),
|
|
1864
|
+
priceUsd: null,
|
|
1865
|
+
priceEur: null,
|
|
1866
|
+
change24h: null,
|
|
1867
|
+
fiatValueUsd: null,
|
|
1868
|
+
fiatValueEur: null
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
function priceIdOf(registry, coinId) {
|
|
1872
|
+
return registry.getName(coinId).toLowerCase();
|
|
1873
|
+
}
|
|
1874
|
+
async function withPrices(raw, registry, price) {
|
|
1875
|
+
try {
|
|
1876
|
+
const ids = [...new Set(raw.map((a) => priceIdOf(registry, a.coinId)))];
|
|
1877
|
+
const quotes = await price.getPrices(ids);
|
|
1878
|
+
return raw.map((a) => priceOne(a, quotes.get(priceIdOf(registry, a.coinId))));
|
|
1879
|
+
} catch {
|
|
1880
|
+
return raw;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
function priceOne(asset, quote) {
|
|
1884
|
+
if (!quote) return asset;
|
|
1885
|
+
const human = Number(asset.totalAmount) / Math.pow(10, asset.decimals);
|
|
1886
|
+
return {
|
|
1887
|
+
...asset,
|
|
1888
|
+
priceUsd: quote.priceUsd,
|
|
1889
|
+
priceEur: quote.priceEur ?? null,
|
|
1890
|
+
change24h: quote.change24h ?? null,
|
|
1891
|
+
fiatValueUsd: human * quote.priceUsd,
|
|
1892
|
+
fiatValueEur: quote.priceEur != null ? human * quote.priceEur : null
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
function transferringToken(tokenId, coinId, amount, registry, now) {
|
|
1896
|
+
const snapshot = { assets: [], createdAt: now, updatedAt: now };
|
|
1897
|
+
return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, registry, {
|
|
1898
|
+
transferring: true,
|
|
1899
|
+
suspectedSpent: false
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
// modules/payments-v2/send-whole.ts
|
|
1904
|
+
async function materializeWholeSpend(deps, input) {
|
|
1855
1905
|
const { engine } = deps;
|
|
1856
1906
|
const tokenId = input.request.tokenId;
|
|
1857
1907
|
const bytes = (await deps.storagePort.getBlobs([tokenId])).get(tokenId);
|
|
@@ -1859,14 +1909,20 @@ async function materializeCoinlessSpend(deps, input) {
|
|
|
1859
1909
|
throw new SphereError(`Selected source ${tokenId} has no blob in storage`, "STORAGE_ERROR");
|
|
1860
1910
|
}
|
|
1861
1911
|
const token = await engine.decodeToken({ tokenId, token: bytes });
|
|
1862
|
-
if (
|
|
1912
|
+
if (token.valueEnvelope === "bare_collection") {
|
|
1913
|
+
throw new SphereError(
|
|
1914
|
+
`Token ${tokenId} carries a value envelope this SDK cannot read, so its coins cannot be accounted for; it cannot be sent`,
|
|
1915
|
+
"VALIDATION_ERROR"
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
if (input.requireCoinless && token.value !== null) {
|
|
1863
1919
|
throw new SphereError(
|
|
1864
|
-
`Token ${tokenId} carries coin value and cannot be sent with sendCoinless \u2014 use
|
|
1920
|
+
`Token ${tokenId} carries coin value and cannot be sent with sendCoinless \u2014 use sendWholeToken, which requires coin-transfer authority`,
|
|
1865
1921
|
"VALIDATION_ERROR"
|
|
1866
1922
|
);
|
|
1867
1923
|
}
|
|
1868
1924
|
const keys = await engine.deliveryKeys(bytes);
|
|
1869
|
-
const payload =
|
|
1925
|
+
const payload = buildWholePayload(input.recipientPubkey, input.request, {
|
|
1870
1926
|
[tokenId]: { local: keys.stateHash, protocol: keys.stateHash }
|
|
1871
1927
|
});
|
|
1872
1928
|
const plan = {
|
|
@@ -1877,7 +1933,10 @@ async function materializeCoinlessSpend(deps, input) {
|
|
|
1877
1933
|
sources: /* @__PURE__ */ new Map([[tokenId, token]]),
|
|
1878
1934
|
...input.request.memo !== void 0 ? { memo: input.request.memo } : {}
|
|
1879
1935
|
};
|
|
1880
|
-
|
|
1936
|
+
const sourceTokens = (token.value?.assets ?? []).map(
|
|
1937
|
+
(asset) => transferringToken(tokenId, asset.coinId, asset.amount, deps.registry, deps.now)
|
|
1938
|
+
);
|
|
1939
|
+
return { transferId: input.transferId, coinId: "", plan, sourceIds: input.sourceIds, sourceTokens };
|
|
1881
1940
|
}
|
|
1882
1941
|
|
|
1883
1942
|
// modules/payments-v2/send-errors.ts
|
|
@@ -2024,100 +2083,6 @@ async function takeSourceBlobs(deps, sourceIds) {
|
|
|
2024
2083
|
return blobs;
|
|
2025
2084
|
}
|
|
2026
2085
|
|
|
2027
|
-
// modules/payments-v2/inventory/presentation.ts
|
|
2028
|
-
function toToken(tokenId, snapshot, asset, registry, flags) {
|
|
2029
|
-
const iconUrl = registry.getIconUrl(asset.coinId);
|
|
2030
|
-
return {
|
|
2031
|
-
id: tokenId,
|
|
2032
|
-
coinId: asset.coinId,
|
|
2033
|
-
symbol: registry.getSymbol(asset.coinId),
|
|
2034
|
-
name: registry.getName(asset.coinId),
|
|
2035
|
-
decimals: registry.getDecimals(asset.coinId),
|
|
2036
|
-
...iconUrl !== null ? { iconUrl } : {},
|
|
2037
|
-
amount: asset.amount,
|
|
2038
|
-
status: flags.transferring ? "transferring" : "confirmed",
|
|
2039
|
-
createdAt: snapshot.createdAt,
|
|
2040
|
-
updatedAt: snapshot.updatedAt,
|
|
2041
|
-
lazy: true,
|
|
2042
|
-
...flags.suspectedSpent ? { suspectedSpent: true } : {}
|
|
2043
|
-
};
|
|
2044
|
-
}
|
|
2045
|
-
function aggregateAssets(entries, isTransferring, registry) {
|
|
2046
|
-
const groups = /* @__PURE__ */ new Map();
|
|
2047
|
-
for (const [tokenId, entry] of entries) {
|
|
2048
|
-
const moving = isTransferring(tokenId);
|
|
2049
|
-
for (const asset of entry.assets) {
|
|
2050
|
-
let group = groups.get(asset.coinId);
|
|
2051
|
-
if (!group) {
|
|
2052
|
-
group = { total: 0n, count: 0, transferring: 0n, transferringCount: 0 };
|
|
2053
|
-
groups.set(asset.coinId, group);
|
|
2054
|
-
}
|
|
2055
|
-
if (moving) {
|
|
2056
|
-
group.transferring += BigInt(asset.amount);
|
|
2057
|
-
group.transferringCount += 1;
|
|
2058
|
-
} else {
|
|
2059
|
-
group.total += BigInt(asset.amount);
|
|
2060
|
-
group.count += 1;
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
return [...groups].map(([coinId, totals]) => toAsset(coinId, totals, registry));
|
|
2065
|
-
}
|
|
2066
|
-
function toAsset(coinId, totals, registry) {
|
|
2067
|
-
const iconUrl = registry.getIconUrl(coinId);
|
|
2068
|
-
return {
|
|
2069
|
-
coinId,
|
|
2070
|
-
symbol: registry.getSymbol(coinId),
|
|
2071
|
-
name: registry.getName(coinId),
|
|
2072
|
-
decimals: registry.getDecimals(coinId),
|
|
2073
|
-
...iconUrl !== null ? { iconUrl } : {},
|
|
2074
|
-
totalAmount: totals.total.toString(),
|
|
2075
|
-
tokenCount: totals.count,
|
|
2076
|
-
confirmedAmount: totals.total.toString(),
|
|
2077
|
-
unconfirmedAmount: "0",
|
|
2078
|
-
confirmedTokenCount: totals.count,
|
|
2079
|
-
unconfirmedTokenCount: 0,
|
|
2080
|
-
transferringTokenCount: totals.transferringCount,
|
|
2081
|
-
transferringAmount: totals.transferring.toString(),
|
|
2082
|
-
priceUsd: null,
|
|
2083
|
-
priceEur: null,
|
|
2084
|
-
change24h: null,
|
|
2085
|
-
fiatValueUsd: null,
|
|
2086
|
-
fiatValueEur: null
|
|
2087
|
-
};
|
|
2088
|
-
}
|
|
2089
|
-
function priceIdOf(registry, coinId) {
|
|
2090
|
-
return registry.getName(coinId).toLowerCase();
|
|
2091
|
-
}
|
|
2092
|
-
async function withPrices(raw, registry, price) {
|
|
2093
|
-
try {
|
|
2094
|
-
const ids = [...new Set(raw.map((a) => priceIdOf(registry, a.coinId)))];
|
|
2095
|
-
const quotes = await price.getPrices(ids);
|
|
2096
|
-
return raw.map((a) => priceOne(a, quotes.get(priceIdOf(registry, a.coinId))));
|
|
2097
|
-
} catch {
|
|
2098
|
-
return raw;
|
|
2099
|
-
}
|
|
2100
|
-
}
|
|
2101
|
-
function priceOne(asset, quote) {
|
|
2102
|
-
if (!quote) return asset;
|
|
2103
|
-
const human = Number(asset.totalAmount) / Math.pow(10, asset.decimals);
|
|
2104
|
-
return {
|
|
2105
|
-
...asset,
|
|
2106
|
-
priceUsd: quote.priceUsd,
|
|
2107
|
-
priceEur: quote.priceEur ?? null,
|
|
2108
|
-
change24h: quote.change24h ?? null,
|
|
2109
|
-
fiatValueUsd: human * quote.priceUsd,
|
|
2110
|
-
fiatValueEur: quote.priceEur != null ? human * quote.priceEur : null
|
|
2111
|
-
};
|
|
2112
|
-
}
|
|
2113
|
-
function transferringToken(tokenId, coinId, amount, registry, now) {
|
|
2114
|
-
const snapshot = { assets: [], createdAt: now, updatedAt: now };
|
|
2115
|
-
return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, registry, {
|
|
2116
|
-
transferring: true,
|
|
2117
|
-
suspectedSpent: false
|
|
2118
|
-
});
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2121
2086
|
// node_modules/@noble/ciphers/utils.js
|
|
2122
2087
|
function isBytes2(a) {
|
|
2123
2088
|
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
|
|
@@ -3223,10 +3188,10 @@ var InventoryView = class {
|
|
|
3223
3188
|
if (this.inFlight.has(tokenId) && !this.pinned(tokenId)) return false;
|
|
3224
3189
|
return !this.suspected.has(stateKey(tokenId, entry.stateHash));
|
|
3225
3190
|
}
|
|
3226
|
-
/**
|
|
3227
|
-
|
|
3191
|
+
/** Is this NAMED token spendable whole — coinless or valued (#777)? */
|
|
3192
|
+
spendableToken(tokenId) {
|
|
3228
3193
|
const entry = this.mirror.get(tokenId);
|
|
3229
|
-
return entry !== void 0 &&
|
|
3194
|
+
return entry !== void 0 && this.isSpendable(tokenId, entry);
|
|
3230
3195
|
}
|
|
3231
3196
|
/**
|
|
3232
3197
|
* Current mirrored state of an ACTIVE token, or undefined when it is unknown
|
|
@@ -3450,6 +3415,73 @@ var InventoryView = class {
|
|
|
3450
3415
|
}
|
|
3451
3416
|
};
|
|
3452
3417
|
|
|
3418
|
+
// token-engine/sdk.ts
|
|
3419
|
+
import { StateTransitionClient } from "@unicitylabs/state-transition-sdk/lib/StateTransitionClient.js";
|
|
3420
|
+
import { AggregatorClient } from "@unicitylabs/state-transition-sdk/lib/api/AggregatorClient.js";
|
|
3421
|
+
import { NetworkId } from "@unicitylabs/state-transition-sdk/lib/api/NetworkId.js";
|
|
3422
|
+
import { CertificationData } from "@unicitylabs/state-transition-sdk/lib/api/CertificationData.js";
|
|
3423
|
+
import { CertificationResponse, CertificationStatus } from "@unicitylabs/state-transition-sdk/lib/api/CertificationResponse.js";
|
|
3424
|
+
import { StateId } from "@unicitylabs/state-transition-sdk/lib/api/StateId.js";
|
|
3425
|
+
import { InclusionProof } from "@unicitylabs/state-transition-sdk/lib/api/InclusionProof.js";
|
|
3426
|
+
import { InclusionProofResponse } from "@unicitylabs/state-transition-sdk/lib/api/InclusionProofResponse.js";
|
|
3427
|
+
import { JsonRpcNetworkError } from "@unicitylabs/state-transition-sdk/lib/api/json-rpc/JsonRpcNetworkError.js";
|
|
3428
|
+
import { RootTrustBase } from "@unicitylabs/state-transition-sdk/lib/api/bft/RootTrustBase.js";
|
|
3429
|
+
import { waitInclusionProof } from "@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils.js";
|
|
3430
|
+
import { InclusionProofVerificationStatus } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/rule/InclusionProofVerificationRule.js";
|
|
3431
|
+
import { Token } from "@unicitylabs/state-transition-sdk/lib/transaction/Token.js";
|
|
3432
|
+
import { MintTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/MintTransaction.js";
|
|
3433
|
+
import { TransferTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/TransferTransaction.js";
|
|
3434
|
+
import { CertifiedMintTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/CertifiedMintTransaction.js";
|
|
3435
|
+
import { CertifiedTransferTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/CertifiedTransferTransaction.js";
|
|
3436
|
+
import { TokenId } from "@unicitylabs/state-transition-sdk/lib/transaction/TokenId.js";
|
|
3437
|
+
import { TokenType } from "@unicitylabs/state-transition-sdk/lib/transaction/TokenType.js";
|
|
3438
|
+
import { TokenSalt } from "@unicitylabs/state-transition-sdk/lib/transaction/TokenSalt.js";
|
|
3439
|
+
import { StateMask } from "@unicitylabs/state-transition-sdk/lib/transaction/StateMask.js";
|
|
3440
|
+
import { MintJustificationVerifierService } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/MintJustificationVerifierService.js";
|
|
3441
|
+
import { TokenIssuanceVerifierService } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/TokenIssuanceVerifierService.js";
|
|
3442
|
+
import { VerificationContext } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/VerificationContext.js";
|
|
3443
|
+
import { UnicityCertificateVerifier } from "@unicitylabs/state-transition-sdk/lib/api/bft/verification/UnicityCertificateVerifier.js";
|
|
3444
|
+
import { UnicitySealQuorumSignaturesVerificationRule } from "@unicitylabs/state-transition-sdk/lib/api/bft/verification/rule/UnicitySealQuorumSignaturesVerificationRule.js";
|
|
3445
|
+
import { VerifiedSealCache } from "@unicitylabs/state-transition-sdk/lib/api/bft/verification/VerifiedSealCache.js";
|
|
3446
|
+
import { Secp256k1SignatureVerifier } from "@unicitylabs/state-transition-sdk/lib/crypto/secp256k1/Secp256k1SignatureVerifier.js";
|
|
3447
|
+
import { WorkerTokenVerifier } from "@unicitylabs/state-transition-sdk/lib/transaction/verification/worker/WorkerTokenVerifier.js";
|
|
3448
|
+
import { EncodedPredicate } from "@unicitylabs/state-transition-sdk/lib/predicate/EncodedPredicate.js";
|
|
3449
|
+
import { SignaturePredicate } from "@unicitylabs/state-transition-sdk/lib/predicate/builtin/SignaturePredicate.js";
|
|
3450
|
+
import { SignaturePredicateUnlockScript } from "@unicitylabs/state-transition-sdk/lib/predicate/builtin/SignaturePredicateUnlockScript.js";
|
|
3451
|
+
import { BurnPredicate } from "@unicitylabs/state-transition-sdk/lib/predicate/builtin/BurnPredicate.js";
|
|
3452
|
+
import { PredicateVerifierService } from "@unicitylabs/state-transition-sdk/lib/predicate/verification/PredicateVerifierService.js";
|
|
3453
|
+
import { SigningService } from "@unicitylabs/state-transition-sdk/lib/crypto/secp256k1/SigningService.js";
|
|
3454
|
+
import { Signature } from "@unicitylabs/state-transition-sdk/lib/crypto/secp256k1/Signature.js";
|
|
3455
|
+
import { MintSigningService } from "@unicitylabs/state-transition-sdk/lib/crypto/MintSigningService.js";
|
|
3456
|
+
import { HashAlgorithm } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/HashAlgorithm.js";
|
|
3457
|
+
import { DataHash } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/DataHash.js";
|
|
3458
|
+
import { DataHasher } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/DataHasher.js";
|
|
3459
|
+
import { DataHasherFactory } from "@unicitylabs/state-transition-sdk/lib/crypto/hash/DataHasherFactory.js";
|
|
3460
|
+
import { CborSerializer } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborSerializer.js";
|
|
3461
|
+
import { CborDeserializer } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborDeserializer.js";
|
|
3462
|
+
import { CborError } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborError.js";
|
|
3463
|
+
import { CborReader } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/CborReader.js";
|
|
3464
|
+
import { MajorType } from "@unicitylabs/state-transition-sdk/lib/serialization/cbor/MajorType.js";
|
|
3465
|
+
import { Asset } from "@unicitylabs/state-transition-sdk/lib/payment/asset/Asset.js";
|
|
3466
|
+
import { AssetId } from "@unicitylabs/state-transition-sdk/lib/payment/asset/AssetId.js";
|
|
3467
|
+
import { PaymentAssetCollection } from "@unicitylabs/state-transition-sdk/lib/payment/asset/PaymentAssetCollection.js";
|
|
3468
|
+
import { TokenSplit } from "@unicitylabs/state-transition-sdk/lib/payment/TokenSplit.js";
|
|
3469
|
+
import { SplitTokenRequest } from "@unicitylabs/state-transition-sdk/lib/payment/SplitTokenRequest.js";
|
|
3470
|
+
import { SplitToken } from "@unicitylabs/state-transition-sdk/lib/payment/SplitToken.js";
|
|
3471
|
+
import { SplitAllocationProof } from "@unicitylabs/state-transition-sdk/lib/payment/SplitAllocationProof.js";
|
|
3472
|
+
import { SplitMintJustification } from "@unicitylabs/state-transition-sdk/lib/payment/SplitMintJustification.js";
|
|
3473
|
+
import { SplitMintJustificationVerifier } from "@unicitylabs/state-transition-sdk/lib/payment/SplitMintJustificationVerifier.js";
|
|
3474
|
+
import { VerificationStatus } from "@unicitylabs/state-transition-sdk/lib/verification/VerificationStatus.js";
|
|
3475
|
+
import { VerificationResult } from "@unicitylabs/state-transition-sdk/lib/verification/VerificationResult.js";
|
|
3476
|
+
import { HexConverter } from "@unicitylabs/state-transition-sdk/lib/util/HexConverter.js";
|
|
3477
|
+
import { BigintConverter } from "@unicitylabs/state-transition-sdk/lib/util/BigintConverter.js";
|
|
3478
|
+
import { BitString } from "@unicitylabs/state-transition-sdk/lib/util/BitString.js";
|
|
3479
|
+
|
|
3480
|
+
// token-engine/value-envelope.ts
|
|
3481
|
+
function isCoinlessEnvelope(envelope) {
|
|
3482
|
+
return envelope.startsWith("none_");
|
|
3483
|
+
}
|
|
3484
|
+
|
|
3453
3485
|
// modules/payments-v2/receive/Receive.ts
|
|
3454
3486
|
var ACK_BATCH_SIZE = 200;
|
|
3455
3487
|
var REFRESH_INTERVAL_MS = 2500;
|
|
@@ -3594,7 +3626,7 @@ async function screen(deps, engine, entry) {
|
|
|
3594
3626
|
tokenId: keys.tokenId,
|
|
3595
3627
|
stateHash: keys.stateHash,
|
|
3596
3628
|
assets: toAssetAmounts(token),
|
|
3597
|
-
...
|
|
3629
|
+
...isCoinlessEnvelope(token.valueEnvelope) ? { tokenType: token.tokenType } : {}
|
|
3598
3630
|
}
|
|
3599
3631
|
};
|
|
3600
3632
|
}
|
|
@@ -3731,9 +3763,6 @@ function claimAck(entry) {
|
|
|
3731
3763
|
function rejectAck(entry, reason) {
|
|
3732
3764
|
return { deliveryId: entry.deliveryId, disposition: "rejected", reason, cursor: entry.cursor };
|
|
3733
3765
|
}
|
|
3734
|
-
function isCoinlessEnvelope2(envelope) {
|
|
3735
|
-
return envelope.startsWith("none_");
|
|
3736
|
-
}
|
|
3737
3766
|
function toAssetAmounts(token) {
|
|
3738
3767
|
return (token.value?.assets ?? []).map((asset) => ({
|
|
3739
3768
|
coinId: asset.coinId,
|
|
@@ -4308,7 +4337,7 @@ var SpendQueue = class {
|
|
|
4308
4337
|
* can release, so queueing would block until a timeout on a spend that cannot
|
|
4309
4338
|
* become possible.
|
|
4310
4339
|
*/
|
|
4311
|
-
|
|
4340
|
+
planWhole(reservationId, tokenId) {
|
|
4312
4341
|
if (this.destroyed) {
|
|
4313
4342
|
throw new SphereError("Module has been destroyed", "MODULE_DESTROYED");
|
|
4314
4343
|
}
|
|
@@ -4316,11 +4345,8 @@ var SpendQueue = class {
|
|
|
4316
4345
|
if (unproven !== null) {
|
|
4317
4346
|
throw new SphereError(`Cannot spend yet: ${unproven}`, "SEND_SYNC_PENDING");
|
|
4318
4347
|
}
|
|
4319
|
-
if (this.deps.
|
|
4320
|
-
throw new SphereError(
|
|
4321
|
-
`Token ${tokenId} is not a spendable coinless holding`,
|
|
4322
|
-
"VALIDATION_ERROR"
|
|
4323
|
-
);
|
|
4348
|
+
if (this.deps.spendableToken?.(tokenId) !== true) {
|
|
4349
|
+
throw new SphereError(`Token ${tokenId} is not a spendable holding`, "VALIDATION_ERROR");
|
|
4324
4350
|
}
|
|
4325
4351
|
const holder = this.deps.ledger.holderOf(tokenId);
|
|
4326
4352
|
if (holder !== void 0) {
|
|
@@ -4521,7 +4547,7 @@ function composeFacadeParts(deps, hooks) {
|
|
|
4521
4547
|
const queue = new SpendQueue({
|
|
4522
4548
|
ledger,
|
|
4523
4549
|
getPool: (coinId) => view.pool(coinId),
|
|
4524
|
-
|
|
4550
|
+
spendableToken: (tokenId) => view.spendableToken(tokenId),
|
|
4525
4551
|
...deps.workBudget !== void 0 ? { workBudget: deps.workBudget } : {}
|
|
4526
4552
|
});
|
|
4527
4553
|
const historyStore = new History({
|
|
@@ -4602,12 +4628,12 @@ function buildMachineDeps(deps, hooks, historyStore) {
|
|
|
4602
4628
|
...deps.ownNametag !== void 0 ? { ownNametag: deps.ownNametag } : {},
|
|
4603
4629
|
emit: deps.emit,
|
|
4604
4630
|
now: deps.now ?? Date.now,
|
|
4605
|
-
recordHistory: async ({ transferId, payload, committedAmount }) => {
|
|
4631
|
+
recordHistory: async ({ transferId, payload, committedAmount, committedAssets }) => {
|
|
4606
4632
|
await historyStore.recordSent({
|
|
4607
4633
|
transferId,
|
|
4608
4634
|
// §5.9: the SETTLED amount, never payload.amount — the plan. A token
|
|
4609
4635
|
// spend moved no coin: `assets: []` + tokenId (wallet-api#151 / §10).
|
|
4610
|
-
...payload
|
|
4636
|
+
...isWholeIntent(payload) ? { assets: committedAssets ?? [], tokenId: payload.direct[0] } : { assets: [{ coinId: payload.coinId, amount: committedAmount }] },
|
|
4611
4637
|
recipientPubkey: payload.recipient,
|
|
4612
4638
|
...payload.memo !== void 0 ? { memo: payload.memo } : {}
|
|
4613
4639
|
});
|
|
@@ -4822,10 +4848,14 @@ var PaymentsFacade = class {
|
|
|
4822
4848
|
return { queue: this.queue, view: this.view, storagePort: this.deps.storagePort, cache: this.prewarmed };
|
|
4823
4849
|
}
|
|
4824
4850
|
send(request) {
|
|
4825
|
-
return this.track(this.
|
|
4851
|
+
return this.track(this.runJob({ kind: "coin", request }, request.amount));
|
|
4852
|
+
}
|
|
4853
|
+
sendWholeToken(request) {
|
|
4854
|
+
return this.track(this.runJob({ kind: "whole", request, requireCoinless: false }, "0"));
|
|
4826
4855
|
}
|
|
4856
|
+
/** NFT-scoped twin: refuses a valued source. */
|
|
4827
4857
|
sendCoinless(request) {
|
|
4828
|
-
return this.track(this.
|
|
4858
|
+
return this.track(this.runJob({ kind: "whole", request, requireCoinless: true }, "0"));
|
|
4829
4859
|
}
|
|
4830
4860
|
async receive() {
|
|
4831
4861
|
const transfers = await this.track(this.receiveLoop.drainOnce());
|
|
@@ -4873,13 +4903,6 @@ var PaymentsFacade = class {
|
|
|
4873
4903
|
// ── send policy (§5.5 + old-loop parity; the machine stays policy-free) ────
|
|
4874
4904
|
/** The ONE place a send() outcome is shaped: success emits in finishSend, a
|
|
4875
4905
|
* CLEAN rejection emits `transfer:updated{status:'failed'}` here (§4). */
|
|
4876
|
-
sendOutcome(request) {
|
|
4877
|
-
return this.runJob({ kind: "coin", request }, request.amount);
|
|
4878
|
-
}
|
|
4879
|
-
/** A token spend has no amount; '0' keeps the shortfall arithmetic total-free. */
|
|
4880
|
-
sendCoinlessOutcome(request) {
|
|
4881
|
-
return this.runJob({ kind: "coinless", request }, "0");
|
|
4882
|
-
}
|
|
4883
4906
|
async runJob(job, amount) {
|
|
4884
4907
|
const run = {
|
|
4885
4908
|
amount,
|
|
@@ -4924,7 +4947,7 @@ var PaymentsFacade = class {
|
|
|
4924
4947
|
const disposition = await this.runAttempt(ctx);
|
|
4925
4948
|
if (disposition.kind === "rethrow") throw partialize(disposition.error, run);
|
|
4926
4949
|
if (disposition.kind === "retry-full") {
|
|
4927
|
-
if (job.kind === "
|
|
4950
|
+
if (job.kind === "whole" || attempt >= MAX_RESELECT) throw partialize(disposition.error, run);
|
|
4928
4951
|
continue;
|
|
4929
4952
|
}
|
|
4930
4953
|
if (disposition.kind === "success") {
|
|
@@ -5028,13 +5051,19 @@ var PaymentsFacade = class {
|
|
|
5028
5051
|
async planAndMaterialize(recipientPubkey, job, run) {
|
|
5029
5052
|
const transferId = this.newId();
|
|
5030
5053
|
run.lastTransferId = transferId;
|
|
5031
|
-
if (job.kind === "
|
|
5032
|
-
const spend2 = this.queue.
|
|
5054
|
+
if (job.kind === "whole") {
|
|
5055
|
+
const spend2 = this.queue.planWhole(transferId, job.request.tokenId);
|
|
5033
5056
|
const sourceIds2 = this.markPlanned(transferId, "", spend2);
|
|
5034
5057
|
try {
|
|
5035
|
-
return await
|
|
5036
|
-
{ engine: this.engine(), storagePort: this.deps.storagePort },
|
|
5037
|
-
{
|
|
5058
|
+
return await materializeWholeSpend(
|
|
5059
|
+
{ engine: this.engine(), storagePort: this.deps.storagePort, registry: this.deps.registry, now: this.nowMs() },
|
|
5060
|
+
{
|
|
5061
|
+
transferId,
|
|
5062
|
+
recipientPubkey,
|
|
5063
|
+
request: job.request,
|
|
5064
|
+
sourceIds: sourceIds2,
|
|
5065
|
+
requireCoinless: job.requireCoinless
|
|
5066
|
+
}
|
|
5038
5067
|
);
|
|
5039
5068
|
} catch (err) {
|
|
5040
5069
|
this.settleFailure(transferId, "", sourceIds2);
|