@dvmkit/sdk 0.10.1 → 0.12.0-rc.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/{chunk-STJBBVNL.js → chunk-2VGMZ7VF.js} +487 -71
- package/dist/{chunk-3Q6FTZDB.js → chunk-3YFFZLW7.js} +2 -2
- package/dist/{chunk-VMHYGKWT.js → chunk-566CFXGU.js} +9 -1
- package/dist/chunk-5H7P3ORL.js +92 -0
- package/dist/{chunk-3R7NQA3Z.js → chunk-7KQLPVV7.js} +1 -1
- package/dist/{chunk-JNECYURT.js → chunk-D4FFS3IS.js} +1 -1
- package/dist/{chunk-VTHYQCDB.js → chunk-E7ZBCT5U.js} +1 -1
- package/dist/{chunk-MMGSYMIC.js → chunk-EP7OVWI5.js} +1 -1
- package/dist/{chunk-LDIPVPKI.js → chunk-FFRTAQUW.js} +1 -1
- package/dist/chunk-H3GGFEE5.js +57 -0
- package/dist/{chunk-M3T5JYDJ.js → chunk-HNXMWHLU.js} +1 -1
- package/dist/{chunk-UKD3R2KU.js → chunk-HW2UCOOC.js} +4 -55
- package/dist/{chunk-FFXXGCVG.js → chunk-ITRSITFP.js} +1 -1
- package/dist/{chunk-MU3IE434.js → chunk-JLT2YIBS.js} +267 -52
- package/dist/{chunk-KFCEXCZM.js → chunk-KJZVTWMX.js} +1 -1
- package/dist/{chunk-W3VGCNG6.js → chunk-LDKV4UHI.js} +1 -1
- package/dist/{chunk-AJ6UHXUA.js → chunk-M4NFYEEY.js} +1 -1
- package/dist/{chunk-MB6R4XPZ.js → chunk-NS2OMIU7.js} +15 -3
- package/dist/{chunk-YOSZIWC3.js → chunk-POYUX2NN.js} +149 -11
- package/dist/{chunk-VUGEEMLT.js → chunk-RPUFWIT4.js} +11 -89
- package/dist/{chunk-SYBFMHXQ.js → chunk-S7PIFHE4.js} +590 -67
- package/dist/{chunk-2OGBZPPJ.js → chunk-TWKQFIOW.js} +21 -3
- package/dist/{chunk-EWZFANHJ.js → chunk-VWIMQ5H5.js} +1 -1
- package/dist/{chunk-2XQLL6N6.js → chunk-WFCVS6QB.js} +2 -2
- package/dist/{chunk-QGNXYVBO.js → chunk-Z4FOPROB.js} +17 -0
- package/dist/{content-retention-CrILCNxk.d.ts → content-retention-a1yRdmhI.d.ts} +1 -1
- package/dist/{credit-ledger-4PZNAMDT.js → credit-ledger-MF23UKRJ.js} +6 -3
- package/dist/{credit-menu-BWsVqMh-.d.ts → credit-menu-B2T-O9oY.d.ts} +11 -4
- package/dist/{fx-BM5h4o5S.d.ts → fx-DLhscRUh.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +6 -5
- package/dist/internal/caller.d.ts +8 -6
- package/dist/internal/caller.js +27 -22
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +24 -22
- package/dist/{job-store-92v8e1LQ.d.ts → job-store-B8Ijr5V6.d.ts} +3 -1
- package/dist/{lightning-backend-9oky_wJi.d.ts → lightning-backend-DmwMSgaM.d.ts} +1 -1
- package/dist/memory-credit-ledger-ERD764PS.js +14 -0
- package/dist/{mpp-setup-FURD45LI.js → mpp-setup-JU3MT7QX.js} +3 -3
- package/dist/{payout-reporter-HVJ6WUF3.js → payout-reporter-NXWQVKXW.js} +2 -2
- package/dist/{postgres-consumed-credential-store-WO6OCFXZ.js → postgres-consumed-credential-store-WXJLM6J7.js} +1 -1
- package/dist/{postgres-job-store-H45PRBLA.js → postgres-job-store-ZVMAN6L2.js} +2 -2
- package/dist/{postgres-replay-store-XXJSA457.js → postgres-replay-store-QJ4FG6AR.js} +2 -2
- package/dist/{pricing-X4XU5HXY.js → pricing-KCLENT2C.js} +3 -3
- package/dist/{revenue-reporter-EV3K5L6B.js → revenue-reporter-HD4GMXGD.js} +2 -2
- package/dist/server/index.d.ts +30 -12
- package/dist/server/index.js +32 -30
- package/dist/{step-cache--7yA5Ihr.d.ts → step-cache-DQqpwXa8.d.ts} +206 -47
- package/dist/{tempo-charge-store-5JOIYUIH.js → tempo-charge-store-7LTUAQHQ.js} +2 -2
- package/dist/{tempo-session-store-S6QMLQUA.js → tempo-session-store-LYAIDR2B.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +6 -6
- package/dist/{usd-C7lvLvLk.d.ts → usd-D5kk2nIT.d.ts} +1 -1
- package/dist/{x402-EN5LSOVM.js → x402-RUJ4LUKF.js} +3 -3
- package/package.json +1 -1
- package/recipes/postgres/financial-export-v1.sql +19 -5
- package/dist/memory-credit-ledger-RP7DT5IY.js +0 -11
|
@@ -10,12 +10,15 @@ import {
|
|
|
10
10
|
fifoOrder,
|
|
11
11
|
growthRailValue,
|
|
12
12
|
inKindDrawMsats,
|
|
13
|
+
isFundingRail,
|
|
13
14
|
isInKindDepletion,
|
|
14
15
|
isNonChannelBitcoinRail,
|
|
15
16
|
lotOwedSats,
|
|
16
17
|
netOwedSats,
|
|
18
|
+
refundAssetDelta,
|
|
19
|
+
refundRequest,
|
|
17
20
|
x402SettlementPending
|
|
18
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-2VGMZ7VF.js";
|
|
19
22
|
|
|
20
23
|
// src/sdk/server/memory-credit-ledger.ts
|
|
21
24
|
import { randomUUID } from "crypto";
|
|
@@ -26,7 +29,9 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
26
29
|
* machine and drawing on another would `credit_not_found`.
|
|
27
30
|
*/
|
|
28
31
|
durable = false;
|
|
32
|
+
tempoCreditLossEvidenceVersion = 1;
|
|
29
33
|
credits = /* @__PURE__ */ new Map();
|
|
34
|
+
refunds = /* @__PURE__ */ new Map();
|
|
30
35
|
fundings = /* @__PURE__ */ new Map();
|
|
31
36
|
invoices = /* @__PURE__ */ new Map();
|
|
32
37
|
tempoLosses = /* @__PURE__ */ new Map();
|
|
@@ -35,7 +40,7 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
35
40
|
/** Internal disposable transaction snapshot. The caller must serialize every ledger access. */
|
|
36
41
|
forkForTransaction() {
|
|
37
42
|
const fork = new _MemoryCreditLedger();
|
|
38
|
-
for (const name of ["credits", "fundings", "invoices", "tempoLosses", "x402Losses"]) {
|
|
43
|
+
for (const name of ["credits", "fundings", "invoices", "tempoLosses", "x402Losses", "refunds"]) {
|
|
39
44
|
const target = fork[name];
|
|
40
45
|
for (const [key, value] of this[name]) target.set(key, structuredClone(value));
|
|
41
46
|
}
|
|
@@ -54,6 +59,90 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
54
59
|
if (wedged) throw x402SettlementPending(args.creditId ?? randomUUID(), wedged);
|
|
55
60
|
return run(() => this.fundSync(args));
|
|
56
61
|
}
|
|
62
|
+
/** Development accounting parity; this non-durable store cannot mount admin refunds. */
|
|
63
|
+
refundDraw(args) {
|
|
64
|
+
return run(() => {
|
|
65
|
+
const request = refundRequest(args);
|
|
66
|
+
const prior = this.refunds.get(args.refundId);
|
|
67
|
+
if (prior) {
|
|
68
|
+
if (prior.request !== request) throw new CreditLedgerError("refund_conflict", "This refundId was recorded with different arguments.");
|
|
69
|
+
return { ...prior.result, replayed: true };
|
|
70
|
+
}
|
|
71
|
+
const matches = [...this.credits.values()].flatMap((credit2) => [...credit2.draws.values()].filter((draw2) => args.jobId !== void 0 ? draw2.jobId === args.jobId : credit2.creditId === args.creditId && draw2.drawId === args.drawId).map((draw2) => ({ credit: credit2, draw: draw2 })));
|
|
72
|
+
if (matches.length !== 1 || !matches[0].draw.jobId) {
|
|
73
|
+
throw new CreditLedgerError("draw_not_found", "No unique job-bound draw matches this selector.");
|
|
74
|
+
}
|
|
75
|
+
const { credit, draw } = matches[0];
|
|
76
|
+
if (draw.status !== "settled") throw new CreditLedgerError("draw_not_completed", "Only a settled completed draw can be refunded.");
|
|
77
|
+
const nowMs = args.nowMs ?? Date.now();
|
|
78
|
+
const lastDrain = [...credit.drains.values()].filter((drain) => drain.status !== "released").sort((a, b) => b.ledgerSeq - a.ledgerSeq)[0];
|
|
79
|
+
const drained = lastDrain && lastDrain.balanceAfterMicro === 0 && (credit.lastFundingLedgerSeq === null || credit.lastFundingLedgerSeq < lastDrain.ledgerSeq) && ![...credit.draws.values()].some((later) => later.ledgerSeq > lastDrain.ledgerSeq && later.amountMicro > 0) && ![...this.fundings.values()].some((funding) => funding.creditId === credit.creditId && funding.ledgerSeq !== null && funding.ledgerSeq >= lastDrain.ledgerSeq && funding.amountMicro > 0);
|
|
80
|
+
if (credit.status !== "active" || credit.expiryMs <= nowMs) {
|
|
81
|
+
throw new CreditLedgerError("credit_not_open", "The original credit is no longer open for refunds.");
|
|
82
|
+
}
|
|
83
|
+
if (credit.tempoChannelId || credit.x402ChannelId) {
|
|
84
|
+
throw new CreditLedgerError("credit_refund_channel_unsupported", "Channel collateral cannot back a refund of settled spending.");
|
|
85
|
+
}
|
|
86
|
+
if (credit.balanceMicro === 0 && drained) {
|
|
87
|
+
if (credit.lastFundingLedgerSeq === null) {
|
|
88
|
+
throw new CreditLedgerError("credit_refund_state_unavailable", "The original credit's historical funding and drain order cannot be established.");
|
|
89
|
+
}
|
|
90
|
+
throw new CreditLedgerError("credit_not_open", "The original credit is no longer open for refunds.");
|
|
91
|
+
}
|
|
92
|
+
const before = [...this.refunds.values()].reduce((sum, refund) => sum + (refund.result.creditId === credit.creditId && refund.result.drawId === draw.drawId ? refund.result.amountMicro : 0), 0);
|
|
93
|
+
const amountMicro = args.amountMicro ?? draw.amountMicro - before;
|
|
94
|
+
if (amountMicro <= 0 || amountMicro > draw.amountMicro - before) {
|
|
95
|
+
throw new CreditLedgerError("refund_exceeds_draw", "The refund exceeds the draw's remaining unrefunded charge.");
|
|
96
|
+
}
|
|
97
|
+
if (!isFundingRail(credit.rail)) throw new CreditLedgerError("credit_refund_basis_unavailable", "The original funding rail is not recorded on this older credit.");
|
|
98
|
+
const bitcoin = isNonChannelBitcoinRail(credit.rail);
|
|
99
|
+
const originalSats = draw.settledSats ?? null;
|
|
100
|
+
if (bitcoin && originalSats === null) throw new CreditLedgerError("credit_refund_basis_unavailable", "The original Bitcoin value is not provable from this older draw.");
|
|
101
|
+
const after = before + amountMicro;
|
|
102
|
+
const restoredSats = bitcoin ? refundAssetDelta(originalSats, draw.amountMicro, before, after) : null;
|
|
103
|
+
const restoredMsats = restoredSats === null ? refundAssetDelta(draw.drawMsats, draw.amountMicro, before, after) : restoredSats * 1e3;
|
|
104
|
+
const restoredNative = draw.drawNative === null ? null : refundAssetDelta(draw.drawNative, draw.amountMicro, before, after);
|
|
105
|
+
const balanceAfterMicro = credit.balanceMicro + amountMicro;
|
|
106
|
+
const ledgerSeq = credit.lastLedgerSeq + 1;
|
|
107
|
+
if (![
|
|
108
|
+
balanceAfterMicro,
|
|
109
|
+
ledgerSeq,
|
|
110
|
+
credit.msatsRemaining + restoredMsats,
|
|
111
|
+
(credit.nativeRemaining ?? 0) + (restoredNative ?? 0)
|
|
112
|
+
].every(Number.isSafeInteger)) {
|
|
113
|
+
throw new Error("credit ledger: refund exceeds safe integer range");
|
|
114
|
+
}
|
|
115
|
+
credit.balanceMicro = balanceAfterMicro;
|
|
116
|
+
credit.lastLedgerSeq = ledgerSeq;
|
|
117
|
+
credit.msatsRemaining += restoredMsats;
|
|
118
|
+
if (credit.nativeRemaining !== null) credit.nativeRemaining += restoredNative ?? 0;
|
|
119
|
+
if (bitcoin) credit.lots.push({
|
|
120
|
+
lotId: `lot:refund:${randomUUID()}`,
|
|
121
|
+
creditId: credit.creditId,
|
|
122
|
+
rail: credit.rail,
|
|
123
|
+
satsFunded: restoredSats,
|
|
124
|
+
satsBasisKnown: true,
|
|
125
|
+
creditedMicro: amountMicro,
|
|
126
|
+
remainingMicro: amountMicro,
|
|
127
|
+
fundingRef: args.refundId,
|
|
128
|
+
createdAt: nowMs
|
|
129
|
+
});
|
|
130
|
+
const result = {
|
|
131
|
+
refundId: args.refundId,
|
|
132
|
+
creditId: credit.creditId,
|
|
133
|
+
drawId: draw.drawId,
|
|
134
|
+
jobId: draw.jobId,
|
|
135
|
+
amountMicro,
|
|
136
|
+
currency: credit.currency,
|
|
137
|
+
ledgerSeq,
|
|
138
|
+
refundedAt: nowMs,
|
|
139
|
+
balanceAfterMicro,
|
|
140
|
+
replayed: false
|
|
141
|
+
};
|
|
142
|
+
this.refunds.set(args.refundId, { request, result });
|
|
143
|
+
return { ...result };
|
|
144
|
+
});
|
|
145
|
+
}
|
|
57
146
|
async draw(args) {
|
|
58
147
|
const blocking = await this.blockingRefundForCredit(
|
|
59
148
|
args.creditId,
|
|
@@ -68,8 +157,9 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
68
157
|
blockingRefundForCredit(creditId, statuses) {
|
|
69
158
|
return this.blockingX402Refund(this.credits.get(creditId)?.x402ChannelId, statuses);
|
|
70
159
|
}
|
|
71
|
-
growDraw(args) {
|
|
72
|
-
|
|
160
|
+
async growDraw(args) {
|
|
161
|
+
const blocking = args.spendExistingBalance ? await this.blockingRefundForCredit(args.creditId, X402_SPEND_BLOCKING_SETTLEMENT_STATUSES) : void 0;
|
|
162
|
+
return run(() => this.growDrawSync(args, blocking));
|
|
73
163
|
}
|
|
74
164
|
settle(args) {
|
|
75
165
|
return run(() => {
|
|
@@ -427,6 +517,7 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
427
517
|
}
|
|
428
518
|
);
|
|
429
519
|
}
|
|
520
|
+
existing.lastFundingLedgerSeq = existing.lastLedgerSeq;
|
|
430
521
|
existing.balanceMicro += args.amountMicro;
|
|
431
522
|
existing.expiryMs = args.expiryMs;
|
|
432
523
|
applyBasis(existing, b);
|
|
@@ -457,6 +548,7 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
457
548
|
expiryMs: args.expiryMs,
|
|
458
549
|
status: "active",
|
|
459
550
|
lastLedgerSeq: 0,
|
|
551
|
+
lastFundingLedgerSeq: 0,
|
|
460
552
|
createdAt: nowMs,
|
|
461
553
|
draws: /* @__PURE__ */ new Map(),
|
|
462
554
|
rail: null,
|
|
@@ -537,7 +629,7 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
537
629
|
credit.draws.set(args.drawId, draw);
|
|
538
630
|
return { ...drawResult(draw, credit), replayed: false };
|
|
539
631
|
}
|
|
540
|
-
growDrawSync(args) {
|
|
632
|
+
growDrawSync(args, x402Refund) {
|
|
541
633
|
assertAmount(args.addAmountMicro, { min: 1 });
|
|
542
634
|
const credit = this.requireCredit(args.creditId);
|
|
543
635
|
const draw = credit.draws.get(args.drawId);
|
|
@@ -562,6 +654,16 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
562
654
|
{ expectedJobId: draw.jobId }
|
|
563
655
|
);
|
|
564
656
|
}
|
|
657
|
+
if (args.spendExistingBalance) {
|
|
658
|
+
if (credit.expiryMs <= (args.nowMs ?? Date.now())) {
|
|
659
|
+
throw new CreditLedgerError("credit_expired", `credit ${args.creditId} expired`, {
|
|
660
|
+
expiryMs: credit.expiryMs,
|
|
661
|
+
balanceMicro: credit.balanceMicro
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
if (x402Refund) throw x402SettlementPending(args.creditId, x402Refund);
|
|
665
|
+
if (credit.tempoChannelId) throw new CreditLedgerError("tempo_channel_closing", "Tempo balance growth requires a durable channel lifecycle");
|
|
666
|
+
}
|
|
565
667
|
const pending = pendingSums(credit);
|
|
566
668
|
const available = credit.balanceMicro - pending.micro;
|
|
567
669
|
const headroom = args.capMicro === void 0 ? args.addAmountMicro : Math.max(0, args.capMicro - draw.grownMicro);
|
|
@@ -687,6 +789,15 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
687
789
|
return run(() => {
|
|
688
790
|
const channelId = evidence.channelId.toLowerCase();
|
|
689
791
|
const observedAt = evidence.observedAt ?? Date.now();
|
|
792
|
+
const refunded = evidence.refundedToPayerNative ?? 0n;
|
|
793
|
+
if (refunded < 0n) throw new Error("Tempo close refund must be nonnegative");
|
|
794
|
+
const payerExit = evidence.closeKind === "payer_exit";
|
|
795
|
+
if (payerExit && evidence.refundedToPayerNative !== void 0 || evidence.closeKind === "cooperative_close" && evidence.refundedToPayerNative === void 0) {
|
|
796
|
+
throw new Error("Tempo close kind requires matching exact cooperative refund evidence");
|
|
797
|
+
}
|
|
798
|
+
const lossNative = (payerExit ? evidence.consumedNative : evidence.highestVoucherNative) - evidence.settledOnChainNative - (payerExit ? 0n : refunded);
|
|
799
|
+
const lossBasis = payerExit ? "payer_exit" : evidence.refundedToPayerNative === void 0 ? "caller_asserted" : "cooperative_close";
|
|
800
|
+
if (lossNative <= 0n) return [...this.tempoLosses.values()].filter((loss) => loss.channelId === channelId);
|
|
690
801
|
for (const credit of this.credits.values()) {
|
|
691
802
|
if (credit.tempoChannelId !== channelId) continue;
|
|
692
803
|
if (credit.status === "unbacked") continue;
|
|
@@ -701,6 +812,9 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
701
812
|
highestVoucherNative: evidence.highestVoucherNative,
|
|
702
813
|
consumedServiceMicro,
|
|
703
814
|
consumedNative: evidence.consumedNative,
|
|
815
|
+
refundedToPayerNative: evidence.refundedToPayerNative ?? null,
|
|
816
|
+
lossNative,
|
|
817
|
+
lossBasis,
|
|
704
818
|
observedAt
|
|
705
819
|
});
|
|
706
820
|
credit.status = "unbacked";
|
|
@@ -708,9 +822,9 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
708
822
|
return [...this.tempoLosses.values()].filter((loss) => loss.channelId === channelId);
|
|
709
823
|
});
|
|
710
824
|
}
|
|
711
|
-
listTempoCreditLosses(args) {
|
|
825
|
+
listTempoCreditLosses(args, _tx) {
|
|
712
826
|
return Promise.resolve(
|
|
713
|
-
[...this.tempoLosses.values()].sort((a, b) => b.observedAt - a.observedAt || a.creditId.localeCompare(b.creditId)).slice(0, args?.limit ?? 50)
|
|
827
|
+
[...this.tempoLosses.values()].filter((loss) => !args?.channelId || loss.channelId === args.channelId.toLowerCase()).sort((a, b) => b.observedAt - a.observedAt || a.creditId.localeCompare(b.creditId)).slice(0, args?.limit ?? 50)
|
|
714
828
|
);
|
|
715
829
|
}
|
|
716
830
|
terminalizeX402Credit(evidence, _tx) {
|
|
@@ -841,7 +955,9 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
841
955
|
sentAt: null,
|
|
842
956
|
releasedAt: null,
|
|
843
957
|
writeOffNote: null,
|
|
844
|
-
writtenOffAt: null
|
|
958
|
+
writtenOffAt: null,
|
|
959
|
+
provenRefundNative: null,
|
|
960
|
+
refundPaymentProven: false
|
|
845
961
|
};
|
|
846
962
|
applyLotDebits(credit, drain.lotDebits, -1);
|
|
847
963
|
credit.drains.set(args.drainId, drain);
|
|
@@ -874,7 +990,7 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
874
990
|
const lots = openLots(credit);
|
|
875
991
|
const covered = lots.reduce((sum, lot) => sum + lot.remainingMicro, 0);
|
|
876
992
|
const basisless = lots.reduce(
|
|
877
|
-
(sum, lot) => sum + (lot.satsFunded === 0 ? lot.remainingMicro : 0),
|
|
993
|
+
(sum, lot) => sum + (lot.satsFunded === 0 && !lot.satsBasisKnown ? lot.remainingMicro : 0),
|
|
878
994
|
0
|
|
879
995
|
);
|
|
880
996
|
const inKind = covered >= credit.balanceMicro && basisless === 0;
|
|
@@ -947,7 +1063,7 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
947
1063
|
for (const drain of credit.drains.values()) {
|
|
948
1064
|
if (drain.status !== "pending" && drain.status !== "exit_required" || drain.method !== "tempo") continue;
|
|
949
1065
|
if (drain.createdAt > args.createdBeforeMs) continue;
|
|
950
|
-
if (!args.includeResolved && drain.writtenOffAt !== null) continue;
|
|
1066
|
+
if (!args.includeResolved && !args.includeWrittenOff && drain.writtenOffAt !== null) continue;
|
|
951
1067
|
out.push(drainRecord(drain, credit));
|
|
952
1068
|
}
|
|
953
1069
|
}
|
|
@@ -992,6 +1108,25 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
992
1108
|
return { drain: drainRecord(drain, credit), replayed: false };
|
|
993
1109
|
});
|
|
994
1110
|
}
|
|
1111
|
+
recordTempoDrainRefund(args) {
|
|
1112
|
+
const amount = String(args.refundedNative);
|
|
1113
|
+
if (!/^\d{1,78}$/.test(amount)) return Promise.reject(new CreditLedgerError("invalid_basis", "Tempo refund evidence must be a bounded non-negative integer."));
|
|
1114
|
+
return this.recordTempoDrainRefundEvidence(args, amount);
|
|
1115
|
+
}
|
|
1116
|
+
recordTempoDrainPayment(args) {
|
|
1117
|
+
return this.recordTempoDrainRefundEvidence(args, null);
|
|
1118
|
+
}
|
|
1119
|
+
recordTempoDrainRefundEvidence(args, amount) {
|
|
1120
|
+
return run(() => {
|
|
1121
|
+
const credit = this.credits.get(args.creditId);
|
|
1122
|
+
const drain = credit?.drains.get(args.drainId);
|
|
1123
|
+
if (!credit?.tempoChannelId || !drain || drain.method !== "tempo" || drain.status !== "pending" && drain.status !== "exit_required") return;
|
|
1124
|
+
if (amount !== null && (drain.provenRefundNative === null || BigInt(amount) > BigInt(drain.provenRefundNative))) {
|
|
1125
|
+
drain.provenRefundNative = amount;
|
|
1126
|
+
}
|
|
1127
|
+
drain.refundPaymentProven ||= amount === null || BigInt(amount) > 0n;
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
995
1130
|
releaseDrain(args) {
|
|
996
1131
|
return run(() => {
|
|
997
1132
|
const { credit, drain } = this.requireDrain(args.creditId, args.drainId);
|
|
@@ -1115,6 +1250,7 @@ var MemoryCreditLedger = class _MemoryCreditLedger {
|
|
|
1115
1250
|
if (isNonChannelBitcoinRail(credit.rail)) {
|
|
1116
1251
|
const depletion = depleteLots(openLots(credit), draw.amountMicro);
|
|
1117
1252
|
const settledMsats = inKindDrawMsats(depletion, draw.amountMicro);
|
|
1253
|
+
draw.settledSats = settledMsats === null ? null : settledMsats / 1e3;
|
|
1118
1254
|
if (settledMsats !== null && settledMsats !== draw.drawMsats) {
|
|
1119
1255
|
draw.allocatedMsats = draw.drawMsats;
|
|
1120
1256
|
draw.drawMsats = settledMsats;
|
|
@@ -1295,7 +1431,9 @@ function drainRecord(drain, credit) {
|
|
|
1295
1431
|
sentAt: drain.sentAt,
|
|
1296
1432
|
releasedAt: drain.releasedAt,
|
|
1297
1433
|
writeOffNote: drain.writeOffNote,
|
|
1298
|
-
writtenOffAt: drain.writtenOffAt
|
|
1434
|
+
writtenOffAt: drain.writtenOffAt,
|
|
1435
|
+
provenRefundNative: drain.provenRefundNative,
|
|
1436
|
+
refundPaymentProven: drain.refundPaymentProven
|
|
1299
1437
|
};
|
|
1300
1438
|
}
|
|
1301
1439
|
function assertAmount(amountMicro, opts) {
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
computeResultHash,
|
|
3
|
+
isDrainReceipt,
|
|
4
|
+
isFundingReceipt,
|
|
5
|
+
verifyDrainReceipt,
|
|
6
|
+
verifyFundingReceipt,
|
|
7
|
+
verifyReceipt
|
|
8
|
+
} from "./chunk-5H7P3ORL.js";
|
|
4
9
|
import {
|
|
5
10
|
DvmError
|
|
6
11
|
} from "./chunk-BPYMEMQX.js";
|
|
12
|
+
import {
|
|
13
|
+
canonicaliseForSigning
|
|
14
|
+
} from "./chunk-H3GGFEE5.js";
|
|
7
15
|
import {
|
|
8
16
|
callerLoggers
|
|
9
17
|
} from "./chunk-66HGCPBU.js";
|
|
10
18
|
import {
|
|
11
19
|
diagnosticConsole
|
|
12
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-Z4FOPROB.js";
|
|
13
21
|
|
|
14
22
|
// src/lib/cashu/lock-pubkey.ts
|
|
15
23
|
function toLockPubkey(raw) {
|
|
@@ -1553,82 +1561,6 @@ function hexToBytes4(hex) {
|
|
|
1553
1561
|
return out;
|
|
1554
1562
|
}
|
|
1555
1563
|
|
|
1556
|
-
// src/lib/receipt.ts
|
|
1557
|
-
import { schnorr as schnorr4 } from "@noble/curves/secp256k1.js";
|
|
1558
|
-
import { sha256 as sha2564 } from "@noble/hashes/sha2.js";
|
|
1559
|
-
import { bytesToHex as bytesToHex5, hexToBytes as hexToBytes5 } from "@noble/hashes/utils.js";
|
|
1560
|
-
function computeResultHash(summary, artifactContents) {
|
|
1561
|
-
const artifactHashes = artifactContents.map(
|
|
1562
|
-
(content) => bytesToHex5(sha2564(canonicaliseForSigning(content)))
|
|
1563
|
-
);
|
|
1564
|
-
return bytesToHex5(
|
|
1565
|
-
sha2564(
|
|
1566
|
-
canonicaliseForSigning({
|
|
1567
|
-
summary: summary ?? null,
|
|
1568
|
-
artifact_hashes: artifactHashes
|
|
1569
|
-
})
|
|
1570
|
-
)
|
|
1571
|
-
);
|
|
1572
|
-
}
|
|
1573
|
-
function signReceipt(unsigned, secretHex) {
|
|
1574
|
-
const bytes = canonicaliseForSigning(unsigned);
|
|
1575
|
-
const signature = bytesToHex5(schnorr4.sign(bytes, hexToBytes5(secretHex)));
|
|
1576
|
-
return { ...unsigned, signature };
|
|
1577
|
-
}
|
|
1578
|
-
function verifyReceipt(receipt) {
|
|
1579
|
-
try {
|
|
1580
|
-
const { signature, ...unsigned } = receipt;
|
|
1581
|
-
const bytes = canonicaliseForSigning(unsigned);
|
|
1582
|
-
return schnorr4.verify(hexToBytes5(signature), bytes, hexToBytes5(receipt.receipt_pubkey));
|
|
1583
|
-
} catch {
|
|
1584
|
-
return false;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
function isSignedJobReceipt(value) {
|
|
1588
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1589
|
-
const r = value;
|
|
1590
|
-
const paid = r.paid;
|
|
1591
|
-
return r.v === 1 && typeof r.job_id === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.capability === "string" && (r.outcome === "completed" || r.outcome === "failed" || r.outcome === "cancelled") && typeof r.seq === "number" && typeof r.issued_at === "number" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string" && !!paid && typeof paid === "object" && !Array.isArray(paid) && typeof paid.msats === "number";
|
|
1592
|
-
}
|
|
1593
|
-
function signDrainReceipt(unsigned, secretHex) {
|
|
1594
|
-
const bytes = canonicaliseForSigning(unsigned);
|
|
1595
|
-
const signature = bytesToHex5(schnorr4.sign(bytes, hexToBytes5(secretHex)));
|
|
1596
|
-
return { ...unsigned, signature };
|
|
1597
|
-
}
|
|
1598
|
-
function signFundingReceipt(unsigned, secretHex) {
|
|
1599
|
-
const bytes = canonicaliseForSigning(unsigned);
|
|
1600
|
-
const signature = bytesToHex5(schnorr4.sign(bytes, hexToBytes5(secretHex)));
|
|
1601
|
-
return { ...unsigned, signature };
|
|
1602
|
-
}
|
|
1603
|
-
function isFundingReceipt(value) {
|
|
1604
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1605
|
-
const r = value;
|
|
1606
|
-
return r.v === 1 && r.kind === "credit_funding" && typeof r.credit_id === "string" && typeof r.fund_id === "string" && typeof r.funded_micro === "number" && typeof r.balance_after_micro === "number" && typeof r.ledger_seq === "number" && typeof r.issued_at === "number" && typeof r.caller_pubkey === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string";
|
|
1607
|
-
}
|
|
1608
|
-
function verifyFundingReceipt(receipt) {
|
|
1609
|
-
try {
|
|
1610
|
-
const { signature, ...unsigned } = receipt;
|
|
1611
|
-
const bytes = canonicaliseForSigning(unsigned);
|
|
1612
|
-
return schnorr4.verify(hexToBytes5(signature), bytes, hexToBytes5(receipt.receipt_pubkey));
|
|
1613
|
-
} catch {
|
|
1614
|
-
return false;
|
|
1615
|
-
}
|
|
1616
|
-
}
|
|
1617
|
-
function isDrainReceipt(value) {
|
|
1618
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1619
|
-
const r = value;
|
|
1620
|
-
return r.v === 1 && r.kind === "credit_drain" && typeof r.credit_id === "string" && typeof r.drain_id === "string" && (r.event === "requested" || r.event === "parked" || r.event === "picked_up" || r.event === "sent" || r.event === "released") && typeof r.method === "string" && typeof r.amount_micro === "number" && typeof r.issued_at === "number" && typeof r.caller_pubkey === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string";
|
|
1621
|
-
}
|
|
1622
|
-
function verifyDrainReceipt(receipt) {
|
|
1623
|
-
try {
|
|
1624
|
-
const { signature, ...unsigned } = receipt;
|
|
1625
|
-
const bytes = canonicaliseForSigning(unsigned);
|
|
1626
|
-
return schnorr4.verify(hexToBytes5(signature), bytes, hexToBytes5(receipt.receipt_pubkey));
|
|
1627
|
-
} catch {
|
|
1628
|
-
return false;
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
1564
|
// src/lib/receipt-verify.ts
|
|
1633
1565
|
function attestedDvmIdentity(builder) {
|
|
1634
1566
|
const builderPubkey = authenticatedBuilderPubkey(builder);
|
|
@@ -1924,16 +1856,6 @@ export {
|
|
|
1924
1856
|
buildAttestation,
|
|
1925
1857
|
signAttestation,
|
|
1926
1858
|
verifyAttestation,
|
|
1927
|
-
computeResultHash,
|
|
1928
|
-
signReceipt,
|
|
1929
|
-
verifyReceipt,
|
|
1930
|
-
isSignedJobReceipt,
|
|
1931
|
-
signDrainReceipt,
|
|
1932
|
-
signFundingReceipt,
|
|
1933
|
-
isFundingReceipt,
|
|
1934
|
-
verifyFundingReceipt,
|
|
1935
|
-
isDrainReceipt,
|
|
1936
|
-
verifyDrainReceipt,
|
|
1937
1859
|
attestedDvmIdentity,
|
|
1938
1860
|
authenticatedBuilderPubkey,
|
|
1939
1861
|
verifyJobReceipt,
|