@thecryptodonkey/toll-booth 3.5.0 → 3.7.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/core/melt-to-lightning.d.ts +24 -0
- package/dist/core/melt-to-lightning.js +43 -0
- package/dist/core/toll-booth.js +13 -0
- package/dist/core/xcashu-rail.js +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Proof } from '@cashu/cashu-ts';
|
|
2
|
+
export type MeltResult = {
|
|
3
|
+
paid: true;
|
|
4
|
+
amountSats: number;
|
|
5
|
+
preimage?: string;
|
|
6
|
+
} | {
|
|
7
|
+
paid: false;
|
|
8
|
+
error: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Melts Cashu proofs to pay a Lightning invoice on the operator's node.
|
|
12
|
+
* Handles the full flow: invoice creation → melt quote → coin selection → melt.
|
|
13
|
+
* Discards change proofs (fee overpayment donated to mint).
|
|
14
|
+
*
|
|
15
|
+
* @param opts.mintUrl - The mint that issued the proofs
|
|
16
|
+
* @param opts.proofs - Server-side proofs from wallet.receive()
|
|
17
|
+
* @param opts.createInvoice - Callback to create a BOLT11 invoice on the operator's node
|
|
18
|
+
*/
|
|
19
|
+
export declare function meltToLightning(opts: {
|
|
20
|
+
mintUrl: string;
|
|
21
|
+
proofs: Proof[];
|
|
22
|
+
createInvoice: (amountSats: number) => Promise<string>;
|
|
23
|
+
}): Promise<MeltResult>;
|
|
24
|
+
//# sourceMappingURL=melt-to-lightning.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Wallet } from '@cashu/cashu-ts';
|
|
2
|
+
/**
|
|
3
|
+
* Melts Cashu proofs to pay a Lightning invoice on the operator's node.
|
|
4
|
+
* Handles the full flow: invoice creation → melt quote → coin selection → melt.
|
|
5
|
+
* Discards change proofs (fee overpayment donated to mint).
|
|
6
|
+
*
|
|
7
|
+
* @param opts.mintUrl - The mint that issued the proofs
|
|
8
|
+
* @param opts.proofs - Server-side proofs from wallet.receive()
|
|
9
|
+
* @param opts.createInvoice - Callback to create a BOLT11 invoice on the operator's node
|
|
10
|
+
*/
|
|
11
|
+
export async function meltToLightning(opts) {
|
|
12
|
+
const { mintUrl, proofs, createInvoice } = opts;
|
|
13
|
+
const totalSats = proofs.reduce((sum, p) => sum + p.amount, 0);
|
|
14
|
+
if (totalSats <= 0) {
|
|
15
|
+
return { paid: false, error: 'No proofs to melt' };
|
|
16
|
+
}
|
|
17
|
+
const wallet = new Wallet(mintUrl, { unit: 'sat' });
|
|
18
|
+
// Create invoice for the full proof amount
|
|
19
|
+
const invoice = await createInvoice(totalSats);
|
|
20
|
+
// Get melt quote to learn fee_reserve
|
|
21
|
+
const meltQuote = await wallet.createMeltQuoteBolt11(invoice);
|
|
22
|
+
const needed = meltQuote.amount + meltQuote.fee_reserve;
|
|
23
|
+
if (needed > totalSats) {
|
|
24
|
+
return {
|
|
25
|
+
paid: false,
|
|
26
|
+
error: `Proofs insufficient for fees (have ${totalSats}, need ${needed} including ${meltQuote.fee_reserve} fee reserve)`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Coin selection
|
|
30
|
+
const { send } = await wallet.send(needed, proofs, { includeFees: true });
|
|
31
|
+
// Melt — pay the Lightning invoice via the mint
|
|
32
|
+
const meltResponse = await wallet.meltProofsBolt11(meltQuote, send);
|
|
33
|
+
if (meltResponse.quote.state === 'PAID') {
|
|
34
|
+
// Discard change proofs (keep + change) — bearer instruments not retained
|
|
35
|
+
return {
|
|
36
|
+
paid: true,
|
|
37
|
+
amountSats: meltQuote.amount,
|
|
38
|
+
preimage: meltResponse.quote.payment_preimage ?? undefined,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { paid: false, error: `Melt state: ${meltResponse.quote.state}` };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=melt-to-lightning.js.map
|
package/dist/core/toll-booth.js
CHANGED
|
@@ -65,6 +65,19 @@ export function createTollBooth(config) {
|
|
|
65
65
|
const challengeHeaders = {};
|
|
66
66
|
const challengeBody = {};
|
|
67
67
|
const normalisedPrice = normalisedPricing[req.path] ?? { sats: defaultAmount };
|
|
68
|
+
// HEAD requests return a lightweight price probe without creating
|
|
69
|
+
// invoices or storing state. Useful for lnget --dry-run and indexers.
|
|
70
|
+
if (req.method === 'HEAD') {
|
|
71
|
+
if (normalisedPrice.sats !== undefined) {
|
|
72
|
+
challengeHeaders['X-L402-Price-Sats'] = String(normalisedPrice.sats);
|
|
73
|
+
}
|
|
74
|
+
if (normalisedPrice.usd !== undefined) {
|
|
75
|
+
challengeHeaders['X-L402-Price-Usd'] = String(normalisedPrice.usd);
|
|
76
|
+
}
|
|
77
|
+
challengeHeaders['WWW-Authenticate'] = 'L402 price-only';
|
|
78
|
+
challengeBody.message = 'Payment required.';
|
|
79
|
+
return { action: 'challenge', status: 402, headers: challengeHeaders, body: challengeBody };
|
|
80
|
+
}
|
|
68
81
|
for (const rail of rails) {
|
|
69
82
|
if (rail.canChallenge && !rail.canChallenge(normalisedPrice))
|
|
70
83
|
continue;
|
package/dist/core/xcashu-rail.js
CHANGED
|
@@ -91,6 +91,18 @@ export function createXCashuRail(config, storage) {
|
|
|
91
91
|
if (creditedAmount <= 0) {
|
|
92
92
|
return FAIL;
|
|
93
93
|
}
|
|
94
|
+
// Fire onProofsReceived callback (non-blocking, fire-and-forget)
|
|
95
|
+
if (config.onProofsReceived) {
|
|
96
|
+
try {
|
|
97
|
+
const cbResult = config.onProofsReceived(receivedProofs, tokenMint, creditedAmount);
|
|
98
|
+
if (cbResult && typeof cbResult.catch === 'function') {
|
|
99
|
+
cbResult.catch(() => { });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Callback errors silently discarded — never block the payment flow
|
|
104
|
+
}
|
|
105
|
+
}
|
|
94
106
|
// Generate payment ID and settlement secret
|
|
95
107
|
const paymentId = randomBytes(32).toString('hex');
|
|
96
108
|
const settlementSecret = randomBytes(32).toString('hex');
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export type { X402RailConfig, X402Facilitator, X402Payment, X402VerifyResult } f
|
|
|
29
29
|
export { DEFAULT_USDC_ASSETS } from './core/x402-types.js';
|
|
30
30
|
export { createXCashuRail } from './core/xcashu-rail.js';
|
|
31
31
|
export type { XCashuConfig } from './types.js';
|
|
32
|
+
export { meltToLightning } from './core/melt-to-lightning.js';
|
|
33
|
+
export type { MeltResult } from './core/melt-to-lightning.js';
|
|
32
34
|
export { mintMacaroon, verifyMacaroon, parseCaveats } from './macaroon.js';
|
|
33
35
|
export type { VerifyContext, VerifyResult } from './macaroon.js';
|
|
34
36
|
export { FreeTier, CreditFreeTier } from './free-tier.js';
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export { createL402Rail } from './core/l402-rail.js';
|
|
|
18
18
|
export { createX402Rail } from './core/x402-rail.js';
|
|
19
19
|
export { DEFAULT_USDC_ASSETS } from './core/x402-types.js';
|
|
20
20
|
export { createXCashuRail } from './core/xcashu-rail.js';
|
|
21
|
+
export { meltToLightning } from './core/melt-to-lightning.js';
|
|
21
22
|
// Utilities
|
|
22
23
|
export { mintMacaroon, verifyMacaroon, parseCaveats } from './macaroon.js';
|
|
23
24
|
export { FreeTier, CreditFreeTier } from './free-tier.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export interface LightningBackend {
|
|
|
43
43
|
*/
|
|
44
44
|
checkInvoice(paymentHash: string): Promise<InvoiceStatus>;
|
|
45
45
|
}
|
|
46
|
+
import type { Proof } from '@cashu/cashu-ts';
|
|
46
47
|
import type { Currency, PricingEntry } from './core/payment-rail.js';
|
|
47
48
|
import type { X402RailConfig } from './core/x402-types.js';
|
|
48
49
|
/**
|
|
@@ -81,6 +82,12 @@ export interface XCashuConfig {
|
|
|
81
82
|
mints: string[];
|
|
82
83
|
/** Currency unit, default 'sat' */
|
|
83
84
|
unit?: Currency;
|
|
85
|
+
/**
|
|
86
|
+
* Called after successful token swap with the server-side proofs.
|
|
87
|
+
* Fire-and-forget — the rail does NOT await this callback.
|
|
88
|
+
* Use for melting, persisting, or forwarding received ecash.
|
|
89
|
+
*/
|
|
90
|
+
onProofsReceived?: (proofs: Proof[], mintUrl: string, amount: number) => void | Promise<void>;
|
|
84
91
|
}
|
|
85
92
|
/**
|
|
86
93
|
* Configuration for a toll-booth instance.
|
package/package.json
CHANGED