@dvmkit/sdk 0.16.2 → 0.17.0
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-XSF5YTEY.js → chunk-2PN4DKZW.js} +1 -1
- package/dist/{chunk-F2LNWZCV.js → chunk-3KRFFLAT.js} +1 -1
- package/dist/{chunk-KERFCBT7.js → chunk-4QYADZFN.js} +498 -129
- package/dist/{chunk-V73WRF46.js → chunk-5CCQEAQV.js} +1 -1
- package/dist/{chunk-4IFZHJQK.js → chunk-5RLNRLLB.js} +1 -1
- package/dist/{chunk-7QGS27UT.js → chunk-72A4PHLD.js} +1 -1
- package/dist/{chunk-XBQTFOIT.js → chunk-7RWE6ELV.js} +1 -1
- package/dist/{chunk-N4SBDUVD.js → chunk-A6EY4K46.js} +1 -1
- package/dist/{chunk-5U2RG3ZW.js → chunk-ALTE7I6C.js} +5 -0
- package/dist/{chunk-K4ZQE7IB.js → chunk-B5MPLDRC.js} +2 -2
- package/dist/{chunk-PP5WHB6T.js → chunk-C5XNZLZ7.js} +1 -1
- package/dist/{chunk-2UZOJRRS.js → chunk-CVN2YNMG.js} +1 -1
- package/dist/{chunk-MD34LE6M.js → chunk-CXRI4N4Y.js} +1 -1
- package/dist/{chunk-ELNWQS24.js → chunk-EIDRCGTY.js} +1 -1
- package/dist/{chunk-ICHC4VDZ.js → chunk-KRX7VNBG.js} +1 -1
- package/dist/{chunk-TN6MWTZI.js → chunk-LY2JYSJS.js} +1 -1
- package/dist/{chunk-7N5VDCG3.js → chunk-MWDUGMN2.js} +2 -2
- package/dist/{chunk-FRGKANTZ.js → chunk-ORBWKYDE.js} +1 -1
- package/dist/{chunk-VQHBJXBL.js → chunk-QTKGFG3I.js} +1 -1
- package/dist/{chunk-PBT3H2LZ.js → chunk-RX6FT7XA.js} +1 -1
- package/dist/{chunk-OYBSDJR6.js → chunk-VKFR5PCW.js} +2 -2
- package/dist/{chunk-V4CBI5HB.js → chunk-Y6JJDOGO.js} +1 -1
- package/dist/{content-retention-BASsjgKw.d.ts → content-retention-B_hOQS36.d.ts} +1 -1
- package/dist/{credit-ledger-VWZ5NP7V.js → credit-ledger-5HMJ6VUX.js} +3 -3
- package/dist/{credit-menu-BfXaeHgR.d.ts → credit-menu-D-h0zJCZ.d.ts} +42 -10
- package/dist/{fx-BmvWGISH.d.ts → fx-CpqQaIfg.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/internal/caller.d.ts +14 -8
- package/dist/internal/caller.js +7 -7
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +20 -20
- package/dist/{job-store-CA7u1nHV.d.ts → job-store-CgXT79tS.d.ts} +1 -1
- package/dist/{lightning-backend-BOcopzXk.d.ts → lightning-backend-B1hRUIOb.d.ts} +1 -1
- package/dist/{memory-credit-ledger-DZWRQGSF.js → memory-credit-ledger-ME6FH462.js} +4 -4
- package/dist/{mpp-setup-3NJY354I.js → mpp-setup-BLIYBORK.js} +3 -3
- package/dist/{payout-reporter-P3652TLG.js → payout-reporter-5QAHCYIO.js} +2 -2
- package/dist/{postgres-consumed-credential-store-S2CBQ4NO.js → postgres-consumed-credential-store-4PCJEZBD.js} +1 -1
- package/dist/{postgres-job-store-JRSG54VJ.js → postgres-job-store-E5GXLRB4.js} +2 -2
- package/dist/{postgres-replay-store-ZPILIJIW.js → postgres-replay-store-GH5AINQR.js} +2 -2
- package/dist/{pricing-3P7KAONY.js → pricing-JJYLTTWK.js} +3 -3
- package/dist/{revenue-reporter-2P3PWJJM.js → revenue-reporter-6XARUEG6.js} +2 -2
- package/dist/server/index.d.ts +10 -10
- package/dist/server/index.js +32 -31
- package/dist/{step-cache-BCRHimiY.d.ts → step-cache-Bezn-_ZL.d.ts} +41 -3
- package/dist/{tempo-charge-store-2LK6IDLS.js → tempo-charge-store-A3CDF7D5.js} +2 -2
- package/dist/{tempo-session-store-5MHCH3YW.js → tempo-session-store-EWBE5HJM.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +6 -6
- package/dist/{usd-B8_WMfHT.d.ts → usd-CJwU3-A4.d.ts} +1 -1
- package/dist/{x402-6T73AZQ6.js → x402-HVCUEWWU.js} +3 -3
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-XRLKGCAW.js";
|
|
6
6
|
import {
|
|
7
7
|
x402EarnedCeiling
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KRX7VNBG.js";
|
|
9
9
|
import {
|
|
10
10
|
createX402FacilitatorAuthHeaders,
|
|
11
11
|
createX402FacilitatorClient,
|
|
@@ -14,13 +14,13 @@ import {
|
|
|
14
14
|
verifyWithFacilitator,
|
|
15
15
|
withPaymentDiagnostics,
|
|
16
16
|
withPaymentStage
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-3KRFFLAT.js";
|
|
18
18
|
import {
|
|
19
19
|
MemoryCreditLedger
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-C5XNZLZ7.js";
|
|
21
21
|
import {
|
|
22
22
|
PostgresJobStore
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-A6EY4K46.js";
|
|
24
24
|
import {
|
|
25
25
|
SIGNED_ENVELOPE_FIELDS,
|
|
26
26
|
SignedRequestError,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
humanizeZodIssues,
|
|
29
29
|
signedRequestInput,
|
|
30
30
|
zodIssuesOf
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-5CCQEAQV.js";
|
|
32
32
|
import {
|
|
33
33
|
MemoryJobStore,
|
|
34
34
|
UNCAPPABLE_ASK_TOTAL,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
isJobRetentionStore,
|
|
38
38
|
isReceiptIssuingStore,
|
|
39
39
|
isStreamableJobStore
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-Y6JJDOGO.js";
|
|
41
41
|
import {
|
|
42
42
|
ContentHoldError,
|
|
43
43
|
JobCancelledError,
|
|
@@ -78,7 +78,7 @@ import {
|
|
|
78
78
|
receiptPubkeyFromSecret,
|
|
79
79
|
toLockPubkey,
|
|
80
80
|
verifyChallenge
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-7RWE6ELV.js";
|
|
82
82
|
import {
|
|
83
83
|
X402_BATCH_SETTLEMENT_SCHEME,
|
|
84
84
|
X402_DEFAULT_FACILITATOR,
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
} from "./chunk-SXL44PL5.js";
|
|
106
106
|
import {
|
|
107
107
|
createConsoleLogger
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-QTKGFG3I.js";
|
|
109
109
|
import {
|
|
110
110
|
StepCache
|
|
111
111
|
} from "./chunk-BQJIFRAZ.js";
|
|
@@ -122,7 +122,7 @@ import {
|
|
|
122
122
|
roundUsd,
|
|
123
123
|
satsToFiat,
|
|
124
124
|
validateCurrency
|
|
125
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-72A4PHLD.js";
|
|
126
126
|
import {
|
|
127
127
|
CreditLedger,
|
|
128
128
|
CreditLedgerError,
|
|
@@ -138,7 +138,7 @@ import {
|
|
|
138
138
|
isNonChannelBitcoinRail,
|
|
139
139
|
netOwedSats,
|
|
140
140
|
x402SettlementPending
|
|
141
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-B5MPLDRC.js";
|
|
142
142
|
import {
|
|
143
143
|
parseStoreValue
|
|
144
144
|
} from "./chunk-YG7G4DPZ.js";
|
|
@@ -156,7 +156,7 @@ import {
|
|
|
156
156
|
} from "./chunk-5UC7TOQC.js";
|
|
157
157
|
import {
|
|
158
158
|
withPostgresRecoveryContext
|
|
159
|
-
} from "./chunk-
|
|
159
|
+
} from "./chunk-EIDRCGTY.js";
|
|
160
160
|
import {
|
|
161
161
|
DvmError,
|
|
162
162
|
x402NetworkByCaip2
|
|
@@ -174,17 +174,17 @@ import {
|
|
|
174
174
|
installHostedTempoCloseGuard,
|
|
175
175
|
isTempoInsufficientFundsError,
|
|
176
176
|
resolveTempoNetwork
|
|
177
|
-
} from "./chunk-
|
|
177
|
+
} from "./chunk-MWDUGMN2.js";
|
|
178
178
|
import {
|
|
179
179
|
loggers,
|
|
180
180
|
pinDimension,
|
|
181
181
|
withSpan,
|
|
182
182
|
withTraceContext
|
|
183
|
-
} from "./chunk-
|
|
183
|
+
} from "./chunk-LY2JYSJS.js";
|
|
184
184
|
import {
|
|
185
185
|
createDiagnosticCapabilityAuthority,
|
|
186
186
|
diagnosticConsole
|
|
187
|
-
} from "./chunk-
|
|
187
|
+
} from "./chunk-ALTE7I6C.js";
|
|
188
188
|
|
|
189
189
|
// src/sdk/server/lock-pubkey-store.ts
|
|
190
190
|
async function initLockPubkeyTable(db) {
|
|
@@ -428,13 +428,26 @@ async function insertAccumulatorRows(db, args) {
|
|
|
428
428
|
client.release();
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
|
-
async function
|
|
432
|
-
|
|
431
|
+
async function claimAccumulatorRequestId(tx, dvmId, requestId) {
|
|
432
|
+
await tx.query("SELECT pg_advisory_xact_lock(hashtextextended($1, 0))", [
|
|
433
|
+
JSON.stringify(["wallet_accumulator_request", dvmId, requestId])
|
|
434
|
+
]);
|
|
435
|
+
const { rows: rows2 } = await tx.query(
|
|
436
|
+
`SELECT 1 FROM wallet_accumulator WHERE dvm_id = $1 AND request_id = $2 LIMIT 1`,
|
|
437
|
+
[dvmId, requestId]
|
|
438
|
+
);
|
|
439
|
+
if (rows2.length > 0) throw new AccumulatorReplayError(dvmId, requestId);
|
|
440
|
+
}
|
|
441
|
+
async function acceptedRequestIds(db, dvmId, secrets) {
|
|
442
|
+
if (secrets.length === 0) return [];
|
|
443
|
+
const hashes = secrets.map(hashProofSecret);
|
|
433
444
|
const { rows: rows2 } = await db.query(
|
|
434
|
-
`SELECT
|
|
435
|
-
|
|
445
|
+
`SELECT proof_secret_hash, request_id FROM wallet_accumulator
|
|
446
|
+
WHERE dvm_id = $1 AND proof_secret_hash = ANY($2::text[])`,
|
|
447
|
+
[dvmId, hashes]
|
|
436
448
|
);
|
|
437
|
-
|
|
449
|
+
const byHash = new Map(rows2.map((row) => [row.proof_secret_hash, row.request_id]));
|
|
450
|
+
return hashes.map((hash3) => byHash.get(hash3));
|
|
438
451
|
}
|
|
439
452
|
async function listPendingBatches(db, dvmId) {
|
|
440
453
|
const { rows: rows2 } = await db.query(
|
|
@@ -3234,7 +3247,7 @@ function paymentFailureFields(error) {
|
|
|
3234
3247
|
}
|
|
3235
3248
|
|
|
3236
3249
|
// src/sdk/server/payment.ts
|
|
3237
|
-
import { createHash as
|
|
3250
|
+
import { createHash as createHash5, randomBytes, randomUUID as randomUUID2 } from "crypto";
|
|
3238
3251
|
import { Challenge } from "mppx";
|
|
3239
3252
|
|
|
3240
3253
|
// src/lib/cashu/verify.ts
|
|
@@ -3328,6 +3341,63 @@ function methodNativeAmountToDecimal(amount, methodName) {
|
|
|
3328
3341
|
return `${nativeAmount2 / scale}.${(nativeAmount2 % scale).toString().padStart(decimals, "0")}`;
|
|
3329
3342
|
}
|
|
3330
3343
|
|
|
3344
|
+
// src/sdk/server/cashu-payment-request.ts
|
|
3345
|
+
import { createHash as createHash4 } from "crypto";
|
|
3346
|
+
import { PaymentRequest } from "@cashu/cashu-ts";
|
|
3347
|
+
function cashuPaymentRequest(args) {
|
|
3348
|
+
return new PaymentRequest(
|
|
3349
|
+
void 0,
|
|
3350
|
+
void 0,
|
|
3351
|
+
Math.ceil(args.requiredMsats / 1e3),
|
|
3352
|
+
"sat",
|
|
3353
|
+
args.mints,
|
|
3354
|
+
void 0,
|
|
3355
|
+
false,
|
|
3356
|
+
{ kind: "P2PK", data: args.lockPubkey, tags: [] }
|
|
3357
|
+
).toEncodedCreqA();
|
|
3358
|
+
}
|
|
3359
|
+
function proofSetRequestId(secrets) {
|
|
3360
|
+
const canonical = JSON.stringify([...secrets].sort());
|
|
3361
|
+
return `${DERIVED_REQUEST_ID_PREFIX}${createHash4("sha256").update(canonical).digest("hex")}`;
|
|
3362
|
+
}
|
|
3363
|
+
var DERIVED_REQUEST_ID_PREFIX = "nut24-";
|
|
3364
|
+
function withFxHistory(inner, opts = {}) {
|
|
3365
|
+
const holdWindowMs = opts.holdWindowMs ?? FX_HOLD_WINDOW_MS;
|
|
3366
|
+
const now = opts.now ?? Date.now;
|
|
3367
|
+
const history = [];
|
|
3368
|
+
return {
|
|
3369
|
+
async fetch() {
|
|
3370
|
+
const snapshot = await inner.fetch();
|
|
3371
|
+
const latest = history.at(-1);
|
|
3372
|
+
if (latest && sameRates(latest.snapshot, snapshot)) {
|
|
3373
|
+
latest.lastPricedAt = now();
|
|
3374
|
+
} else {
|
|
3375
|
+
history.push({ snapshot, lastPricedAt: now() });
|
|
3376
|
+
if (history.length > 4) history.shift();
|
|
3377
|
+
}
|
|
3378
|
+
return snapshot;
|
|
3379
|
+
},
|
|
3380
|
+
supportedCurrencies: () => inner.supportedCurrencies(),
|
|
3381
|
+
...inner.lastKnown && { lastKnown: inner.lastKnown.bind(inner) },
|
|
3382
|
+
previousFor(pricedAt) {
|
|
3383
|
+
for (let i = history.length - 1; i > 0; i--) {
|
|
3384
|
+
if (!sameRates(history[i].snapshot, pricedAt)) continue;
|
|
3385
|
+
const replaced = history[i - 1];
|
|
3386
|
+
return now() - replaced.lastPricedAt <= holdWindowMs ? replaced.snapshot : void 0;
|
|
3387
|
+
}
|
|
3388
|
+
return void 0;
|
|
3389
|
+
}
|
|
3390
|
+
};
|
|
3391
|
+
}
|
|
3392
|
+
function sameRates(a, b) {
|
|
3393
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a.rates), ...Object.keys(b.rates)]);
|
|
3394
|
+
for (const key of keys) {
|
|
3395
|
+
if (a.rates[key] !== b.rates[key]) return false;
|
|
3396
|
+
}
|
|
3397
|
+
return true;
|
|
3398
|
+
}
|
|
3399
|
+
var FX_HOLD_WINDOW_MS = 10 * 6e4;
|
|
3400
|
+
|
|
3331
3401
|
// src/lib/mints.ts
|
|
3332
3402
|
function isTestMintUrl(url) {
|
|
3333
3403
|
let host;
|
|
@@ -3459,13 +3529,20 @@ async function acceptAccumulatorPayment(opts) {
|
|
|
3459
3529
|
if (opts.disposable && !opts.mints.every(isTestMintUrl)) {
|
|
3460
3530
|
throw new Error("Disposable Cashu accepts only known test or loopback mints.");
|
|
3461
3531
|
}
|
|
3462
|
-
if (!opts.requestId) {
|
|
3532
|
+
if (!opts.requestId && !opts.deriveRequestId) {
|
|
3463
3533
|
return {
|
|
3464
3534
|
kind: "rejected",
|
|
3465
3535
|
code: "missing_request_id",
|
|
3466
3536
|
message: "X-Cashu-Request-Id header required for the agent-wallet path."
|
|
3467
3537
|
};
|
|
3468
3538
|
}
|
|
3539
|
+
if (opts.requestId?.startsWith(DERIVED_REQUEST_ID_PREFIX)) {
|
|
3540
|
+
return {
|
|
3541
|
+
kind: "rejected",
|
|
3542
|
+
code: "reserved_request_id",
|
|
3543
|
+
message: `A Cashu request id may not start with "${DERIVED_REQUEST_ID_PREFIX}".`
|
|
3544
|
+
};
|
|
3545
|
+
}
|
|
3469
3546
|
if (opts.lockPubkeys.length === 0) {
|
|
3470
3547
|
return {
|
|
3471
3548
|
kind: "rejected",
|
|
@@ -3486,6 +3563,9 @@ async function acceptAccumulatorPayment(opts) {
|
|
|
3486
3563
|
if (meta.unit !== "sat" || proofs.length === 0) {
|
|
3487
3564
|
throw new Error("Cashu payment requires nonempty sat proofs.");
|
|
3488
3565
|
}
|
|
3566
|
+
if (new Set(proofs.map((proof) => proof.secret)).size !== proofs.length) {
|
|
3567
|
+
throw new Error("Cashu payment carries the same proof more than once.");
|
|
3568
|
+
}
|
|
3489
3569
|
for (const proof of proofs) {
|
|
3490
3570
|
if (!proof.dleq || !verifyDleqIfPresent(proof, wallet.getKeyset(proof.id))) {
|
|
3491
3571
|
throw new Error(
|
|
@@ -3501,10 +3581,12 @@ async function acceptAccumulatorPayment(opts) {
|
|
|
3501
3581
|
message: err instanceof Error ? err.message : "Cashu token decode failed"
|
|
3502
3582
|
};
|
|
3503
3583
|
}
|
|
3584
|
+
const requestId = opts.requestId || proofSetRequestId(proofs.map((proof) => proof.secret));
|
|
3504
3585
|
const acceptedValue = {
|
|
3505
3586
|
...valuation,
|
|
3506
3587
|
mintUrl,
|
|
3507
|
-
paidMsats: valuation.netMsats
|
|
3588
|
+
paidMsats: valuation.netMsats,
|
|
3589
|
+
requestId
|
|
3508
3590
|
};
|
|
3509
3591
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
3510
3592
|
const tExpireMsByIndex = [];
|
|
@@ -3521,9 +3603,8 @@ async function acceptAccumulatorPayment(opts) {
|
|
|
3521
3603
|
tExpireMsByIndex.push(parseNut11LocktimeMs(p.secret));
|
|
3522
3604
|
}
|
|
3523
3605
|
if (belowFloorMessage) {
|
|
3524
|
-
const
|
|
3525
|
-
|
|
3526
|
-
if (banked) return replayRejected();
|
|
3606
|
+
const banked = await acceptedUnder(opts, proofs);
|
|
3607
|
+
if (banked.some((id) => id !== void 0)) return replayRejected(banked, requestId);
|
|
3527
3608
|
return { kind: "rejected", code: "lock_not_exclusive", message: belowFloorMessage };
|
|
3528
3609
|
}
|
|
3529
3610
|
try {
|
|
@@ -3567,23 +3648,24 @@ async function acceptAccumulatorPayment(opts) {
|
|
|
3567
3648
|
lockPubkeyByIndex: matchedLockPubkeyByIndex,
|
|
3568
3649
|
mintUrl,
|
|
3569
3650
|
proofs,
|
|
3570
|
-
requestId
|
|
3651
|
+
requestId,
|
|
3571
3652
|
tExpireMsByIndex
|
|
3572
3653
|
};
|
|
3573
3654
|
try {
|
|
3574
3655
|
if (opts.disposable) {
|
|
3575
3656
|
const account = opts.withDisposableLedger;
|
|
3576
3657
|
if (!account) throw new Error("Disposable Cashu requires atomic credit accounting.");
|
|
3577
|
-
await opts.disposable.commit(
|
|
3658
|
+
await opts.disposable.commit(requestId, proofs, (ledger) => account(ledger, acceptedValue));
|
|
3578
3659
|
} else if (!opts.db) {
|
|
3579
3660
|
throw new Error("Cashu accumulator requires a storage backend.");
|
|
3580
|
-
} else
|
|
3581
|
-
const withCommitTx = opts.withCommitTx;
|
|
3661
|
+
} else {
|
|
3582
3662
|
const client = await opts.db.connect();
|
|
3583
3663
|
try {
|
|
3584
3664
|
await client.query("BEGIN");
|
|
3665
|
+
await client.query("SET TRANSACTION ISOLATION LEVEL READ COMMITTED");
|
|
3666
|
+
await claimAccumulatorRequestId(client, opts.dvmId, requestId);
|
|
3585
3667
|
await insertAccumulatorRows(opts.db, { ...insertArgs, tx: client });
|
|
3586
|
-
await withCommitTx(client, acceptedValue);
|
|
3668
|
+
await opts.withCommitTx?.(client, acceptedValue);
|
|
3587
3669
|
await client.query("COMMIT");
|
|
3588
3670
|
} catch (err) {
|
|
3589
3671
|
try {
|
|
@@ -3594,11 +3676,13 @@ async function acceptAccumulatorPayment(opts) {
|
|
|
3594
3676
|
} finally {
|
|
3595
3677
|
client.release();
|
|
3596
3678
|
}
|
|
3597
|
-
} else {
|
|
3598
|
-
await insertAccumulatorRows(opts.db, insertArgs);
|
|
3599
3679
|
}
|
|
3600
3680
|
} catch (err) {
|
|
3601
|
-
if (err instanceof AccumulatorReplayError)
|
|
3681
|
+
if (err instanceof AccumulatorReplayError) {
|
|
3682
|
+
const banked = await acceptedUnder(opts, proofs);
|
|
3683
|
+
if (banked.every((id) => id === void 0)) return requestIdReused(requestId);
|
|
3684
|
+
return replayRejected(banked, requestId);
|
|
3685
|
+
}
|
|
3602
3686
|
throw err;
|
|
3603
3687
|
}
|
|
3604
3688
|
return {
|
|
@@ -3607,14 +3691,33 @@ async function acceptAccumulatorPayment(opts) {
|
|
|
3607
3691
|
grossMsats: valuation.grossMsats,
|
|
3608
3692
|
inputFeeMsats: valuation.inputFeeMsats,
|
|
3609
3693
|
netMsats: valuation.netMsats,
|
|
3610
|
-
mintUrl
|
|
3694
|
+
mintUrl,
|
|
3695
|
+
requestId
|
|
3611
3696
|
};
|
|
3612
3697
|
}
|
|
3613
|
-
function
|
|
3698
|
+
async function acceptedUnder(opts, proofs) {
|
|
3699
|
+
const secrets = proofs.map((p) => p.secret);
|
|
3700
|
+
if (opts.disposable) return await opts.disposable.acceptedRequestIds(secrets);
|
|
3701
|
+
if (opts.db) return await acceptedRequestIds(opts.db, opts.dvmId, secrets);
|
|
3702
|
+
return secrets.map(() => void 0);
|
|
3703
|
+
}
|
|
3704
|
+
function requestIdReused(requestId) {
|
|
3705
|
+
return {
|
|
3706
|
+
kind: "rejected",
|
|
3707
|
+
code: "request_id_reused",
|
|
3708
|
+
requestId,
|
|
3709
|
+
message: "This request id already carries a different payment at this DVM; these proofs were not accepted."
|
|
3710
|
+
};
|
|
3711
|
+
}
|
|
3712
|
+
function replayRejected(accepted, requestId) {
|
|
3713
|
+
const [first] = accepted;
|
|
3714
|
+
const bound = first !== void 0 && accepted.every((id) => id === first);
|
|
3614
3715
|
return {
|
|
3615
3716
|
kind: "rejected",
|
|
3616
3717
|
code: "replay_rejected",
|
|
3617
|
-
message: "Proofs or request id already accepted at this DVM."
|
|
3718
|
+
message: "Proofs or request id already accepted at this DVM.",
|
|
3719
|
+
requestId,
|
|
3720
|
+
...bound && { acceptedRequestId: first }
|
|
3618
3721
|
};
|
|
3619
3722
|
}
|
|
3620
3723
|
function parseNut11LocktimeMs(secret) {
|
|
@@ -3850,7 +3953,7 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
3850
3953
|
}
|
|
3851
3954
|
};
|
|
3852
3955
|
}
|
|
3853
|
-
if (
|
|
3956
|
+
if (cashuAccumulatorReady(opts)) {
|
|
3854
3957
|
return verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx);
|
|
3855
3958
|
}
|
|
3856
3959
|
return {
|
|
@@ -4014,7 +4117,7 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
4014
4117
|
x402Requirements
|
|
4015
4118
|
});
|
|
4016
4119
|
}
|
|
4017
|
-
const { verifyX402Payment } = await import("./x402-
|
|
4120
|
+
const { verifyX402Payment } = await import("./x402-HVCUEWWU.js");
|
|
4018
4121
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
4019
4122
|
x402Payment,
|
|
4020
4123
|
x402Config,
|
|
@@ -4469,6 +4572,8 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
4469
4572
|
opts.fundOnly?.allowOneShotStablecoin,
|
|
4470
4573
|
opts.priceFiat
|
|
4471
4574
|
) : void 0;
|
|
4575
|
+
const lockPubkey = opts.lockPubkeys?.[0];
|
|
4576
|
+
const cashuRequest = opts.nut24 && opts.nut24.mints.length > 0 && !opts.fundOnly && cashuAccumulatorReady(opts) && lockPubkey ? cashuPaymentRequest({ requiredMsats, mints: opts.nut24.mints, lockPubkey }) : void 0;
|
|
4472
4577
|
return {
|
|
4473
4578
|
paidMsats: 0,
|
|
4474
4579
|
receivedProofs: [],
|
|
@@ -4479,6 +4584,7 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
4479
4584
|
...mints && { mints }
|
|
4480
4585
|
},
|
|
4481
4586
|
status: 402,
|
|
4587
|
+
...cashuRequest && { cashuPaymentRequest: cashuRequest },
|
|
4482
4588
|
...mppChallenges && { mppChallenges },
|
|
4483
4589
|
...x402Requirements && { x402Requirements },
|
|
4484
4590
|
...x402BatchRequirements && { x402V2Requirements: x402BatchRequirements }
|
|
@@ -4612,6 +4718,11 @@ var PAYMENT_ERROR_COPY = {
|
|
|
4612
4718
|
hint: "Request a fresh quote and pay again \u2014 the previous payment can't be reused.",
|
|
4613
4719
|
retryable: false
|
|
4614
4720
|
},
|
|
4721
|
+
payment_method_requires_signature: {
|
|
4722
|
+
display: "This service accepts unsigned requests only when they are paid with Cashu, so this payment was not applied to the job.",
|
|
4723
|
+
hint: "Pay with Cashu to call without signing, or sign the request (secp256k1 Schnorr) to use another payment method.",
|
|
4724
|
+
retryable: false
|
|
4725
|
+
},
|
|
4615
4726
|
x402_not_offered: {
|
|
4616
4727
|
display: "This service does not offer x402 payment for prices in its configured currency. Nothing was charged.",
|
|
4617
4728
|
hint: "Use one of the payment methods advertised by this service and submit the request again.",
|
|
@@ -4837,6 +4948,11 @@ var PAYMENT_ERROR_COPY = {
|
|
|
4837
4948
|
hint: "Include the X-Cashu-Request-Id header and pay again.",
|
|
4838
4949
|
retryable: false
|
|
4839
4950
|
},
|
|
4951
|
+
reserved_request_id: {
|
|
4952
|
+
display: "The payment's request identifier isn't allowed, so the payment wasn't processed. Nothing was charged.",
|
|
4953
|
+
hint: 'Send a fresh UUIDv4 as X-Cashu-Request-Id. Ids starting with "nut24-" are reserved for payments sent without one.',
|
|
4954
|
+
retryable: false
|
|
4955
|
+
},
|
|
4840
4956
|
missing_lock_pubkey: {
|
|
4841
4957
|
display: "This service can't accept the payment right now. Nothing was charged.",
|
|
4842
4958
|
hint: "The service is missing payment configuration; retrying won't help. Contact the service operator.",
|
|
@@ -4903,6 +5019,11 @@ var PAYMENT_ERROR_COPY = {
|
|
|
4903
5019
|
// agent could follow straight into paying twice for the same charge.
|
|
4904
5020
|
hint: "Don't re-send this payment \u2014 the proofs already landed under this request id. Only a genuinely new charge needs a fresh token and request id.",
|
|
4905
5021
|
retryable: false
|
|
5022
|
+
},
|
|
5023
|
+
request_id_reused: {
|
|
5024
|
+
display: "This payment was not accepted and nothing was charged.",
|
|
5025
|
+
hint: "Each X-Cashu-Request-Id belongs to the first payment made under it. Send these proofs again under a new request id.",
|
|
5026
|
+
retryable: false
|
|
4906
5027
|
}
|
|
4907
5028
|
};
|
|
4908
5029
|
function paymentErrorBody(code, opts) {
|
|
@@ -5044,7 +5165,7 @@ async function verifyIncomingPaymentInScope(body, opts, snapshot) {
|
|
|
5044
5165
|
snapshot
|
|
5045
5166
|
});
|
|
5046
5167
|
}
|
|
5047
|
-
const { verifyX402Payment } = await import("./x402-
|
|
5168
|
+
const { verifyX402Payment } = await import("./x402-HVCUEWWU.js");
|
|
5048
5169
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
5049
5170
|
body.content.x402_payment,
|
|
5050
5171
|
opts.x402Config,
|
|
@@ -5495,7 +5616,7 @@ async function processIncomingPaymentInScope(job, body, opts) {
|
|
|
5495
5616
|
try {
|
|
5496
5617
|
const requiredMsats = job.pendingPaymentMsats ?? 0;
|
|
5497
5618
|
const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
|
|
5498
|
-
const { verifyX402Payment } = await import("./x402-
|
|
5619
|
+
const { verifyX402Payment } = await import("./x402-HVCUEWWU.js");
|
|
5499
5620
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
5500
5621
|
body.content.x402_payment,
|
|
5501
5622
|
opts.x402Config,
|
|
@@ -5620,6 +5741,16 @@ function creditPendingPayment(job) {
|
|
|
5620
5741
|
job.pendingPaymentMsats = void 0;
|
|
5621
5742
|
}
|
|
5622
5743
|
}
|
|
5744
|
+
function cashuAccumulatorReady(opts) {
|
|
5745
|
+
return opts.cashuMode === "p2pk-accumulator" && Boolean(opts.accumulatorDb || opts.disposableCashu) && Boolean(opts.dvmId) && (opts.lockPubkeys?.length ?? 0) > 0;
|
|
5746
|
+
}
|
|
5747
|
+
var NUT24_PAYER_FIXABLE = /* @__PURE__ */ new Set([
|
|
5748
|
+
"invalid_token",
|
|
5749
|
+
"not_p2pk_locked",
|
|
5750
|
+
"wrong_lock_pubkey",
|
|
5751
|
+
"lock_not_exclusive",
|
|
5752
|
+
"payment_insufficient"
|
|
5753
|
+
]);
|
|
5623
5754
|
async function verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx) {
|
|
5624
5755
|
const { cashuToken, accumulatorDb, dvmId, lockPubkeys, mintHealthTracker } = opts;
|
|
5625
5756
|
if (!cashuToken || !accumulatorDb && !opts.disposableCashu || !dvmId || !lockPubkeys || lockPubkeys.length === 0) {
|
|
@@ -5668,7 +5799,13 @@ async function verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx) {
|
|
|
5668
5799
|
};
|
|
5669
5800
|
}
|
|
5670
5801
|
let credited;
|
|
5671
|
-
const
|
|
5802
|
+
const headerless = !opts.requestId && opts.nut24 !== void 0;
|
|
5803
|
+
const previousRequired = headerless ? opts.nut24?.previousRequiredMsats : void 0;
|
|
5804
|
+
const requiredFor = (paidMsats) => requiredMsats !== void 0 && paidMsats < requiredMsats && previousRequired !== void 0 && paidMsats >= previousRequired ? previousRequired : requiredMsats;
|
|
5805
|
+
const held = (ctx, paidMsats) => ({
|
|
5806
|
+
...ctx,
|
|
5807
|
+
requiredMsats: requiredFor(paidMsats) ?? ctx.requiredMsats
|
|
5808
|
+
});
|
|
5672
5809
|
const signedFund = ledgerCtx?.creditEnvelope?.fund;
|
|
5673
5810
|
const beforeCommit = ledgerCtx && signedFund ? (accepted) => {
|
|
5674
5811
|
const expected = fundedMicroFor(
|
|
@@ -5680,12 +5817,12 @@ async function verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx) {
|
|
|
5680
5817
|
throw new CashuFundingAmountMismatchError(signedFund.amountMicro, expected);
|
|
5681
5818
|
}
|
|
5682
5819
|
} : void 0;
|
|
5683
|
-
const withCommitTx = ledgerCtx
|
|
5820
|
+
const withCommitTx = ledgerCtx ? async (tx, accepted) => {
|
|
5684
5821
|
credited = await fundAndDraw(
|
|
5685
|
-
ledgerCtx,
|
|
5822
|
+
held(ledgerCtx, accepted.paidMsats),
|
|
5686
5823
|
{
|
|
5687
5824
|
rail: "cashu",
|
|
5688
|
-
paymentId: requestId,
|
|
5825
|
+
paymentId: accepted.requestId,
|
|
5689
5826
|
paidMsats: accepted.paidMsats,
|
|
5690
5827
|
grossPaidMsats: accepted.grossMsats,
|
|
5691
5828
|
cashuInputFeeMsats: accepted.inputFeeMsats,
|
|
@@ -5699,13 +5836,14 @@ async function verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx) {
|
|
|
5699
5836
|
result = await acceptAccumulatorPayment({
|
|
5700
5837
|
cashuToken,
|
|
5701
5838
|
requestId: opts.requestId,
|
|
5839
|
+
deriveRequestId: headerless,
|
|
5702
5840
|
mints,
|
|
5703
5841
|
db: accumulatorDb,
|
|
5704
5842
|
disposable: opts.disposableCashu,
|
|
5705
|
-
withDisposableLedger: ledgerCtx
|
|
5706
|
-
credited = await fundAndDraw({ ...ledgerCtx, ledger }, {
|
|
5843
|
+
withDisposableLedger: ledgerCtx ? async (ledger, accepted) => {
|
|
5844
|
+
credited = await fundAndDraw({ ...held(ledgerCtx, accepted.paidMsats), ledger }, {
|
|
5707
5845
|
rail: "cashu",
|
|
5708
|
-
paymentId: requestId,
|
|
5846
|
+
paymentId: accepted.requestId,
|
|
5709
5847
|
paidMsats: accepted.paidMsats,
|
|
5710
5848
|
grossPaidMsats: accepted.grossMsats,
|
|
5711
5849
|
cashuInputFeeMsats: accepted.inputFeeMsats,
|
|
@@ -5729,24 +5867,35 @@ async function verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx) {
|
|
|
5729
5867
|
throw err;
|
|
5730
5868
|
}
|
|
5731
5869
|
if (result.kind === "rejected") {
|
|
5732
|
-
const status = result.code === "replay_rejected" ? 409 : 402;
|
|
5870
|
+
const status = result.code === "replay_rejected" || result.code === "request_id_reused" ? 409 : result.code === "reserved_request_id" || headerless && NUT24_PAYER_FIXABLE.has(result.code) ? 400 : 402;
|
|
5871
|
+
const requestId = result.requestId;
|
|
5733
5872
|
return {
|
|
5734
5873
|
paidMsats: 0,
|
|
5735
5874
|
receivedProofs: [],
|
|
5736
5875
|
error: {
|
|
5737
|
-
body: paymentErrorBody(result.code, {
|
|
5876
|
+
body: paymentErrorBody(result.code, {
|
|
5877
|
+
message: result.message,
|
|
5878
|
+
// Without a request id the proof set is the payment's identity, so
|
|
5879
|
+
// only these exact proofs with the original body recover its job.
|
|
5880
|
+
...headerless && result.code === "replay_rejected" && {
|
|
5881
|
+
hint: "These proofs already paid for an earlier request. Resend them with that request's exact body to fetch its job; a new request needs new proofs."
|
|
5882
|
+
},
|
|
5883
|
+
extra: { mints }
|
|
5884
|
+
}),
|
|
5738
5885
|
status,
|
|
5739
|
-
// The
|
|
5740
|
-
//
|
|
5741
|
-
//
|
|
5742
|
-
|
|
5886
|
+
// The request id is also the funding id a mid-job top-up committed
|
|
5887
|
+
// under and the job's payment reference, so the route can return the
|
|
5888
|
+
// original evidence beside the 409. It is passed on only when every
|
|
5889
|
+
// presented proof was accepted under this same request id.
|
|
5890
|
+
...requestId && result.acceptedRequestId === requestId && { replayPaymentId: requestId }
|
|
5743
5891
|
}
|
|
5744
5892
|
};
|
|
5745
5893
|
}
|
|
5746
5894
|
if (credited?.drawRefusal) {
|
|
5747
5895
|
return creditLedgerErrorResult(credited.drawRefusal, void 0, credited.deposit);
|
|
5748
5896
|
}
|
|
5749
|
-
|
|
5897
|
+
const heldRequired = requiredFor(result.paidMsats);
|
|
5898
|
+
if (heldRequired && result.paidMsats < heldRequired && !ledgerCtx?.fundOnly && !ledgerCtx?.creditEnvelope) {
|
|
5750
5899
|
let forfeit;
|
|
5751
5900
|
if (credited?.draw && ledgerCtx && !ledgerCtx.midJob) {
|
|
5752
5901
|
const drawId = credited.draw.drawId;
|
|
@@ -5768,36 +5917,39 @@ async function verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx) {
|
|
|
5768
5917
|
});
|
|
5769
5918
|
}
|
|
5770
5919
|
}
|
|
5771
|
-
const
|
|
5920
|
+
const held2 = ledgerCtx?.midJob ? credited : void 0;
|
|
5772
5921
|
return {
|
|
5773
5922
|
paidMsats: 0,
|
|
5774
5923
|
receivedProofs: [],
|
|
5775
5924
|
error: {
|
|
5776
5925
|
body: paymentErrorBody("payment_insufficient", {
|
|
5777
5926
|
message: `Payment of ${result.paidMsats} msats is short of the ${requiredMsats} msats required.`,
|
|
5778
|
-
...
|
|
5927
|
+
...held2 && {
|
|
5779
5928
|
// Per-code copy can't say where the money went, and this is the one
|
|
5780
5929
|
// site where that is the caller's next action.
|
|
5781
|
-
hint: `The ${result.paidMsats} msats already sent are held on credit ${
|
|
5930
|
+
hint: `The ${result.paidMsats} msats already sent are held on credit ${held2.creditId} and do not reduce what is owed \u2014 retry with a single payment of required_msats, or reclaim the held balance with op "drain" at POST /v1/credit.`
|
|
5931
|
+
},
|
|
5932
|
+
...!held2 && headerless && {
|
|
5933
|
+
hint: "The proofs already sent are kept and do not count toward this request. Pay again with new proofs worth required_msats after the mint's input fee."
|
|
5782
5934
|
},
|
|
5783
5935
|
extra: {
|
|
5784
5936
|
required_msats: requiredMsats,
|
|
5785
5937
|
received_msats: result.paidMsats,
|
|
5786
5938
|
mints,
|
|
5787
|
-
...
|
|
5788
|
-
credit_id:
|
|
5789
|
-
credited_micro:
|
|
5790
|
-
credit_currency:
|
|
5939
|
+
...held2 && {
|
|
5940
|
+
credit_id: held2.creditId,
|
|
5941
|
+
credited_micro: held2.deposit.amountMicro,
|
|
5942
|
+
credit_currency: held2.deposit.currency
|
|
5791
5943
|
}
|
|
5792
5944
|
}
|
|
5793
5945
|
}),
|
|
5794
|
-
status: 402,
|
|
5946
|
+
status: headerless ? 400 : 402,
|
|
5795
5947
|
forfeit,
|
|
5796
5948
|
// Report the deposit on the failure path too, or the platform never
|
|
5797
5949
|
// learns about a liability it is carrying. Mutually exclusive with
|
|
5798
5950
|
// `forfeit` by construction: one is money still owed, the other is
|
|
5799
5951
|
// money nothing is owed against.
|
|
5800
|
-
...
|
|
5952
|
+
...held2 && { funding: held2.deposit }
|
|
5801
5953
|
}
|
|
5802
5954
|
};
|
|
5803
5955
|
}
|
|
@@ -5807,13 +5959,11 @@ async function verifyAccumulatorReceipt(opts, mints, requiredMsats, ledgerCtx) {
|
|
|
5807
5959
|
paymentMint: result.mintUrl,
|
|
5808
5960
|
paymentRail: "cashu",
|
|
5809
5961
|
receivedProofs: [],
|
|
5810
|
-
//
|
|
5811
|
-
//
|
|
5812
|
-
//
|
|
5813
|
-
//
|
|
5814
|
-
|
|
5815
|
-
// it serves as a stable id even though it isn't an on-chain hash.
|
|
5816
|
-
paymentTxHash: opts.requestId,
|
|
5962
|
+
// The request id the proofs were banked under, supplied or derived, is
|
|
5963
|
+
// the per-call settlement reference for revenue_events.tx_hash. Unique
|
|
5964
|
+
// per (dvm_id, request_id) by the wallet_accumulator UNIQUE constraint,
|
|
5965
|
+
// so it serves as a stable id even though it isn't an on-chain hash.
|
|
5966
|
+
paymentTxHash: result.requestId,
|
|
5817
5967
|
cashuFlow: "p2pk_accumulator"
|
|
5818
5968
|
},
|
|
5819
5969
|
ledgerCtx,
|
|
@@ -5889,7 +6039,7 @@ async function resolveTopUpLedgerContext(opts, snapshot, binding) {
|
|
|
5889
6039
|
draw_id: snapshot.drawId,
|
|
5890
6040
|
...extra,
|
|
5891
6041
|
...typeof opts.jobId === "string" && {
|
|
5892
|
-
job_id_hash:
|
|
6042
|
+
job_id_hash: createHash5("sha256").update(opts.jobId, "utf8").digest("hex")
|
|
5893
6043
|
}
|
|
5894
6044
|
}
|
|
5895
6045
|
);
|
|
@@ -9592,7 +9742,7 @@ async function handle(c, opts, action) {
|
|
|
9592
9742
|
}
|
|
9593
9743
|
|
|
9594
9744
|
// src/sdk/server/x402-exact-settlement.ts
|
|
9595
|
-
import { createHash as
|
|
9745
|
+
import { createHash as createHash6 } from "crypto";
|
|
9596
9746
|
var X402ExactSettlementServer = class {
|
|
9597
9747
|
constructor(opts) {
|
|
9598
9748
|
this.opts = opts;
|
|
@@ -9918,7 +10068,7 @@ function settlementMayHaveMoved(response) {
|
|
|
9918
10068
|
return reason.includes("authorization_already_used") || reason.includes("authorization already used") || /facilitator_status_5\d\d/.test(reason);
|
|
9919
10069
|
}
|
|
9920
10070
|
function hash(parts) {
|
|
9921
|
-
return
|
|
10071
|
+
return createHash6("sha256").update(JSON.stringify(parts)).digest("hex");
|
|
9922
10072
|
}
|
|
9923
10073
|
function safeError(err) {
|
|
9924
10074
|
if (err instanceof Error) return err.name;
|
|
@@ -9926,7 +10076,7 @@ function safeError(err) {
|
|
|
9926
10076
|
}
|
|
9927
10077
|
|
|
9928
10078
|
// src/sdk/server/hosting-settlement-report-obligations.ts
|
|
9929
|
-
import { createHash as
|
|
10079
|
+
import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
|
|
9930
10080
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
9931
10081
|
import { BATCH_SETTLEMENT_ADDRESS as BATCH_SETTLEMENT_ADDRESS3 } from "@x402/evm";
|
|
9932
10082
|
import { computeChannelId as computeChannelId2 } from "@x402/evm/batch-settlement/client";
|
|
@@ -9999,7 +10149,7 @@ var TEMPO_CLOSED_EVENT = TempoSession.Precompile.escrowAbi.find(
|
|
|
9999
10149
|
(item) => item.type === "event" && item.name === "ChannelClosed"
|
|
10000
10150
|
);
|
|
10001
10151
|
function hash2(value) {
|
|
10002
|
-
return
|
|
10152
|
+
return createHash7("sha256").update(JSON.stringify(value)).digest("hex");
|
|
10003
10153
|
}
|
|
10004
10154
|
function hex(value, bytes) {
|
|
10005
10155
|
return typeof value === "string" && new RegExp(`^0x[0-9a-fA-F]{${bytes * 2}}$`).test(value);
|
|
@@ -11387,7 +11537,7 @@ var HostingCleanupFence = class {
|
|
|
11387
11537
|
};
|
|
11388
11538
|
|
|
11389
11539
|
// src/sdk/server/hosting-channel-evidence.ts
|
|
11390
|
-
import { createHash as
|
|
11540
|
+
import { createHash as createHash8 } from "crypto";
|
|
11391
11541
|
import { Session as TempoSession2 } from "mppx/tempo";
|
|
11392
11542
|
import { createPublicClient as createPublicClient5, http as http5 } from "viem";
|
|
11393
11543
|
import { BATCH_SETTLEMENT_ADDRESS as BATCH_SETTLEMENT_ADDRESS4 } from "@x402/evm";
|
|
@@ -11438,7 +11588,7 @@ async function readHostedChannelSnapshot(query) {
|
|
|
11438
11588
|
};
|
|
11439
11589
|
const x402HistoryComplete = await history(names[6]);
|
|
11440
11590
|
const tempoHistoryComplete = await history(names[7]);
|
|
11441
|
-
const digest =
|
|
11591
|
+
const digest = createHash8("sha256").update(JSON.stringify({
|
|
11442
11592
|
present: [...exists].sort(),
|
|
11443
11593
|
x402,
|
|
11444
11594
|
x402Tombstones,
|
|
@@ -12588,9 +12738,9 @@ import { AsyncLocalStorage } from "async_hooks";
|
|
|
12588
12738
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
12589
12739
|
|
|
12590
12740
|
// src/sdk/server/instrumented-kv.ts
|
|
12591
|
-
import { createHash as
|
|
12741
|
+
import { createHash as createHash9 } from "crypto";
|
|
12592
12742
|
function hashKey(key) {
|
|
12593
|
-
return
|
|
12743
|
+
return createHash9("sha256").update(key).digest("hex").slice(0, 16);
|
|
12594
12744
|
}
|
|
12595
12745
|
function instrumentKVStore(inner) {
|
|
12596
12746
|
return {
|
|
@@ -12904,7 +13054,7 @@ function buildContext(job, opts) {
|
|
|
12904
13054
|
let x402Nonce;
|
|
12905
13055
|
let x402AmountUsdcMicro;
|
|
12906
13056
|
const hasExplicitX402 = Boolean(payOpts?.x402);
|
|
12907
|
-
if ((opts.pricingCurrency ?? "usd") === "usd") {
|
|
13057
|
+
if (!opts.cashuOnly && (opts.pricingCurrency ?? "usd") === "usd") {
|
|
12908
13058
|
if (payOpts?.x402) {
|
|
12909
13059
|
paymentRequestContent.x402 = payOpts.x402;
|
|
12910
13060
|
} else if (opts.paymentMethods?.includes("x402") && opts.x402 && (opts.x402FacilitatorHealth?.support().available ?? true)) {
|
|
@@ -12943,7 +13093,8 @@ function buildContext(job, opts) {
|
|
|
12943
13093
|
job.pendingX402Nonce = x402Nonce;
|
|
12944
13094
|
job.pendingX402AmountUsdcMicro = x402AmountUsdcMicro;
|
|
12945
13095
|
let mppChallengeIds;
|
|
12946
|
-
if (
|
|
13096
|
+
if (opts.cashuOnly) {
|
|
13097
|
+
} else if (payOpts?.mpp) {
|
|
12947
13098
|
const challenges = payOpts.mpp.challenges.filter((c) => c.intent !== "session");
|
|
12948
13099
|
if (challenges.length > 0) {
|
|
12949
13100
|
paymentRequestContent.tempo = { challenges };
|
|
@@ -13351,6 +13502,39 @@ function resultHashFor(record) {
|
|
|
13351
13502
|
return computeResultHash(summary, artifacts);
|
|
13352
13503
|
}
|
|
13353
13504
|
|
|
13505
|
+
// src/sdk/server/unsigned-request.ts
|
|
13506
|
+
function takesUnsignedPath(auth, body) {
|
|
13507
|
+
if (!auth?.allowUnsignedPaid) return false;
|
|
13508
|
+
const raw = signedRequestInput(body);
|
|
13509
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return true;
|
|
13510
|
+
return !SIGNED_ENVELOPE_FIELDS.some((field) => field in raw);
|
|
13511
|
+
}
|
|
13512
|
+
function carriesCreditFields(raw) {
|
|
13513
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
13514
|
+
return CREDIT_ENVELOPE_KEYS.some((field) => field in raw);
|
|
13515
|
+
}
|
|
13516
|
+
function unsignedInputSchema(schema) {
|
|
13517
|
+
if (narrowed.has(schema)) return narrowed.get(schema);
|
|
13518
|
+
const result = narrow(schema);
|
|
13519
|
+
narrowed.set(schema, result);
|
|
13520
|
+
return result;
|
|
13521
|
+
}
|
|
13522
|
+
var narrowed = /* @__PURE__ */ new WeakMap();
|
|
13523
|
+
function narrow(schema) {
|
|
13524
|
+
const candidate = schema;
|
|
13525
|
+
const def = candidate._zod?.def;
|
|
13526
|
+
if (def?.type !== "object" || typeof candidate.clone !== "function" || candidate.shape === null || typeof candidate.shape !== "object") {
|
|
13527
|
+
return void 0;
|
|
13528
|
+
}
|
|
13529
|
+
const shape = { ...candidate.shape };
|
|
13530
|
+
for (const field of SIGNED_ENVELOPE_FIELDS) delete shape[field];
|
|
13531
|
+
try {
|
|
13532
|
+
return candidate.clone({ ...def, shape });
|
|
13533
|
+
} catch {
|
|
13534
|
+
return void 0;
|
|
13535
|
+
}
|
|
13536
|
+
}
|
|
13537
|
+
|
|
13354
13538
|
// src/lib/cashu/mint-info.ts
|
|
13355
13539
|
async function getKeysetFinalExpiry(mintUrl, keysetId) {
|
|
13356
13540
|
try {
|
|
@@ -13814,11 +13998,12 @@ var JobManager = class {
|
|
|
13814
13998
|
* `"$X.XX"` is parsed as USD and converted via the SDK's shared fx fetcher.
|
|
13815
13999
|
* Returns `undefined` for dynamic-priced capabilities (those that declare
|
|
13816
14000
|
* `onQuote`) — the caller falls back to `computeDynamicPrice` in that path.
|
|
14001
|
+
* A caller that already holds the snapshot it prices at passes it as `fx`.
|
|
13817
14002
|
*/
|
|
13818
|
-
async currentPriceMsats(capability) {
|
|
14003
|
+
async currentPriceMsats(capability, fx) {
|
|
13819
14004
|
const cap = this.requireCapability(capability);
|
|
13820
14005
|
if (cap.price === void 0) return void 0;
|
|
13821
|
-
return resolveStaticPriceMsats(cap.price, this.opts.fxFetcher);
|
|
14006
|
+
return resolveStaticPriceMsats(cap.price, fx ?? await this.opts.fxFetcher.fetch());
|
|
13822
14007
|
}
|
|
13823
14008
|
/**
|
|
13824
14009
|
* Translate a capability's static `price` into the fiat envelope used by
|
|
@@ -13851,12 +14036,16 @@ var JobManager = class {
|
|
|
13851
14036
|
* explicit draw as an unknown key, before the envelope was even extracted.
|
|
13852
14037
|
* The persisted `record.input` the reactivation path re-reads is the
|
|
13853
14038
|
* pre-Zod wire form, so it comes through the second branch carrying them too.
|
|
14039
|
+
*
|
|
14040
|
+
* `unsigned` validates against the schema without its envelope fields; pass
|
|
14041
|
+
* it only when {@link unsignedPaidInput} accepted the same body.
|
|
13854
14042
|
*/
|
|
13855
|
-
parseInput(body, capability) {
|
|
14043
|
+
parseInput(body, capability, unsigned2 = false) {
|
|
13856
14044
|
const cap = this.requireCapability(capability);
|
|
13857
14045
|
const rawSchema = cap.input;
|
|
13858
14046
|
if (!rawSchema || !isZodSchema(rawSchema)) return body.input ?? "";
|
|
13859
|
-
const schema = rawSchema;
|
|
14047
|
+
const schema = unsigned2 ? unsignedInputSchema(rawSchema) : rawSchema;
|
|
14048
|
+
if (!schema) throw new Error(`capability "${capability}" cannot validate unsigned input`);
|
|
13860
14049
|
if (body.data !== void 0) {
|
|
13861
14050
|
return schema.parse(stripProtocolEnvelope(schema, body.data));
|
|
13862
14051
|
}
|
|
@@ -13866,6 +14055,16 @@ var JobManager = class {
|
|
|
13866
14055
|
}
|
|
13867
14056
|
throw new MissingStructuredInputError();
|
|
13868
14057
|
}
|
|
14058
|
+
/**
|
|
14059
|
+
* Whether this body takes the unsigned paid path: the auth scheme allows it,
|
|
14060
|
+
* the raw input carries no envelope field, and the capability schema can be
|
|
14061
|
+
* narrowed to exclude the envelope. Otherwise the signed path applies.
|
|
14062
|
+
*/
|
|
14063
|
+
unsignedPaidInput(body, capability) {
|
|
14064
|
+
if (!takesUnsignedPath(this.descriptor.auth, body)) return false;
|
|
14065
|
+
const rawSchema = this.requireCapability(capability).input;
|
|
14066
|
+
return isZodSchema(rawSchema) && unsignedInputSchema(rawSchema) !== void 0;
|
|
14067
|
+
}
|
|
13869
14068
|
/**
|
|
13870
14069
|
* Look up the per-capability descriptor by name. Throws when the
|
|
13871
14070
|
* name doesn't exist — the route layer validates body.capability first, so
|
|
@@ -15352,8 +15551,9 @@ var JobManager = class {
|
|
|
15352
15551
|
* it re-verified clean.
|
|
15353
15552
|
*/
|
|
15354
15553
|
reactivateJob(record) {
|
|
15355
|
-
const
|
|
15356
|
-
|
|
15554
|
+
const unsigned2 = record.authRequestPath === void 0 && record.requesterPubkey === void 0 && this.unsignedPaidInput({ input: record.input }, record.capability);
|
|
15555
|
+
const parsedInput = this.parseInput({ input: record.input }, record.capability, unsigned2);
|
|
15556
|
+
if (this.descriptor.auth && !unsigned2) {
|
|
15357
15557
|
const cap = this.requireCapability(record.capability);
|
|
15358
15558
|
if (!cap.input || !isZodSchema(cap.input)) {
|
|
15359
15559
|
throw new ReactivationAuthSchemaError(record.id, record.capability);
|
|
@@ -15897,6 +16097,7 @@ var JobManager = class {
|
|
|
15897
16097
|
store: this.opts.store,
|
|
15898
16098
|
env: this.opts.env,
|
|
15899
16099
|
paymentMethods: this.opts.paymentMethods,
|
|
16100
|
+
cashuOnly: Boolean(this.descriptor.auth?.allowUnsignedPaid) && job.requesterPubkey === void 0,
|
|
15900
16101
|
x402: this.opts.x402,
|
|
15901
16102
|
x402FacilitatorHealth: this.opts.x402FacilitatorHealth,
|
|
15902
16103
|
mpp: this.opts.mpp,
|
|
@@ -16701,9 +16902,8 @@ function unappliedCopy(reason, creditId) {
|
|
|
16701
16902
|
}
|
|
16702
16903
|
}[reason];
|
|
16703
16904
|
}
|
|
16704
|
-
|
|
16905
|
+
function resolveStaticPriceMsats(price, fx) {
|
|
16705
16906
|
const usd = parseUsdPrice(price, "price");
|
|
16706
|
-
const fx = await fxFetcher.fetch();
|
|
16707
16907
|
return fiatToSatsCeil(usd, fxRateFor(fx, "usd")) * 1e3;
|
|
16708
16908
|
}
|
|
16709
16909
|
function deriveAuthFromParsedInput(descriptor, parsedInput) {
|
|
@@ -17769,7 +17969,7 @@ function withWallClockDeadline(promise, timeoutMs) {
|
|
|
17769
17969
|
}
|
|
17770
17970
|
|
|
17771
17971
|
// src/sdk/server/balance-payment.ts
|
|
17772
|
-
import { createHash as
|
|
17972
|
+
import { createHash as createHash10 } from "crypto";
|
|
17773
17973
|
import { z as z2 } from "zod";
|
|
17774
17974
|
var BALANCE_PAYMENT_SCHEMA = z2.object({
|
|
17775
17975
|
credit_id: z2.string().min(1).max(256),
|
|
@@ -17799,7 +17999,7 @@ async function commitBalancePayment(args) {
|
|
|
17799
17999
|
args.auth.recheckSignature(BALANCE_PAYMENT_SCHEMA, args.raw, args.domain);
|
|
17800
18000
|
const auth = BALANCE_PAYMENT_SCHEMA.parse(args.raw);
|
|
17801
18001
|
const { pubkey, credit_id, draw_id, payment_id, request_seq, amount_micro, currency } = auth;
|
|
17802
|
-
const fingerprint =
|
|
18002
|
+
const fingerprint = createHash10("sha256").update(JSON.stringify([
|
|
17803
18003
|
args.domain,
|
|
17804
18004
|
args.jobId,
|
|
17805
18005
|
pubkey,
|
|
@@ -17923,7 +18123,7 @@ async function commitBalancePayment(args) {
|
|
|
17923
18123
|
}
|
|
17924
18124
|
|
|
17925
18125
|
// src/sdk/server/app.ts
|
|
17926
|
-
import { createHash as
|
|
18126
|
+
import { createHash as createHash12, randomBytes as randomBytes5, randomUUID as randomUUID6 } from "crypto";
|
|
17927
18127
|
import { Hono } from "hono";
|
|
17928
18128
|
import { getCookie } from "hono/cookie";
|
|
17929
18129
|
import { cors } from "hono/cors";
|
|
@@ -20974,7 +21174,7 @@ initSchemaForm();
|
|
|
20974
21174
|
}
|
|
20975
21175
|
|
|
20976
21176
|
// src/sdk/server/request-fingerprint.ts
|
|
20977
|
-
import { createHash as
|
|
21177
|
+
import { createHash as createHash11 } from "crypto";
|
|
20978
21178
|
function requestFingerprint(req, opts) {
|
|
20979
21179
|
const canonical = canonicalize({
|
|
20980
21180
|
capability: req.capability,
|
|
@@ -20982,7 +21182,7 @@ function requestFingerprint(req, opts) {
|
|
|
20982
21182
|
params: req.params ?? {},
|
|
20983
21183
|
data: opts.stripAuthEnvelope ? stripEnvelope(req.data) : req.data
|
|
20984
21184
|
});
|
|
20985
|
-
return
|
|
21185
|
+
return createHash11("sha256").update(canonical).digest("hex");
|
|
20986
21186
|
}
|
|
20987
21187
|
var ENVELOPE_KEYS = /* @__PURE__ */ new Set(["pubkey", "signature", "timestamp", "nonce", "auth_statement"]);
|
|
20988
21188
|
function stripEnvelope(data) {
|
|
@@ -21105,7 +21305,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
21105
21305
|
}
|
|
21106
21306
|
}
|
|
21107
21307
|
if (!opts.onJobCompleted && platformToken && platformUrl && dvmId && opts.db) {
|
|
21108
|
-
const { RevenueReporter } = await import("./revenue-reporter-
|
|
21308
|
+
const { RevenueReporter } = await import("./revenue-reporter-6XARUEG6.js");
|
|
21109
21309
|
const reporter = new RevenueReporter(
|
|
21110
21310
|
opts.db,
|
|
21111
21311
|
platformUrl,
|
|
@@ -21115,7 +21315,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
21115
21315
|
revenueReporter = reporter;
|
|
21116
21316
|
await reporter.init();
|
|
21117
21317
|
reporter.startRetryLoop();
|
|
21118
|
-
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-
|
|
21318
|
+
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-5QAHCYIO.js");
|
|
21119
21319
|
payoutReporter = new PayoutReporter({
|
|
21120
21320
|
dvmId,
|
|
21121
21321
|
db: opts.db,
|
|
@@ -21396,7 +21596,9 @@ var DVMServer = class {
|
|
|
21396
21596
|
this.consumedCredentialStore = opts.consumedCredentialStore ?? new MemoryConsumedCredentialStore();
|
|
21397
21597
|
this.adminCashuNonceStore = opts.adminCashuNonceStore ?? createAdminCashuNonceStore();
|
|
21398
21598
|
const fxEnv = opts.env;
|
|
21399
|
-
this.fxFetcher =
|
|
21599
|
+
this.fxFetcher = withFxHistory(
|
|
21600
|
+
opts.fxFetcher ?? createFxFetcher({ source: resolveFxSourceFromEnv(fxEnv) })
|
|
21601
|
+
);
|
|
21400
21602
|
const fxCurrencies = this.fxFetcher.supportedCurrencies();
|
|
21401
21603
|
if (!fxCurrencies.includes(this.pricingCurrency)) {
|
|
21402
21604
|
throw new Error(
|
|
@@ -21505,6 +21707,15 @@ var DVMServer = class {
|
|
|
21505
21707
|
this.app = new Hono();
|
|
21506
21708
|
try {
|
|
21507
21709
|
this.registerRoutes();
|
|
21710
|
+
if (opts.mints?.length && !this.resolvePaymentMethods().includes("cashu")) {
|
|
21711
|
+
diagnosticConsole.warn({
|
|
21712
|
+
event: "cashu_not_advertised",
|
|
21713
|
+
cashu_explicitly_excluded: opts.paymentMethods !== void 0 && !opts.paymentMethods.includes("cashu"),
|
|
21714
|
+
cashu_mode_missing: opts.cashuMode !== "p2pk-accumulator",
|
|
21715
|
+
cashu_lock_pubkey_missing: !opts.lockPubkey,
|
|
21716
|
+
cashu_store_missing: !opts.db && !opts.disposableCashu
|
|
21717
|
+
});
|
|
21718
|
+
}
|
|
21508
21719
|
if (opts.hostingControlInstance) {
|
|
21509
21720
|
this.hostingSweepTimer = setInterval(() => {
|
|
21510
21721
|
void this.sweepHostingDeadline().catch((error) => {
|
|
@@ -21714,7 +21925,7 @@ var DVMServer = class {
|
|
|
21714
21925
|
})
|
|
21715
21926
|
);
|
|
21716
21927
|
if (this.opts.devMode) {
|
|
21717
|
-
this.app.use("*", cors());
|
|
21928
|
+
this.app.use("*", cors({ exposeHeaders: ["X-Cashu"] }));
|
|
21718
21929
|
this.app.get("/_dev", (c) => c.html(devPageHtml(this.descriptor.name)));
|
|
21719
21930
|
this.app.all("/_proxy/*", (c) => this.handleProxy(c));
|
|
21720
21931
|
}
|
|
@@ -22028,7 +22239,7 @@ var DVMServer = class {
|
|
|
22028
22239
|
const dvmId = this.opts.dvmId ?? `dev:${this.descriptor.name}`;
|
|
22029
22240
|
return {
|
|
22030
22241
|
dvm_id: dvmId,
|
|
22031
|
-
builder_pubkey:
|
|
22242
|
+
builder_pubkey: createHash12("sha256").update(`dvmkit-dev:${dvmId}`).digest("hex")
|
|
22032
22243
|
};
|
|
22033
22244
|
}
|
|
22034
22245
|
throw new AuthAudienceError();
|
|
@@ -22126,7 +22337,7 @@ var DVMServer = class {
|
|
|
22126
22337
|
const methods = this.resolvePaymentMethods().filter(
|
|
22127
22338
|
(method) => method !== "tempo" || creditMpp
|
|
22128
22339
|
);
|
|
22129
|
-
if (this.x402CurrencySupported() && this.x402BatchAvailable() && !methods.includes("x402")) {
|
|
22340
|
+
if ((this.opts.paymentMethods === void 0 || this.opts.paymentMethods.includes("x402")) && this.x402CurrencySupported() && this.x402BatchAvailable() && !methods.includes("x402")) {
|
|
22130
22341
|
methods.push("x402");
|
|
22131
22342
|
}
|
|
22132
22343
|
if (this.opts.lightningReceive?.available()) methods.push("lightning");
|
|
@@ -22149,7 +22360,9 @@ var DVMServer = class {
|
|
|
22149
22360
|
* distinction, and a reason it can relay.
|
|
22150
22361
|
*/
|
|
22151
22362
|
creditMppSplit() {
|
|
22152
|
-
if (!this.opts.mpp)
|
|
22363
|
+
if (!this.opts.mpp || !this.resolvePaymentMethods().includes("tempo")) {
|
|
22364
|
+
return { offered: [], withheld: [] };
|
|
22365
|
+
}
|
|
22153
22366
|
const configured = advertisedMethods(this.opts.mpp).filter(
|
|
22154
22367
|
(method) => method.intent === "charge" || method.intent === "session"
|
|
22155
22368
|
).sort(
|
|
@@ -22381,7 +22594,7 @@ var DVMServer = class {
|
|
|
22381
22594
|
const paymentAuthorization = ctx.req.header("Authorization");
|
|
22382
22595
|
const mppArtifact = paymentAuthorization ? (await import("mppx")).Credential.extractPaymentScheme(paymentAuthorization) : void 0;
|
|
22383
22596
|
const attachedPayment = ctx.req.header("X-Cashu") ?? ctx.req.header("PAYMENT-SIGNATURE") ?? ctx.req.header("X-PAYMENT") ?? mppArtifact;
|
|
22384
|
-
const paymentArtifactHash = attachedPayment ?
|
|
22597
|
+
const paymentArtifactHash = attachedPayment ? createHash12("sha256").update(attachedPayment).digest("hex") : void 0;
|
|
22385
22598
|
hostingFundingArtifactHash = paymentArtifactHash;
|
|
22386
22599
|
if (!await control.admit(admissionId, workId, {
|
|
22387
22600
|
creditId,
|
|
@@ -22481,7 +22694,7 @@ var DVMServer = class {
|
|
|
22481
22694
|
name: this.descriptor.name,
|
|
22482
22695
|
description: this.descriptor.description || void 0,
|
|
22483
22696
|
tags: this.descriptor.tags,
|
|
22484
|
-
auth: this.descriptor.auth ? [this.descriptor.auth.
|
|
22697
|
+
auth: !this.descriptor.auth ? ["none"] : this.descriptor.auth.allowUnsignedPaid ? [this.descriptor.auth.id, "none"] : [this.descriptor.auth.id],
|
|
22485
22698
|
...this.authAudience ? { auth_audience: this.authAudience } : {},
|
|
22486
22699
|
protocol_version: 1,
|
|
22487
22700
|
sdk_sha: this.opts.env.GIT_SHA ?? "unknown",
|
|
@@ -22500,7 +22713,7 @@ var DVMServer = class {
|
|
|
22500
22713
|
if (this.opts.mints) info.mints = this.advertisedMints();
|
|
22501
22714
|
info.capabilities = this.renderCapabilities();
|
|
22502
22715
|
info.payment = { methods: this.resolvePaymentMethods() };
|
|
22503
|
-
if (
|
|
22716
|
+
if (info.payment.methods.includes("x402") && this.opts.x402 && this.x402Support()?.available) {
|
|
22504
22717
|
info.x402 = {
|
|
22505
22718
|
pay_to: this.opts.x402.payTo,
|
|
22506
22719
|
network: this.opts.x402.network,
|
|
@@ -22510,7 +22723,7 @@ var DVMServer = class {
|
|
|
22510
22723
|
dual_serve: this.opts.x402.dualServe ?? true
|
|
22511
22724
|
};
|
|
22512
22725
|
}
|
|
22513
|
-
if (this.opts.mpp) {
|
|
22726
|
+
if (info.payment.methods.includes("tempo") && this.opts.mpp) {
|
|
22514
22727
|
const configured = advertisedMethods(this.opts.mpp);
|
|
22515
22728
|
const withheld = configured.flatMap((method) => {
|
|
22516
22729
|
const reason = this.tempoSessionWithheldReason(method);
|
|
@@ -22885,6 +23098,48 @@ var DVMServer = class {
|
|
|
22885
23098
|
400
|
|
22886
23099
|
);
|
|
22887
23100
|
}
|
|
23101
|
+
/**
|
|
23102
|
+
* Refuse an x402 or Tempo mid-job payment on an unsigned paid job before it
|
|
23103
|
+
* is recorded or verified: those rails settle into credit owned by a caller
|
|
23104
|
+
* pubkey, which the job lacks. Signed jobs always store their pubkey.
|
|
23105
|
+
*/
|
|
23106
|
+
unsignedJobRailRefusal(job, body) {
|
|
23107
|
+
if (!this.descriptor.auth?.allowUnsignedPaid || job.requesterPubkey !== void 0) return void 0;
|
|
23108
|
+
if (body.type !== "payment" || !body.content.x402_payment && !body.content.tempo_credential) {
|
|
23109
|
+
return void 0;
|
|
23110
|
+
}
|
|
23111
|
+
return buildPaymentErrorResponse(
|
|
23112
|
+
paymentErrorBody("payment_method_requires_signature", {
|
|
23113
|
+
message: "Unsigned jobs may be paid only with Cashu; an x402 or Tempo payment was sent."
|
|
23114
|
+
}),
|
|
23115
|
+
void 0,
|
|
23116
|
+
void 0,
|
|
23117
|
+
402
|
|
23118
|
+
);
|
|
23119
|
+
}
|
|
23120
|
+
/** Whether this DVM takes Cashu, the only rail an unsigned payer may use. */
|
|
23121
|
+
unsignedCashuOffered() {
|
|
23122
|
+
return (this.opts.mints?.length ?? 0) > 0 && this.resolvePaymentMethods().includes("cashu");
|
|
23123
|
+
}
|
|
23124
|
+
/**
|
|
23125
|
+
* The error the signed path raises for this envelope-free body, so a refused
|
|
23126
|
+
* unsigned request reads exactly as it does on a DVM without the option.
|
|
23127
|
+
*/
|
|
23128
|
+
unsignedRequestRefusal(c, schema, body, capabilityName) {
|
|
23129
|
+
try {
|
|
23130
|
+
if (this.descriptor.auth && isZodSchema(schema)) {
|
|
23131
|
+
this.descriptor.auth.checkAuth(
|
|
23132
|
+
schema,
|
|
23133
|
+
signedRequestInput(body),
|
|
23134
|
+
this.signedRequestDomain(c, capabilityName)
|
|
23135
|
+
);
|
|
23136
|
+
}
|
|
23137
|
+
} catch (err) {
|
|
23138
|
+
if (err instanceof SignedRequestError) return err;
|
|
23139
|
+
throw err;
|
|
23140
|
+
}
|
|
23141
|
+
return new SignedRequestError("signed request required", "signature_invalid");
|
|
23142
|
+
}
|
|
22888
23143
|
/**
|
|
22889
23144
|
* On authenticated DVMs, envelope-only parse failures defer to auth
|
|
22890
23145
|
* (401 signature_invalid). Builder input issues remain 400 invalid_input.
|
|
@@ -22914,6 +23169,25 @@ var DVMServer = class {
|
|
|
22914
23169
|
if (healthy.length > 0) return healthy;
|
|
22915
23170
|
return all.filter((m) => !tracker.isNutIncompatible(m));
|
|
22916
23171
|
}
|
|
23172
|
+
/**
|
|
23173
|
+
* This request's price at the rates `pricedAt` replaced, or `undefined` when
|
|
23174
|
+
* there are none or they were replaced longer ago than the hold window.
|
|
23175
|
+
* Computed the way the current price is, so the figure matches the one an
|
|
23176
|
+
* earlier 402 quoted.
|
|
23177
|
+
*/
|
|
23178
|
+
previousPriceMsats(cap, dynamicUpfront, pricedAt) {
|
|
23179
|
+
const previous = pricedAt && this.fxFetcher.previousFor(pricedAt);
|
|
23180
|
+
if (!previous) return void 0;
|
|
23181
|
+
try {
|
|
23182
|
+
if (dynamicUpfront) {
|
|
23183
|
+
return fiatToSatsCeil(dynamicUpfront.amount, fxRateFor(previous, dynamicUpfront.currency)) * 1e3;
|
|
23184
|
+
}
|
|
23185
|
+
if (cap.price === void 0) return void 0;
|
|
23186
|
+
return fiatToSatsCeil(parseUsdPrice(cap.price, "price"), fxRateFor(previous, "usd")) * 1e3;
|
|
23187
|
+
} catch {
|
|
23188
|
+
return void 0;
|
|
23189
|
+
}
|
|
23190
|
+
}
|
|
22917
23191
|
/** Authenticated, read-only recovery of a previously accepted public request id. */
|
|
22918
23192
|
async handleRequestResult(c) {
|
|
22919
23193
|
const requestId = c.req.param("requestId");
|
|
@@ -22984,6 +23258,14 @@ var DVMServer = class {
|
|
|
22984
23258
|
400
|
|
22985
23259
|
);
|
|
22986
23260
|
}
|
|
23261
|
+
if (c.req.header("X-Cashu-Request-Id")?.startsWith(DERIVED_REQUEST_ID_PREFIX)) {
|
|
23262
|
+
return c.json(
|
|
23263
|
+
paymentErrorBody("reserved_request_id", {
|
|
23264
|
+
message: `X-Cashu-Request-Id may not start with "${DERIVED_REQUEST_ID_PREFIX}".`
|
|
23265
|
+
}),
|
|
23266
|
+
400
|
|
23267
|
+
);
|
|
23268
|
+
}
|
|
22987
23269
|
const publicRequestId = requestIdFromEnvelope(body.data);
|
|
22988
23270
|
const recoveryStore = requestRecoveryStore(this.jobManager.store);
|
|
22989
23271
|
const resumedRequestId = resumeOnly ? c.req.param("requestId") : void 0;
|
|
@@ -23002,6 +23284,17 @@ var DVMServer = class {
|
|
|
23002
23284
|
const capabilityResult = this.requireCapabilityFromBody(c, body.capability);
|
|
23003
23285
|
if ("error" in capabilityResult) return capabilityResult.error;
|
|
23004
23286
|
const capabilityName = capabilityResult.name;
|
|
23287
|
+
const unsignedPaid = this.jobManager.unsignedPaidInput(body, capabilityName);
|
|
23288
|
+
if (unsignedPaid && publicRequestId) {
|
|
23289
|
+
return c.json(
|
|
23290
|
+
{
|
|
23291
|
+
error: "request_recovery_unsupported",
|
|
23292
|
+
message: "Public request ids require a signed request.",
|
|
23293
|
+
hint: "Sign the request to use request_id recovery, or omit request_id."
|
|
23294
|
+
},
|
|
23295
|
+
400
|
|
23296
|
+
);
|
|
23297
|
+
}
|
|
23005
23298
|
pinDimension("capability", capabilityName);
|
|
23006
23299
|
const cap = this.descriptor.capabilities[capabilityName];
|
|
23007
23300
|
let parsedInput;
|
|
@@ -23010,13 +23303,23 @@ var DVMServer = class {
|
|
|
23010
23303
|
parsedInput = await loggers.isolate.span(
|
|
23011
23304
|
"dvm.input.validate",
|
|
23012
23305
|
{ capability: capabilityName, stage: "input" },
|
|
23013
|
-
() => this.jobManager.parseInput(body, capabilityName),
|
|
23306
|
+
() => this.jobManager.parseInput(body, capabilityName, unsignedPaid),
|
|
23014
23307
|
{ onError: () => ({ "error.code": "invalid_input" }) }
|
|
23015
23308
|
);
|
|
23016
23309
|
} catch (err) {
|
|
23017
|
-
if (!this.deferToAuthGate(err)) return this.invalidInputResponse(c, err);
|
|
23310
|
+
if (unsignedPaid || !this.deferToAuthGate(err)) return this.invalidInputResponse(c, err);
|
|
23018
23311
|
deferredInputError = err;
|
|
23019
23312
|
}
|
|
23313
|
+
if (unsignedPaid && carriesCreditFields(signedRequestInput(body))) {
|
|
23314
|
+
return c.json(
|
|
23315
|
+
{
|
|
23316
|
+
error: "invalid_credit_fields",
|
|
23317
|
+
message: "credit_id, draw_id and fund require a signed request.",
|
|
23318
|
+
hint: "Sign the request to draw on or fund prepaid credit, or remove the credit fields and pay per call."
|
|
23319
|
+
},
|
|
23320
|
+
400
|
|
23321
|
+
);
|
|
23322
|
+
}
|
|
23020
23323
|
let creditEnvelope;
|
|
23021
23324
|
try {
|
|
23022
23325
|
creditEnvelope = extractCreditEnvelope(body.data);
|
|
@@ -23033,9 +23336,26 @@ var DVMServer = class {
|
|
|
23033
23336
|
}
|
|
23034
23337
|
throw err;
|
|
23035
23338
|
}
|
|
23339
|
+
if (unsignedPaid && (cap.price === void 0 && !cap.onQuote || devModeSkipsPaymentVerification(this.opts) || !this.unsignedCashuOffered())) {
|
|
23340
|
+
return buildAuthErrorResponse(
|
|
23341
|
+
c,
|
|
23342
|
+
this.unsignedRequestRefusal(c, cap.input, body, capabilityName),
|
|
23343
|
+
this.publicOrigin
|
|
23344
|
+
);
|
|
23345
|
+
}
|
|
23346
|
+
if (unsignedPaid && await carriesNonCashuPayment(c)) {
|
|
23347
|
+
return buildPaymentErrorResponse(
|
|
23348
|
+
paymentErrorBody("payment_method_requires_signature", {
|
|
23349
|
+
message: "Unsigned requests may pay only with Cashu; an x402 or Tempo payment was attached."
|
|
23350
|
+
}),
|
|
23351
|
+
void 0,
|
|
23352
|
+
void 0,
|
|
23353
|
+
402
|
|
23354
|
+
);
|
|
23355
|
+
}
|
|
23036
23356
|
let authEnvelope;
|
|
23037
23357
|
let authPubkey;
|
|
23038
|
-
if (this.descriptor.auth) {
|
|
23358
|
+
if (this.descriptor.auth && !unsignedPaid) {
|
|
23039
23359
|
const auth = this.descriptor.auth;
|
|
23040
23360
|
try {
|
|
23041
23361
|
const result = await loggers.isolate.span(
|
|
@@ -23083,14 +23403,14 @@ var DVMServer = class {
|
|
|
23083
23403
|
{ capability: capabilityName, input: body.input, params: body.params, data: body.data },
|
|
23084
23404
|
{ stripAuthEnvelope: this.descriptor.auth !== void 0 }
|
|
23085
23405
|
);
|
|
23086
|
-
const authFingerprint =
|
|
23406
|
+
const authFingerprint = authEnvelope ? requestFingerprint(
|
|
23087
23407
|
{ capability: capabilityName, input: body.input, params: body.params, data: body.data },
|
|
23088
23408
|
{ stripAuthEnvelope: false }
|
|
23089
23409
|
) : void 0;
|
|
23090
23410
|
const authorization = c.req.header("Authorization");
|
|
23091
23411
|
const mppArtifact = authorization ? (await import("mppx")).Credential.extractPaymentScheme(authorization) : void 0;
|
|
23092
23412
|
const attachedPayment = c.req.header("X-Cashu") ?? c.req.header("PAYMENT-SIGNATURE") ?? c.req.header("X-PAYMENT") ?? mppArtifact;
|
|
23093
|
-
const hostingPaymentArtifactHash = attachedPayment ?
|
|
23413
|
+
const hostingPaymentArtifactHash = attachedPayment ? createHash12("sha256").update(attachedPayment).digest("hex") : void 0;
|
|
23094
23414
|
if (!resumeOnly && this.opts.hostingControlInstance && hostingPaymentArtifactHash) {
|
|
23095
23415
|
const priorId = await this.opts.hostingControlInstance.acceptedJobByPaymentArtifactHash(
|
|
23096
23416
|
hostingPaymentArtifactHash
|
|
@@ -23172,9 +23492,11 @@ var DVMServer = class {
|
|
|
23172
23492
|
}
|
|
23173
23493
|
const skipPayment = devModeSkipsPaymentVerification(this.opts);
|
|
23174
23494
|
let priceMsats = resumeOnly ? payment.paidMsats || void 0 : void 0;
|
|
23495
|
+
let pricedAt;
|
|
23175
23496
|
if (!resumeOnly && !skipPayment) {
|
|
23176
23497
|
try {
|
|
23177
|
-
|
|
23498
|
+
if (cap.price !== void 0) pricedAt = await this.fxFetcher.fetch();
|
|
23499
|
+
priceMsats = await this.jobManager.currentPriceMsats(capabilityName, pricedAt);
|
|
23178
23500
|
} catch (err) {
|
|
23179
23501
|
const fxErr = pickFxRateUnavailable(err);
|
|
23180
23502
|
if (fxErr) return c.json({ error: fxErr }, 503);
|
|
@@ -23188,17 +23510,26 @@ var DVMServer = class {
|
|
|
23188
23510
|
parsedInput,
|
|
23189
23511
|
normalisedBody,
|
|
23190
23512
|
authPubkey,
|
|
23191
|
-
skipPayment
|
|
23513
|
+
skipPayment,
|
|
23514
|
+
unsignedPaid
|
|
23192
23515
|
);
|
|
23193
23516
|
if (dyn.error) return c.json(dyn.error.body, dyn.error.status);
|
|
23194
23517
|
priceMsats = dyn.priceMsats;
|
|
23195
23518
|
dynamicUpfront = dyn.upfront;
|
|
23519
|
+
pricedAt = dyn.pricedAt;
|
|
23196
23520
|
}
|
|
23197
23521
|
const priceFiat = resumeOnly ? void 0 : resolvePriceFiat({
|
|
23198
23522
|
price: typeof cap.price === "string" ? cap.price : void 0,
|
|
23199
23523
|
priceMsats,
|
|
23200
23524
|
dynamicUpfront
|
|
23201
23525
|
});
|
|
23526
|
+
if (unsignedPaid && !priceMsats) {
|
|
23527
|
+
return buildAuthErrorResponse(
|
|
23528
|
+
c,
|
|
23529
|
+
this.unsignedRequestRefusal(c, cap.input, body, capabilityName),
|
|
23530
|
+
this.publicOrigin
|
|
23531
|
+
);
|
|
23532
|
+
}
|
|
23202
23533
|
if (!resumeOnly && creditEnvelope?.creditId) {
|
|
23203
23534
|
await this.settleLightningFunding(authPubkey, creditEnvelope.creditId);
|
|
23204
23535
|
}
|
|
@@ -23221,7 +23552,13 @@ var DVMServer = class {
|
|
|
23221
23552
|
}
|
|
23222
23553
|
}
|
|
23223
23554
|
if (!skipPayment && !resumedAcceptedPayment) {
|
|
23224
|
-
const railOpts = await this.railVerifyOpts(c);
|
|
23555
|
+
const railOpts = unsignedPaid ? cashuOnlyRailOpts(await this.railVerifyOpts(c)) : await this.railVerifyOpts(c);
|
|
23556
|
+
if (!this.descriptor.auth || unsignedPaid) {
|
|
23557
|
+
railOpts.nut24 = {
|
|
23558
|
+
mints: this.advertisedMints(),
|
|
23559
|
+
previousRequiredMsats: this.previousPriceMsats(cap, dynamicUpfront, pricedAt)
|
|
23560
|
+
};
|
|
23561
|
+
}
|
|
23225
23562
|
hostingPaymentMayHaveLanded = Boolean(
|
|
23226
23563
|
creditEnvelope || railOpts.cashuToken || railOpts.x402Payment || railOpts.mppCredential
|
|
23227
23564
|
);
|
|
@@ -23259,7 +23596,7 @@ var DVMServer = class {
|
|
|
23259
23596
|
this.reportShortPayForfeit(err.detail.forfeit);
|
|
23260
23597
|
if (err.detail.body.error === "replay_rejected") {
|
|
23261
23598
|
const recovered = await this.recoverReplayedJob(c, {
|
|
23262
|
-
requestId: err.detail.replayPaymentId
|
|
23599
|
+
requestId: err.detail.replayPaymentId,
|
|
23263
23600
|
fingerprint,
|
|
23264
23601
|
callerPubkey: authPubkey
|
|
23265
23602
|
});
|
|
@@ -23287,15 +23624,17 @@ var DVMServer = class {
|
|
|
23287
23624
|
}
|
|
23288
23625
|
}
|
|
23289
23626
|
if (!resumedAcceptedPayment) {
|
|
23290
|
-
|
|
23291
|
-
|
|
23292
|
-
|
|
23293
|
-
|
|
23627
|
+
if (!unsignedPaid) {
|
|
23628
|
+
attachCreditMenu(
|
|
23629
|
+
err.detail.body,
|
|
23630
|
+
await this.creditMenu(this.creditCurrency(), authPubkey)
|
|
23631
|
+
);
|
|
23632
|
+
}
|
|
23294
23633
|
if (priceFiat) {
|
|
23295
23634
|
err.detail.body.price_micro = priceFiat.amountMicro;
|
|
23296
23635
|
err.detail.body.price_currency = priceFiat.currency;
|
|
23297
23636
|
}
|
|
23298
|
-
|
|
23637
|
+
const response2 = buildPaymentErrorResponse(
|
|
23299
23638
|
err.detail.body,
|
|
23300
23639
|
err.detail.mppChallenges,
|
|
23301
23640
|
err.detail.x402Requirements,
|
|
@@ -23305,6 +23644,11 @@ var DVMServer = class {
|
|
|
23305
23644
|
this.x402Support()?.exact,
|
|
23306
23645
|
err.detail.x402ErrorCode
|
|
23307
23646
|
);
|
|
23647
|
+
if (err.detail.cashuPaymentRequest) {
|
|
23648
|
+
response2.headers.set("X-Cashu", err.detail.cashuPaymentRequest);
|
|
23649
|
+
response2.headers.set("Cache-Control", "no-store");
|
|
23650
|
+
}
|
|
23651
|
+
return response2;
|
|
23308
23652
|
}
|
|
23309
23653
|
}
|
|
23310
23654
|
throw err;
|
|
@@ -23388,7 +23732,7 @@ var DVMServer = class {
|
|
|
23388
23732
|
}
|
|
23389
23733
|
const isAnonymous = requesterId === "anonymous" || requesterId === "dev-anonymous";
|
|
23390
23734
|
const jobToken = isAnonymous ? randomBytes5(32).toString("hex") : void 0;
|
|
23391
|
-
const requesterTokenHash = jobToken ?
|
|
23735
|
+
const requesterTokenHash = jobToken ? createHash12("sha256").update(jobToken).digest("hex") : void 0;
|
|
23392
23736
|
const job = jm.createJob(
|
|
23393
23737
|
normalisedBody,
|
|
23394
23738
|
requesterId,
|
|
@@ -23401,7 +23745,7 @@ var DVMServer = class {
|
|
|
23401
23745
|
requestFingerprint: fingerprint,
|
|
23402
23746
|
requesterPubkey: authPubkey,
|
|
23403
23747
|
requestId: publicRequestId,
|
|
23404
|
-
authRequestPath:
|
|
23748
|
+
authRequestPath: authEnvelope ? canonicalRequestPath(c.req.url) : void 0,
|
|
23405
23749
|
jobId
|
|
23406
23750
|
}
|
|
23407
23751
|
);
|
|
@@ -23497,15 +23841,16 @@ var DVMServer = class {
|
|
|
23497
23841
|
}
|
|
23498
23842
|
/**
|
|
23499
23843
|
* Recover a lost paid response only for matching request fingerprint,
|
|
23500
|
-
* authenticated pubkey and requester identity.
|
|
23501
|
-
*
|
|
23844
|
+
* authenticated pubkey and requester identity. `requestId` must be the
|
|
23845
|
+
* payment reference the rail bound the presented payment to; a spent bearer
|
|
23846
|
+
* token alone is not proof of request ownership.
|
|
23502
23847
|
*/
|
|
23503
23848
|
async recoverReplayedJob(c, opts) {
|
|
23504
23849
|
if (!opts.requestId) return void 0;
|
|
23505
23850
|
const prior = await this.jobManager.store.findJobByPaymentTxHash(opts.requestId);
|
|
23506
23851
|
if (!prior) return void 0;
|
|
23507
23852
|
const bodyMatches = prior.requestFingerprint !== void 0 && prior.requestFingerprint === opts.fingerprint;
|
|
23508
|
-
const pubkeyMatches = this.descriptor.auth === void 0 || prior.requesterPubkey
|
|
23853
|
+
const pubkeyMatches = this.descriptor.auth === void 0 || prior.requesterPubkey === opts.callerPubkey;
|
|
23509
23854
|
const requesterMatches = prior.requesterId === c.get("requesterId");
|
|
23510
23855
|
if (!bodyMatches || !pubkeyMatches || !requesterMatches) {
|
|
23511
23856
|
diagnosticConsole.warn(
|
|
@@ -23638,16 +23983,17 @@ var DVMServer = class {
|
|
|
23638
23983
|
* schema separately. Refuse invalid input/results, currency mismatch or missing
|
|
23639
23984
|
* FX when payment needs a price (400/500/503 as classified below).
|
|
23640
23985
|
*/
|
|
23641
|
-
async computeDynamicPrice(onQuote, parsedInput, body, callerPubkey, skipRateConversion = false) {
|
|
23986
|
+
async computeDynamicPrice(onQuote, parsedInput, body, callerPubkey, skipRateConversion = false, unsigned2 = false) {
|
|
23642
23987
|
let data = parsedInput;
|
|
23643
23988
|
if (isZodSchema(onQuote.schema)) {
|
|
23644
|
-
const
|
|
23989
|
+
const schema = unsigned2 ? unsignedInputSchema(onQuote.schema) ?? onQuote.schema : onQuote.schema;
|
|
23990
|
+
const parsed = schema.safeParse(parsedInput);
|
|
23645
23991
|
if (!parsed.success) {
|
|
23646
23992
|
return {
|
|
23647
23993
|
error: {
|
|
23648
23994
|
body: {
|
|
23649
23995
|
error: "quote_unavailable",
|
|
23650
|
-
message: "DVM uses dynamic pricing but the job input does not satisfy onQuote.schema. Submit the same payload to /v1/quote to confirm pricing."
|
|
23996
|
+
message: unsigned2 ? "DVM uses dynamic pricing but the unsigned job input does not satisfy onQuote.schema. Sign the request, or send input that matches the published schema." : "DVM uses dynamic pricing but the job input does not satisfy onQuote.schema. Submit the same payload to /v1/quote to confirm pricing."
|
|
23651
23997
|
},
|
|
23652
23998
|
status: 400
|
|
23653
23999
|
}
|
|
@@ -23677,7 +24023,8 @@ var DVMServer = class {
|
|
|
23677
24023
|
const priceMsats = fiatToSatsCeil(validated.upfront.amount, fxRateFor(fx, upfrontCurrency)) * 1e3;
|
|
23678
24024
|
return {
|
|
23679
24025
|
priceMsats,
|
|
23680
|
-
upfront: { amount: validated.upfront.amount, currency: upfrontCurrency }
|
|
24026
|
+
upfront: { amount: validated.upfront.amount, currency: upfrontCurrency },
|
|
24027
|
+
pricedAt: fx
|
|
23681
24028
|
};
|
|
23682
24029
|
} catch (err) {
|
|
23683
24030
|
if (err instanceof InvalidCurrencyError || err instanceof UnsupportedCurrencyError) {
|
|
@@ -23959,6 +24306,8 @@ var DVMServer = class {
|
|
|
23959
24306
|
this.opts.devMode === true
|
|
23960
24307
|
);
|
|
23961
24308
|
if (contentErr2) return c.json({ error: "invalid_message", message: contentErr2 }, 400);
|
|
24309
|
+
const railRefusal2 = this.unsignedJobRailRefusal(activeJob, body2);
|
|
24310
|
+
if (railRefusal2) return railRefusal2;
|
|
23962
24311
|
const inboundSeq2 = await jm.recordInboundPending(activeJob, body2.type, body2.content);
|
|
23963
24312
|
const lockPubkeys2 = await this.resolveLockPubkeysForReceive();
|
|
23964
24313
|
let unappliedCredit2;
|
|
@@ -24019,6 +24368,8 @@ var DVMServer = class {
|
|
|
24019
24368
|
}
|
|
24020
24369
|
const contentErr = validateMessageContent(body.type, body.content, this.opts.devMode === true);
|
|
24021
24370
|
if (contentErr) return c.json({ error: "invalid_message", message: contentErr }, 400);
|
|
24371
|
+
const railRefusal = this.unsignedJobRailRefusal(record, body);
|
|
24372
|
+
if (railRefusal) return railRefusal;
|
|
24022
24373
|
if (isStreamableJobStore(jm.store)) {
|
|
24023
24374
|
record.messages = await jm.store.getMessages(id, 0);
|
|
24024
24375
|
record.seq = Math.max(record.seq, ...record.messages.map((message) => message.seq));
|
|
@@ -24218,7 +24569,7 @@ function isJobOwner(c, job) {
|
|
|
24218
24569
|
if (job.requesterTokenHash) {
|
|
24219
24570
|
const token = c.req.header("X-Job-Token");
|
|
24220
24571
|
if (!token) return false;
|
|
24221
|
-
const provided =
|
|
24572
|
+
const provided = createHash12("sha256").update(token).digest("hex");
|
|
24222
24573
|
return timingSafeEqualHex(provided, job.requesterTokenHash);
|
|
24223
24574
|
}
|
|
24224
24575
|
return c.get("requesterId") === job.requesterId;
|
|
@@ -24341,6 +24692,24 @@ function removeUnavailableContent(fields) {
|
|
|
24341
24692
|
delete fields.payload_in;
|
|
24342
24693
|
}
|
|
24343
24694
|
}
|
|
24695
|
+
async function carriesNonCashuPayment(c) {
|
|
24696
|
+
if (c.req.header("PAYMENT-SIGNATURE") || c.req.header("X-PAYMENT")) return true;
|
|
24697
|
+
const authorization = c.req.header("Authorization");
|
|
24698
|
+
if (!authorization) return false;
|
|
24699
|
+
return Boolean((await import("mppx")).Credential.extractPaymentScheme(authorization));
|
|
24700
|
+
}
|
|
24701
|
+
function cashuOnlyRailOpts(opts) {
|
|
24702
|
+
return {
|
|
24703
|
+
...opts,
|
|
24704
|
+
x402Payment: void 0,
|
|
24705
|
+
x402Config: void 0,
|
|
24706
|
+
x402ExactSettlement: void 0,
|
|
24707
|
+
x402ExactVersions: void 0,
|
|
24708
|
+
x402BatchSettlement: void 0,
|
|
24709
|
+
mppCredential: void 0,
|
|
24710
|
+
mpp: void 0
|
|
24711
|
+
};
|
|
24712
|
+
}
|
|
24344
24713
|
function terminalResponseFields(job) {
|
|
24345
24714
|
const fields = {};
|
|
24346
24715
|
if (job.upfrontPayment !== void 0) fields.upfront_payment = job.upfrontPayment;
|