thunder-bridge 1.4.2 → 2.1.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/README.md +145 -133
- package/dist/bank-CEIuNhV_.d.cts +896 -0
- package/dist/bank-M8flcMks.d.ts +896 -0
- package/dist/bank.cjs +338 -0
- package/dist/bank.d.cts +46 -0
- package/dist/bank.d.ts +46 -0
- package/dist/bank.js +310 -0
- package/dist/errors-DriqW-lp.d.cts +126 -0
- package/dist/errors-ZEUT-MhO.d.ts +126 -0
- package/dist/index.cjs +2108 -1235
- package/dist/index.d.cts +13 -505
- package/dist/index.d.ts +13 -505
- package/dist/index.js +2088 -1193
- package/dist/{server.cjs → nwc.cjs} +376 -720
- package/dist/nwc.d.cts +122 -0
- package/dist/nwc.d.ts +122 -0
- package/dist/{server.js → nwc.js} +368 -695
- package/dist/price.cjs +240 -0
- package/dist/price.d.cts +17 -0
- package/dist/price.d.ts +17 -0
- package/dist/price.js +205 -0
- package/dist/qr-CF-YeXU1.d.cts +55 -0
- package/dist/qr-CF-YeXU1.d.ts +55 -0
- package/dist/qr.cjs +259 -0
- package/dist/qr.d.cts +1 -0
- package/dist/qr.d.ts +1 -0
- package/dist/qr.js +224 -0
- package/dist/types-DYZ9EkmJ.d.cts +261 -0
- package/dist/types-DYZ9EkmJ.d.ts +261 -0
- package/openapi.yaml +29 -39
- package/package.json +48 -9
- package/dist/rail-CqUfuYXJ.d.cts +0 -615
- package/dist/rail-CqUfuYXJ.d.ts +0 -615
- package/dist/server.d.cts +0 -145
- package/dist/server.d.ts +0 -145
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many minor units of `currency` one bitcoin costs at one venue, so 134883815
|
|
3
|
+
* is 1,348,838.15 CZK. Throws when that venue does not quote that currency, which
|
|
4
|
+
* is a normal answer rather than a fault: Kraken and Bitstamp have no CZK pair
|
|
5
|
+
*
|
|
6
|
+
* This is the plugin seam for prices. Another venue is another function of this
|
|
7
|
+
* shape
|
|
8
|
+
*/
|
|
9
|
+
type Ticker = (currency: string) => Promise<number>;
|
|
10
|
+
/** How many venues have to agree, how far apart they may be, and how long an answer is held */
|
|
11
|
+
interface MedianOptions {
|
|
12
|
+
/**
|
|
13
|
+
* How many venues have to answer before a price is usable. Two is the floor
|
|
14
|
+
* worth having, because one venue is a number nobody checked
|
|
15
|
+
*/
|
|
16
|
+
minVenues?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Refuse the lot when the cheapest and dearest answers are further apart than
|
|
19
|
+
* this many basis points. Venues normally sit inside 50, so a wider spread means
|
|
20
|
+
* one of them is broken or stale rather than that the market moved
|
|
21
|
+
*/
|
|
22
|
+
maxSpreadBps?: number;
|
|
23
|
+
/** Hold the last answer this long per currency, so an order page is not four requests */
|
|
24
|
+
holdForSecs?: number;
|
|
25
|
+
}
|
|
26
|
+
/** Coinbase, CASP authorised in Luxembourg. Quotes CZK, EUR and most fiat */
|
|
27
|
+
declare function coinbase(baseUrl?: string): Ticker;
|
|
28
|
+
/** Kraken, CASP authorised by the Central Bank of Ireland. Quotes EUR and USD, no CZK */
|
|
29
|
+
declare function kraken(baseUrl?: string): Ticker;
|
|
30
|
+
/**
|
|
31
|
+
* Bitstamp, CASP authorised by the CSSF in Luxembourg. Quotes EUR and USD, no CZK.
|
|
32
|
+
*
|
|
33
|
+
* An unknown pair is answered with a `200` and the whole ticker list, whose first
|
|
34
|
+
* entry is BTC/USD, so asking it for CZK and reading the number would quote a
|
|
35
|
+
* bitcoin at 64,000 crowns. Anything but a single object is therefore refused
|
|
36
|
+
*/
|
|
37
|
+
declare function bitstamp(baseUrl?: string): Ticker;
|
|
38
|
+
/** Coinmate, on the ESMA CASP register, Czech and the one with a real BTC/CZK book */
|
|
39
|
+
declare function coinmate(baseUrl?: string): Ticker;
|
|
40
|
+
/**
|
|
41
|
+
* Ask several venues and take the middle answer, refusing the lot when they
|
|
42
|
+
* disagree too much.
|
|
43
|
+
*
|
|
44
|
+
* The default is the four MiCA authorised venues below, and every one of them is
|
|
45
|
+
* replaceable: pass your own list, or one venue, or a function that reads a price
|
|
46
|
+
* you already have. A venue that does not quote the currency is skipped rather
|
|
47
|
+
* than fatal, which for CZK leaves Coinbase and Coinmate.
|
|
48
|
+
*
|
|
49
|
+
* The middle is taken rather than the mean so one stuck venue moves the answer by
|
|
50
|
+
* nothing instead of by half its error, and the spread check is what catches the
|
|
51
|
+
* stuck venue that stays inside the pack.
|
|
52
|
+
*/
|
|
53
|
+
declare function medianOf(tickers?: Ticker[], options?: MedianOptions): Ticker;
|
|
54
|
+
/**
|
|
55
|
+
* What to ask for over Lightning for a price named in fiat, in millisatoshi.
|
|
56
|
+
*
|
|
57
|
+
* `priceMinorPerBtc` is what a `Ticker` returns. The arithmetic is exact, in
|
|
58
|
+
* BigInt, because a million crown order times a hundred billion millisatoshi
|
|
59
|
+
* leaves what a double can count, and it rounds up, because the extra
|
|
60
|
+
* millisatoshi is worth nothing and belongs to the recipient rather than to a
|
|
61
|
+
* rounding rule.
|
|
62
|
+
*
|
|
63
|
+
* `spreadBps` is yours to set, in basis points, and defaults to none. A Lightning
|
|
64
|
+
* invoice lives an hour and a bank transfer takes days, so a shop pricing in fiat is
|
|
65
|
+
* carrying that volatility whether or not it charges for it
|
|
66
|
+
*/
|
|
67
|
+
declare function msatFor(amountMinor: number, priceMinorPerBtc: number, options?: {
|
|
68
|
+
spreadBps?: number;
|
|
69
|
+
}): number;
|
|
70
|
+
|
|
71
|
+
declare const brand: unique symbol;
|
|
72
|
+
/**
|
|
73
|
+
* A whole number of millisatoshi that came from `sats`, `msat` or `fiat`, and
|
|
74
|
+
* could not have come from anywhere else.
|
|
75
|
+
*
|
|
76
|
+
* The brand is why: a bare number is not one of these, so `21` cannot be passed
|
|
77
|
+
* where a price is wanted and quietly mean twenty-one thousandths of a satoshi.
|
|
78
|
+
* It costs nothing at runtime, where the value is an ordinary number
|
|
79
|
+
*/
|
|
80
|
+
type Msat = number & {
|
|
81
|
+
readonly [brand]: "Msat";
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* What a payment is worth. A `Msat` is a price known now, and a function is one
|
|
85
|
+
* worked out when the invoice is minted, which is what a fiat price has to be.
|
|
86
|
+
*
|
|
87
|
+
* Build one with `sats`, `msat` or `fiat`
|
|
88
|
+
*/
|
|
89
|
+
type Amount = Msat | (() => Msat | Promise<Msat>);
|
|
90
|
+
/** How a fiat price is turned into millisatoshi at the moment of minting */
|
|
91
|
+
interface FiatOptions {
|
|
92
|
+
/**
|
|
93
|
+
* Where the rate comes from, the median of the four MiCA authorised venues by
|
|
94
|
+
* default. Pass your own to price off one venue, off your own book, or off a
|
|
95
|
+
* number you already hold
|
|
96
|
+
*/
|
|
97
|
+
rate?: Ticker;
|
|
98
|
+
/**
|
|
99
|
+
* What you add over the rate, in basis points, none by default. A Lightning
|
|
100
|
+
* invoice lives an hour and a bank transfer takes days, so a shop pricing in
|
|
101
|
+
* fiat carries that volatility whether or not it charges for it
|
|
102
|
+
*/
|
|
103
|
+
spreadBps?: number;
|
|
104
|
+
}
|
|
105
|
+
/** A whole number of satoshi, so `sats(21)` is 21000 millisatoshi */
|
|
106
|
+
declare function sats(whole: number): Msat;
|
|
107
|
+
/** An exact number of millisatoshi, for a price already in the smallest unit */
|
|
108
|
+
declare function msat(exact: number): Msat;
|
|
109
|
+
/**
|
|
110
|
+
* A price named in fiat, converted when the invoice is minted rather than now.
|
|
111
|
+
*
|
|
112
|
+
* Name it as a string and it is read digit by digit, exactly. Name it as a
|
|
113
|
+
* number and it is rounded to the currency's ISO 4217 minor unit, because
|
|
114
|
+
* binary floating point cannot hold 4.99 and a payment library that pretends
|
|
115
|
+
* otherwise moves the wrong amount.
|
|
116
|
+
*
|
|
117
|
+
* Every conversion asks the rate afresh, so two calls a second apart can
|
|
118
|
+
* differ. That is the honest behaviour for a fiat price, and the reason an
|
|
119
|
+
* amount is a function rather than a number.
|
|
120
|
+
*
|
|
121
|
+
* The answer is rounded up to a whole satoshi, because a wallet issues an
|
|
122
|
+
* invoice in satoshi and refuses a fraction of one. Up rather than down, so the
|
|
123
|
+
* rounding is never the shop's loss. `msatFor` is the raw conversion, for a rail
|
|
124
|
+
* that has no invoice to round for
|
|
125
|
+
*/
|
|
126
|
+
declare function fiat(major: number | string, currency: string, options?: FiatOptions): () => Promise<Msat>;
|
|
127
|
+
|
|
128
|
+
/** Where a payment stands, `paid` is the only status that carries a preimage */
|
|
129
|
+
type PaymentStatus = "pending" | "paid" | "expired";
|
|
130
|
+
interface Reported {
|
|
131
|
+
id: string;
|
|
132
|
+
status: PaymentStatus;
|
|
133
|
+
paymentHash: string;
|
|
134
|
+
verifyUrl: string;
|
|
135
|
+
preimage: string | null;
|
|
136
|
+
expiresAt: number;
|
|
137
|
+
createdAt: number;
|
|
138
|
+
/** What the watcher needs and the gateway cannot read, `unseal` opens it */
|
|
139
|
+
sealed: string | null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A payment the gateway minted. It resolved the address itself, so it knows who
|
|
143
|
+
* is paid, how much, and which invoice says so, and none of the three can be
|
|
144
|
+
* null here
|
|
145
|
+
*/
|
|
146
|
+
interface MintedPayment extends Reported {
|
|
147
|
+
kind: "minted";
|
|
148
|
+
lnAddress: string;
|
|
149
|
+
amountMsat: number;
|
|
150
|
+
bolt11: string;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* A payment the gateway was handed rather than asked to mint. It was told a hash,
|
|
154
|
+
* a URL and an expiry and nothing else, which is the point of `watch`, so the
|
|
155
|
+
* address, the amount and the invoice are all absent rather than merely unknown
|
|
156
|
+
*/
|
|
157
|
+
interface WatchedPayment extends Reported {
|
|
158
|
+
kind: "watched";
|
|
159
|
+
lnAddress: null;
|
|
160
|
+
amountMsat: null;
|
|
161
|
+
bolt11: null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A payment as the gateway reports it, of either sort. Check `kind` and the
|
|
165
|
+
* three fields a watched payment does not carry stop being null, so nothing here
|
|
166
|
+
* needs an assertion to read
|
|
167
|
+
*/
|
|
168
|
+
type Payment = MintedPayment | WatchedPayment;
|
|
169
|
+
/**
|
|
170
|
+
* A payment as the caller already knows it: what the gateway calls it and the
|
|
171
|
+
* hash it settles against. Every `Payment` is one, and a caller reading back
|
|
172
|
+
* after a restart builds one from the two fields it stored
|
|
173
|
+
*/
|
|
174
|
+
interface Held {
|
|
175
|
+
id: string;
|
|
176
|
+
paymentHash: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Who is paid and how much. `to` is a priority list when it is an array: the
|
|
180
|
+
* gateway takes the first address that can issue a provable invoice for the
|
|
181
|
+
* amount and the rest are the fallback
|
|
182
|
+
*/
|
|
183
|
+
interface Charge {
|
|
184
|
+
paidTo: string | string[];
|
|
185
|
+
amount: Amount;
|
|
186
|
+
/** Where the gateway posts the settlement, signed with the key it publishes */
|
|
187
|
+
webhookUrl?: string;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* A charge with its price settled, which is what a proof compares the gateway's
|
|
191
|
+
* answer against. Asking a fiat price twice gives two numbers, so the proof is
|
|
192
|
+
* handed the one that was actually asked for
|
|
193
|
+
*/
|
|
194
|
+
interface Priced {
|
|
195
|
+
paidTo: string[];
|
|
196
|
+
amountMsat: number;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* An invoice you obtained yourself, handed over to be watched. The gateway is
|
|
200
|
+
* given no address and no amount, so it cannot refuse one recipient rather than
|
|
201
|
+
* all of them
|
|
202
|
+
*/
|
|
203
|
+
interface Handover {
|
|
204
|
+
paymentHash: string;
|
|
205
|
+
verifyUrl: string;
|
|
206
|
+
expiresAt: number;
|
|
207
|
+
/** Groups this payment with every other one carrying the same secret */
|
|
208
|
+
trigger?: string;
|
|
209
|
+
/**
|
|
210
|
+
* How many of this trigger's settlements the gateway keeps replayable past the
|
|
211
|
+
* hour it would otherwise forget them in, up to the ceiling its operator set.
|
|
212
|
+
* Needs `trigger`, defaults to none
|
|
213
|
+
*/
|
|
214
|
+
replay?: number;
|
|
215
|
+
/** Sealed with `seal` for this payment hash, so the gateway stores what it cannot read or move */
|
|
216
|
+
sealed?: string;
|
|
217
|
+
webhookUrl?: string;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Which address would serve an amount, and what the ones ahead of it refused.
|
|
221
|
+
* `feeMsat` is always zero, the payer pays the recipient's own invoice and the
|
|
222
|
+
* gateway is never in the money's path
|
|
223
|
+
*/
|
|
224
|
+
interface Quote {
|
|
225
|
+
lnAddress: string;
|
|
226
|
+
amountMsat: number;
|
|
227
|
+
feeMsat: number;
|
|
228
|
+
minMsat: number;
|
|
229
|
+
maxMsat: number;
|
|
230
|
+
metadata: string;
|
|
231
|
+
refusals: WalletFailure[];
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* A one minute pass onto one trigger's stream. It opens that trigger and nothing
|
|
235
|
+
* else, which is what makes it the thing to hand a browser when the trigger
|
|
236
|
+
* secret is not. `expiresAt` is unix seconds, like every other time here
|
|
237
|
+
*/
|
|
238
|
+
interface SocketTicket {
|
|
239
|
+
ticket: string;
|
|
240
|
+
expiresAt: number;
|
|
241
|
+
}
|
|
242
|
+
/** Why one wallet in the list could not be used */
|
|
243
|
+
type WalletReason = "address-unusable" | "unreachable" | "amount-not-accepted" | "cannot-prove-delivery" | "invoice-refused";
|
|
244
|
+
/** One wallet on the list that could not be used, and the reason it could not */
|
|
245
|
+
interface WalletFailure {
|
|
246
|
+
address: string;
|
|
247
|
+
reason: WalletReason;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* What a delivery carries. Everything needed to act on a settlement and to check
|
|
251
|
+
* it, and nothing else, so a retry is the same size every time
|
|
252
|
+
*/
|
|
253
|
+
interface Settlement {
|
|
254
|
+
id: string;
|
|
255
|
+
status: PaymentStatus;
|
|
256
|
+
paymentHash: string;
|
|
257
|
+
preimage: string | null;
|
|
258
|
+
settledAt: number;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export { type Amount as A, type Charge as C, type FiatOptions as F, type Handover as H, type MedianOptions as M, type Payment as P, type Quote as Q, type Settlement as S, type Ticker as T, type WalletFailure as W, coinmate as a, bitstamp as b, coinbase as c, msatFor as d, type Held as e, type MintedPayment as f, type Msat as g, type PaymentStatus as h, type Priced as i, type SocketTicket as j, kraken as k, type WalletReason as l, medianOf as m, type WatchedPayment as n, fiat as o, msat as p, sats as s };
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many minor units of `currency` one bitcoin costs at one venue, so 134883815
|
|
3
|
+
* is 1,348,838.15 CZK. Throws when that venue does not quote that currency, which
|
|
4
|
+
* is a normal answer rather than a fault: Kraken and Bitstamp have no CZK pair
|
|
5
|
+
*
|
|
6
|
+
* This is the plugin seam for prices. Another venue is another function of this
|
|
7
|
+
* shape
|
|
8
|
+
*/
|
|
9
|
+
type Ticker = (currency: string) => Promise<number>;
|
|
10
|
+
/** How many venues have to agree, how far apart they may be, and how long an answer is held */
|
|
11
|
+
interface MedianOptions {
|
|
12
|
+
/**
|
|
13
|
+
* How many venues have to answer before a price is usable. Two is the floor
|
|
14
|
+
* worth having, because one venue is a number nobody checked
|
|
15
|
+
*/
|
|
16
|
+
minVenues?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Refuse the lot when the cheapest and dearest answers are further apart than
|
|
19
|
+
* this many basis points. Venues normally sit inside 50, so a wider spread means
|
|
20
|
+
* one of them is broken or stale rather than that the market moved
|
|
21
|
+
*/
|
|
22
|
+
maxSpreadBps?: number;
|
|
23
|
+
/** Hold the last answer this long per currency, so an order page is not four requests */
|
|
24
|
+
holdForSecs?: number;
|
|
25
|
+
}
|
|
26
|
+
/** Coinbase, CASP authorised in Luxembourg. Quotes CZK, EUR and most fiat */
|
|
27
|
+
declare function coinbase(baseUrl?: string): Ticker;
|
|
28
|
+
/** Kraken, CASP authorised by the Central Bank of Ireland. Quotes EUR and USD, no CZK */
|
|
29
|
+
declare function kraken(baseUrl?: string): Ticker;
|
|
30
|
+
/**
|
|
31
|
+
* Bitstamp, CASP authorised by the CSSF in Luxembourg. Quotes EUR and USD, no CZK.
|
|
32
|
+
*
|
|
33
|
+
* An unknown pair is answered with a `200` and the whole ticker list, whose first
|
|
34
|
+
* entry is BTC/USD, so asking it for CZK and reading the number would quote a
|
|
35
|
+
* bitcoin at 64,000 crowns. Anything but a single object is therefore refused
|
|
36
|
+
*/
|
|
37
|
+
declare function bitstamp(baseUrl?: string): Ticker;
|
|
38
|
+
/** Coinmate, on the ESMA CASP register, Czech and the one with a real BTC/CZK book */
|
|
39
|
+
declare function coinmate(baseUrl?: string): Ticker;
|
|
40
|
+
/**
|
|
41
|
+
* Ask several venues and take the middle answer, refusing the lot when they
|
|
42
|
+
* disagree too much.
|
|
43
|
+
*
|
|
44
|
+
* The default is the four MiCA authorised venues below, and every one of them is
|
|
45
|
+
* replaceable: pass your own list, or one venue, or a function that reads a price
|
|
46
|
+
* you already have. A venue that does not quote the currency is skipped rather
|
|
47
|
+
* than fatal, which for CZK leaves Coinbase and Coinmate.
|
|
48
|
+
*
|
|
49
|
+
* The middle is taken rather than the mean so one stuck venue moves the answer by
|
|
50
|
+
* nothing instead of by half its error, and the spread check is what catches the
|
|
51
|
+
* stuck venue that stays inside the pack.
|
|
52
|
+
*/
|
|
53
|
+
declare function medianOf(tickers?: Ticker[], options?: MedianOptions): Ticker;
|
|
54
|
+
/**
|
|
55
|
+
* What to ask for over Lightning for a price named in fiat, in millisatoshi.
|
|
56
|
+
*
|
|
57
|
+
* `priceMinorPerBtc` is what a `Ticker` returns. The arithmetic is exact, in
|
|
58
|
+
* BigInt, because a million crown order times a hundred billion millisatoshi
|
|
59
|
+
* leaves what a double can count, and it rounds up, because the extra
|
|
60
|
+
* millisatoshi is worth nothing and belongs to the recipient rather than to a
|
|
61
|
+
* rounding rule.
|
|
62
|
+
*
|
|
63
|
+
* `spreadBps` is yours to set, in basis points, and defaults to none. A Lightning
|
|
64
|
+
* invoice lives an hour and a bank transfer takes days, so a shop pricing in fiat is
|
|
65
|
+
* carrying that volatility whether or not it charges for it
|
|
66
|
+
*/
|
|
67
|
+
declare function msatFor(amountMinor: number, priceMinorPerBtc: number, options?: {
|
|
68
|
+
spreadBps?: number;
|
|
69
|
+
}): number;
|
|
70
|
+
|
|
71
|
+
declare const brand: unique symbol;
|
|
72
|
+
/**
|
|
73
|
+
* A whole number of millisatoshi that came from `sats`, `msat` or `fiat`, and
|
|
74
|
+
* could not have come from anywhere else.
|
|
75
|
+
*
|
|
76
|
+
* The brand is why: a bare number is not one of these, so `21` cannot be passed
|
|
77
|
+
* where a price is wanted and quietly mean twenty-one thousandths of a satoshi.
|
|
78
|
+
* It costs nothing at runtime, where the value is an ordinary number
|
|
79
|
+
*/
|
|
80
|
+
type Msat = number & {
|
|
81
|
+
readonly [brand]: "Msat";
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* What a payment is worth. A `Msat` is a price known now, and a function is one
|
|
85
|
+
* worked out when the invoice is minted, which is what a fiat price has to be.
|
|
86
|
+
*
|
|
87
|
+
* Build one with `sats`, `msat` or `fiat`
|
|
88
|
+
*/
|
|
89
|
+
type Amount = Msat | (() => Msat | Promise<Msat>);
|
|
90
|
+
/** How a fiat price is turned into millisatoshi at the moment of minting */
|
|
91
|
+
interface FiatOptions {
|
|
92
|
+
/**
|
|
93
|
+
* Where the rate comes from, the median of the four MiCA authorised venues by
|
|
94
|
+
* default. Pass your own to price off one venue, off your own book, or off a
|
|
95
|
+
* number you already hold
|
|
96
|
+
*/
|
|
97
|
+
rate?: Ticker;
|
|
98
|
+
/**
|
|
99
|
+
* What you add over the rate, in basis points, none by default. A Lightning
|
|
100
|
+
* invoice lives an hour and a bank transfer takes days, so a shop pricing in
|
|
101
|
+
* fiat carries that volatility whether or not it charges for it
|
|
102
|
+
*/
|
|
103
|
+
spreadBps?: number;
|
|
104
|
+
}
|
|
105
|
+
/** A whole number of satoshi, so `sats(21)` is 21000 millisatoshi */
|
|
106
|
+
declare function sats(whole: number): Msat;
|
|
107
|
+
/** An exact number of millisatoshi, for a price already in the smallest unit */
|
|
108
|
+
declare function msat(exact: number): Msat;
|
|
109
|
+
/**
|
|
110
|
+
* A price named in fiat, converted when the invoice is minted rather than now.
|
|
111
|
+
*
|
|
112
|
+
* Name it as a string and it is read digit by digit, exactly. Name it as a
|
|
113
|
+
* number and it is rounded to the currency's ISO 4217 minor unit, because
|
|
114
|
+
* binary floating point cannot hold 4.99 and a payment library that pretends
|
|
115
|
+
* otherwise moves the wrong amount.
|
|
116
|
+
*
|
|
117
|
+
* Every conversion asks the rate afresh, so two calls a second apart can
|
|
118
|
+
* differ. That is the honest behaviour for a fiat price, and the reason an
|
|
119
|
+
* amount is a function rather than a number.
|
|
120
|
+
*
|
|
121
|
+
* The answer is rounded up to a whole satoshi, because a wallet issues an
|
|
122
|
+
* invoice in satoshi and refuses a fraction of one. Up rather than down, so the
|
|
123
|
+
* rounding is never the shop's loss. `msatFor` is the raw conversion, for a rail
|
|
124
|
+
* that has no invoice to round for
|
|
125
|
+
*/
|
|
126
|
+
declare function fiat(major: number | string, currency: string, options?: FiatOptions): () => Promise<Msat>;
|
|
127
|
+
|
|
128
|
+
/** Where a payment stands, `paid` is the only status that carries a preimage */
|
|
129
|
+
type PaymentStatus = "pending" | "paid" | "expired";
|
|
130
|
+
interface Reported {
|
|
131
|
+
id: string;
|
|
132
|
+
status: PaymentStatus;
|
|
133
|
+
paymentHash: string;
|
|
134
|
+
verifyUrl: string;
|
|
135
|
+
preimage: string | null;
|
|
136
|
+
expiresAt: number;
|
|
137
|
+
createdAt: number;
|
|
138
|
+
/** What the watcher needs and the gateway cannot read, `unseal` opens it */
|
|
139
|
+
sealed: string | null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A payment the gateway minted. It resolved the address itself, so it knows who
|
|
143
|
+
* is paid, how much, and which invoice says so, and none of the three can be
|
|
144
|
+
* null here
|
|
145
|
+
*/
|
|
146
|
+
interface MintedPayment extends Reported {
|
|
147
|
+
kind: "minted";
|
|
148
|
+
lnAddress: string;
|
|
149
|
+
amountMsat: number;
|
|
150
|
+
bolt11: string;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* A payment the gateway was handed rather than asked to mint. It was told a hash,
|
|
154
|
+
* a URL and an expiry and nothing else, which is the point of `watch`, so the
|
|
155
|
+
* address, the amount and the invoice are all absent rather than merely unknown
|
|
156
|
+
*/
|
|
157
|
+
interface WatchedPayment extends Reported {
|
|
158
|
+
kind: "watched";
|
|
159
|
+
lnAddress: null;
|
|
160
|
+
amountMsat: null;
|
|
161
|
+
bolt11: null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A payment as the gateway reports it, of either sort. Check `kind` and the
|
|
165
|
+
* three fields a watched payment does not carry stop being null, so nothing here
|
|
166
|
+
* needs an assertion to read
|
|
167
|
+
*/
|
|
168
|
+
type Payment = MintedPayment | WatchedPayment;
|
|
169
|
+
/**
|
|
170
|
+
* A payment as the caller already knows it: what the gateway calls it and the
|
|
171
|
+
* hash it settles against. Every `Payment` is one, and a caller reading back
|
|
172
|
+
* after a restart builds one from the two fields it stored
|
|
173
|
+
*/
|
|
174
|
+
interface Held {
|
|
175
|
+
id: string;
|
|
176
|
+
paymentHash: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Who is paid and how much. `to` is a priority list when it is an array: the
|
|
180
|
+
* gateway takes the first address that can issue a provable invoice for the
|
|
181
|
+
* amount and the rest are the fallback
|
|
182
|
+
*/
|
|
183
|
+
interface Charge {
|
|
184
|
+
paidTo: string | string[];
|
|
185
|
+
amount: Amount;
|
|
186
|
+
/** Where the gateway posts the settlement, signed with the key it publishes */
|
|
187
|
+
webhookUrl?: string;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* A charge with its price settled, which is what a proof compares the gateway's
|
|
191
|
+
* answer against. Asking a fiat price twice gives two numbers, so the proof is
|
|
192
|
+
* handed the one that was actually asked for
|
|
193
|
+
*/
|
|
194
|
+
interface Priced {
|
|
195
|
+
paidTo: string[];
|
|
196
|
+
amountMsat: number;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* An invoice you obtained yourself, handed over to be watched. The gateway is
|
|
200
|
+
* given no address and no amount, so it cannot refuse one recipient rather than
|
|
201
|
+
* all of them
|
|
202
|
+
*/
|
|
203
|
+
interface Handover {
|
|
204
|
+
paymentHash: string;
|
|
205
|
+
verifyUrl: string;
|
|
206
|
+
expiresAt: number;
|
|
207
|
+
/** Groups this payment with every other one carrying the same secret */
|
|
208
|
+
trigger?: string;
|
|
209
|
+
/**
|
|
210
|
+
* How many of this trigger's settlements the gateway keeps replayable past the
|
|
211
|
+
* hour it would otherwise forget them in, up to the ceiling its operator set.
|
|
212
|
+
* Needs `trigger`, defaults to none
|
|
213
|
+
*/
|
|
214
|
+
replay?: number;
|
|
215
|
+
/** Sealed with `seal` for this payment hash, so the gateway stores what it cannot read or move */
|
|
216
|
+
sealed?: string;
|
|
217
|
+
webhookUrl?: string;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Which address would serve an amount, and what the ones ahead of it refused.
|
|
221
|
+
* `feeMsat` is always zero, the payer pays the recipient's own invoice and the
|
|
222
|
+
* gateway is never in the money's path
|
|
223
|
+
*/
|
|
224
|
+
interface Quote {
|
|
225
|
+
lnAddress: string;
|
|
226
|
+
amountMsat: number;
|
|
227
|
+
feeMsat: number;
|
|
228
|
+
minMsat: number;
|
|
229
|
+
maxMsat: number;
|
|
230
|
+
metadata: string;
|
|
231
|
+
refusals: WalletFailure[];
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* A one minute pass onto one trigger's stream. It opens that trigger and nothing
|
|
235
|
+
* else, which is what makes it the thing to hand a browser when the trigger
|
|
236
|
+
* secret is not. `expiresAt` is unix seconds, like every other time here
|
|
237
|
+
*/
|
|
238
|
+
interface SocketTicket {
|
|
239
|
+
ticket: string;
|
|
240
|
+
expiresAt: number;
|
|
241
|
+
}
|
|
242
|
+
/** Why one wallet in the list could not be used */
|
|
243
|
+
type WalletReason = "address-unusable" | "unreachable" | "amount-not-accepted" | "cannot-prove-delivery" | "invoice-refused";
|
|
244
|
+
/** One wallet on the list that could not be used, and the reason it could not */
|
|
245
|
+
interface WalletFailure {
|
|
246
|
+
address: string;
|
|
247
|
+
reason: WalletReason;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* What a delivery carries. Everything needed to act on a settlement and to check
|
|
251
|
+
* it, and nothing else, so a retry is the same size every time
|
|
252
|
+
*/
|
|
253
|
+
interface Settlement {
|
|
254
|
+
id: string;
|
|
255
|
+
status: PaymentStatus;
|
|
256
|
+
paymentHash: string;
|
|
257
|
+
preimage: string | null;
|
|
258
|
+
settledAt: number;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export { type Amount as A, type Charge as C, type FiatOptions as F, type Handover as H, type MedianOptions as M, type Payment as P, type Quote as Q, type Settlement as S, type Ticker as T, type WalletFailure as W, coinmate as a, bitstamp as b, coinbase as c, msatFor as d, type Held as e, type MintedPayment as f, type Msat as g, type PaymentStatus as h, type Priced as i, type SocketTicket as j, kraken as k, type WalletReason as l, medianOf as m, type WatchedPayment as n, fiat as o, msat as p, sats as s };
|
package/openapi.yaml
CHANGED
|
@@ -2,7 +2,7 @@ openapi: 3.1.0
|
|
|
2
2
|
|
|
3
3
|
info:
|
|
4
4
|
title: thunder-bridge, the endpoint your own service serves
|
|
5
|
-
version: 1.
|
|
5
|
+
version: 2.1.1
|
|
6
6
|
license:
|
|
7
7
|
name: MIT
|
|
8
8
|
identifier: MIT
|
|
@@ -71,14 +71,17 @@ paths:
|
|
|
71
71
|
summary: Quote the price, or mint the invoice for a quote already given
|
|
72
72
|
description: |
|
|
73
73
|
Without `to` this answers the payRequest. It calls your `amountMsat()` once, quotes
|
|
74
|
-
your address list through the gateway
|
|
75
|
-
|
|
74
|
+
your address list, through the gateway or by itself when the trigger is blind, and
|
|
75
|
+
returns the first address that answers and accepts the amount, along with that
|
|
76
|
+
wallet's own LUD-06 metadata string byte for byte. A quote naming an address you did
|
|
77
|
+
not list is refused, so a gateway cannot put its own address in front of your payers.
|
|
76
78
|
`minSendable` and `maxSendable` are both the price, so the payer's wallet offers no
|
|
77
79
|
amount field and the payment is exactly what you asked for.
|
|
78
80
|
|
|
79
81
|
With `to` this is the callback. The signature is checked first, and a request that was
|
|
80
82
|
not signed by this service is refused before anything is minted, which is what stops a
|
|
81
|
-
stranger making your endpoint mint invoices on wallets of their choosing.
|
|
83
|
+
stranger making your endpoint mint invoices on wallets of their choosing. An address
|
|
84
|
+
you have since taken off the list is refused too, signed or not. The invoice
|
|
82
85
|
then comes from the recipient's own wallet, never from this service and never from the
|
|
83
86
|
gateway, and `verify` on the answer points at that recipient's LUD-21 endpoint.
|
|
84
87
|
|
|
@@ -200,48 +203,35 @@ paths:
|
|
|
200
203
|
operationId: verifyBankTransfer
|
|
201
204
|
summary: Say whether the transfer landed, and release the preimage when it did
|
|
202
205
|
description: |
|
|
203
|
-
Mounted wherever you passed `verifyUrl` to `bankTransfer`, which
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
Mounted wherever you passed `verifyUrl` to `bankTransfer`, which seals what to look for
|
|
207
|
+
into the query. The gateway polls this exactly as it polls a wallet's LUD-21 endpoint,
|
|
208
|
+
and it cannot tell the difference, which is the whole point.
|
|
206
209
|
|
|
207
|
-
A query this service did not
|
|
208
|
-
answer "did anyone send you this amount
|
|
209
|
-
bank statement handed out one question at
|
|
210
|
+
A query this service did not seal is refused, and so is one sealed for another
|
|
211
|
+
account. Without that check the endpoint would answer "did anyone send you this amount
|
|
212
|
+
with this note" to whoever asked, which is a bank statement handed out one question at
|
|
213
|
+
a time.
|
|
210
214
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
215
|
+
A credit pays when its amount and currency match exactly and the reference stands as a
|
|
216
|
+
whole word in what the payer wrote, across every field the bank puts a note in, so
|
|
217
|
+
noise around it is fine. A credit that also names another reference shaped like it, a
|
|
218
|
+
second order number of the same kind, pays neither.
|
|
219
|
+
|
|
220
|
+
The preimage is an HMAC of the account, the amount, the currency, the expiry and the
|
|
221
|
+
reference under a secret only this service holds, so the gateway can check it hashes to
|
|
222
|
+
what it was given and still cannot produce it, and a second order under the same
|
|
223
|
+
reference is another payment. Nothing is stored between calls.
|
|
214
224
|
parameters:
|
|
215
|
-
- name:
|
|
225
|
+
- name: q
|
|
216
226
|
in: query
|
|
217
227
|
required: true
|
|
218
228
|
description: |
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
type: string
|
|
223
|
-
- name: minor
|
|
224
|
-
in: query
|
|
225
|
-
required: true
|
|
226
|
-
description: The price in the smallest unit of the currency, so 48055 is 480.55 CZK.
|
|
227
|
-
schema:
|
|
228
|
-
type: integer
|
|
229
|
-
minimum: 1
|
|
230
|
-
- name: cc
|
|
231
|
-
in: query
|
|
232
|
-
required: true
|
|
233
|
-
description: The three letter currency code the credit has to be in.
|
|
229
|
+
One blob sealed by `bankTransfer` under the rail secret, naming the account, the
|
|
230
|
+
amount in minor units, the currency, the expiry and the reference. Padded to one
|
|
231
|
+
size class, so its length says nothing about what it carries.
|
|
234
232
|
schema:
|
|
235
233
|
type: string
|
|
236
|
-
|
|
237
|
-
maxLength: 3
|
|
238
|
-
- name: sig
|
|
239
|
-
in: query
|
|
240
|
-
required: true
|
|
241
|
-
description: Hex HMAC-SHA256 over `<ref>|<minor>|<cc>`, minted by `bankTransfer`.
|
|
242
|
-
schema:
|
|
243
|
-
type: string
|
|
244
|
-
pattern: "^[0-9a-f]{64}$"
|
|
234
|
+
pattern: "^v2\\."
|
|
245
235
|
responses:
|
|
246
236
|
"200":
|
|
247
237
|
description: |
|
|
@@ -258,7 +248,7 @@ paths:
|
|
|
258
248
|
schema:
|
|
259
249
|
$ref: "#/components/schemas/unsettled"
|
|
260
250
|
"403":
|
|
261
|
-
description: The
|
|
251
|
+
description: The blob does not open under this service's secret, or was sealed for another account, so it never asked the question.
|
|
262
252
|
content:
|
|
263
253
|
application/json:
|
|
264
254
|
schema:
|