@atomiqlabs/lp-lib 10.3.11 → 11.0.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.
Files changed (94) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +2 -4
  3. package/dist/plugins/IPlugin.d.ts +3 -2
  4. package/dist/plugins/PluginManager.d.ts +3 -2
  5. package/dist/plugins/PluginManager.js +2 -2
  6. package/dist/swaps/FromBtcBaseSwap.d.ts +5 -1
  7. package/dist/swaps/FromBtcBaseSwap.js +20 -0
  8. package/dist/swaps/FromBtcBaseSwapHandler.d.ts +1 -0
  9. package/dist/swaps/FromBtcBaseSwapHandler.js +1 -1
  10. package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +8 -6
  11. package/dist/swaps/FromBtcLnBaseSwapHandler.js +7 -5
  12. package/dist/swaps/SwapHandler.d.ts +1 -4
  13. package/dist/swaps/SwapHandler.js +1 -2
  14. package/dist/swaps/SwapHandlerSwap.d.ts +4 -0
  15. package/dist/swaps/SwapHandlerSwap.js +9 -1
  16. package/dist/swaps/ToBtcBaseSwap.d.ts +3 -1
  17. package/dist/swaps/ToBtcBaseSwap.js +8 -2
  18. package/dist/swaps/ToBtcBaseSwapHandler.d.ts +1 -0
  19. package/dist/swaps/ToBtcBaseSwapHandler.js +1 -1
  20. package/dist/swaps/frombtc_abstract/FromBtcAbs.d.ts +3 -5
  21. package/dist/swaps/frombtc_abstract/FromBtcAbs.js +18 -25
  22. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.d.ts +1 -4
  23. package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.js +3 -16
  24. package/dist/swaps/frombtc_trusted/FromBtcTrusted.d.ts +6 -9
  25. package/dist/swaps/frombtc_trusted/FromBtcTrusted.js +238 -137
  26. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.d.ts +9 -6
  27. package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.js +15 -10
  28. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.d.ts +2 -2
  29. package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.js +42 -62
  30. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +1 -6
  31. package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.js +2 -14
  32. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.d.ts +3 -5
  33. package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.js +64 -80
  34. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.d.ts +1 -2
  35. package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.js +5 -8
  36. package/dist/swaps/tobtc_abstract/ToBtcAbs.d.ts +5 -125
  37. package/dist/swaps/tobtc_abstract/ToBtcAbs.js +41 -334
  38. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.d.ts +1 -4
  39. package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.js +2 -11
  40. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.d.ts +5 -55
  41. package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.js +152 -398
  42. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.d.ts +1 -6
  43. package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.js +2 -15
  44. package/dist/utils/Utils.d.ts +0 -10
  45. package/dist/utils/Utils.js +1 -34
  46. package/dist/wallets/IBitcoinWallet.d.ts +62 -0
  47. package/dist/wallets/IBitcoinWallet.js +2 -0
  48. package/dist/wallets/ILightningWallet.d.ts +118 -0
  49. package/dist/wallets/ILightningWallet.js +37 -0
  50. package/package.json +4 -9
  51. package/src/index.ts +3 -5
  52. package/src/plugins/IPlugin.ts +4 -2
  53. package/src/plugins/PluginManager.ts +6 -3
  54. package/src/swaps/FromBtcBaseSwap.ts +24 -1
  55. package/src/swaps/FromBtcBaseSwapHandler.ts +6 -2
  56. package/src/swaps/FromBtcLnBaseSwapHandler.ts +22 -6
  57. package/src/swaps/SwapHandler.ts +1 -8
  58. package/src/swaps/SwapHandlerSwap.ts +14 -1
  59. package/src/swaps/ToBtcBaseSwap.ts +12 -3
  60. package/src/swaps/ToBtcBaseSwapHandler.ts +6 -2
  61. package/src/swaps/frombtc_abstract/FromBtcAbs.ts +24 -28
  62. package/src/swaps/frombtc_abstract/FromBtcSwapAbs.ts +3 -18
  63. package/src/swaps/frombtc_trusted/FromBtcTrusted.ts +260 -159
  64. package/src/swaps/frombtc_trusted/FromBtcTrustedSwap.ts +22 -15
  65. package/src/swaps/frombtcln_abstract/FromBtcLnAbs.ts +69 -79
  66. package/src/swaps/frombtcln_abstract/FromBtcLnSwapAbs.ts +3 -20
  67. package/src/swaps/frombtcln_trusted/FromBtcLnTrusted.ts +80 -97
  68. package/src/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.ts +6 -9
  69. package/src/swaps/tobtc_abstract/ToBtcAbs.ts +52 -410
  70. package/src/swaps/tobtc_abstract/ToBtcSwapAbs.ts +3 -18
  71. package/src/swaps/tobtcln_abstract/ToBtcLnAbs.ts +157 -434
  72. package/src/swaps/tobtcln_abstract/ToBtcLnSwapAbs.ts +3 -20
  73. package/src/utils/Utils.ts +0 -31
  74. package/src/wallets/IBitcoinWallet.ts +66 -0
  75. package/src/wallets/ILightningWallet.ts +179 -0
  76. package/dist/fees/OneDollarFeeEstimator.d.ts +0 -16
  77. package/dist/fees/OneDollarFeeEstimator.js +0 -71
  78. package/dist/utils/coinselect2/accumulative.d.ts +0 -6
  79. package/dist/utils/coinselect2/accumulative.js +0 -44
  80. package/dist/utils/coinselect2/blackjack.d.ts +0 -6
  81. package/dist/utils/coinselect2/blackjack.js +0 -41
  82. package/dist/utils/coinselect2/index.d.ts +0 -16
  83. package/dist/utils/coinselect2/index.js +0 -40
  84. package/dist/utils/coinselect2/utils.d.ts +0 -64
  85. package/dist/utils/coinselect2/utils.js +0 -121
  86. package/src/fees/OneDollarFeeEstimator.ts +0 -95
  87. package/src/utils/coinselect2/accumulative.js +0 -32
  88. package/src/utils/coinselect2/accumulative.ts +0 -58
  89. package/src/utils/coinselect2/blackjack.js +0 -29
  90. package/src/utils/coinselect2/blackjack.ts +0 -54
  91. package/src/utils/coinselect2/index.js +0 -16
  92. package/src/utils/coinselect2/index.ts +0 -50
  93. package/src/utils/coinselect2/utils.js +0 -110
  94. package/src/utils/coinselect2/utils.ts +0 -183
@@ -1,7 +1,5 @@
1
1
  import * as BN from "bn.js";
2
2
  import {Express, Request, Response} from "express";
3
- import * as bolt11 from "@atomiqlabs/bolt11";
4
- import * as lncli from "ln-service";
5
3
  import {ToBtcLnSwapAbs, ToBtcLnSwapState} from "./ToBtcLnSwapAbs";
6
4
  import {MultichainData, SwapHandlerType} from "../SwapHandler";
7
5
  import {ISwapPrice} from "../ISwapPrice";
@@ -13,8 +11,7 @@ import {
13
11
  SwapCommitStatus,
14
12
  SwapData
15
13
  } from "@atomiqlabs/base";
16
- import {AuthenticatedLnd} from "lightning";
17
- import {expressHandlerWrapper, handleLndError, HEX_REGEX, isDefinedRuntimeError} from "../../utils/Utils";
14
+ import {expressHandlerWrapper, HEX_REGEX, isDefinedRuntimeError} from "../../utils/Utils";
18
15
  import {PluginManager} from "../../plugins/PluginManager";
19
16
  import {IIntermediaryStorage} from "../../storage/IIntermediaryStorage";
20
17
  import {randomBytes} from "crypto";
@@ -23,7 +20,12 @@ import {IParamReader} from "../../utils/paramcoders/IParamReader";
23
20
  import {FieldTypeEnum, verifySchema} from "../../utils/paramcoders/SchemaVerifier";
24
21
  import {ServerParamEncoder} from "../../utils/paramcoders/server/ServerParamEncoder";
25
22
  import {ToBtcBaseConfig, ToBtcBaseSwapHandler} from "../ToBtcBaseSwapHandler";
26
- import {BlindedPayInfo} from "@atomiqlabs/bolt11";
23
+ import {
24
+ ILightningWallet,
25
+ OutgoingLightningNetworkPayment,
26
+ ParsedPaymentRequest, ProbeAndRouteInit,
27
+ ProbeAndRouteResponse, routesMatch
28
+ } from "../../wallets/ILightningWallet";
27
29
 
28
30
  export type ToBtcLnConfig = ToBtcBaseConfig & {
29
31
  routingFeeMultiplier: BN,
@@ -39,71 +41,13 @@ export type ToBtcLnConfig = ToBtcBaseConfig & {
39
41
  exactInExpiry?: number
40
42
  };
41
43
 
42
- const SNOWFLAKE_LIST: Set<string> = new Set([
43
- "038f8f113c580048d847d6949371726653e02b928196bad310e3eda39ff61723f6"
44
- ]);
45
-
46
- type ProbeAndRouteResponse = {
47
- confidence: number,
48
- fee: number,
49
- fee_mtokens: string,
50
- mtokens: string,
51
- payment: string,
52
- safe_fee: number,
53
- safe_tokens: number,
54
- timeout: number,
55
- tokens: number
56
- };
57
-
58
- type LNRoutes = {
59
- public_key: string,
60
- fee_rate?: number,
61
- cltv_delta?: number,
62
- channel?: string,
63
- base_fee_mtokens?: string
64
- }[][];
65
-
66
- function routesMatch(routesA: LNRoutes, routesB: LNRoutes) {
67
- if(routesA===routesB) return true;
68
- if(routesA==null || routesB==null) {
69
- return false;
70
- }
71
- if(routesA.length!==routesB.length) return false;
72
- for(let i=0;i<routesA.length;i++) {
73
- if(routesA[i]===routesB[i]) continue;
74
- if(routesA[i]==null || routesB[i]==null) {
75
- return false;
76
- }
77
- if(routesA[i].length!==routesB[i].length) return false;
78
- for(let e=0;e<routesA[i].length;e++) {
79
- if(routesA[i][e]===routesB[i][e]) continue;
80
- if(routesA[i][e]==null || routesB[i][e]==null) {
81
- return false;
82
- }
83
- if(
84
- routesA[i][e].public_key!==routesB[i][e].public_key ||
85
- routesA[i][e].base_fee_mtokens!==routesB[i][e].base_fee_mtokens ||
86
- routesA[i][e].channel!==routesB[i][e].channel ||
87
- routesA[i][e].cltv_delta!==routesB[i][e].cltv_delta ||
88
- routesA[i][e].fee_rate!==routesB[i][e].fee_rate
89
- ) {
90
- return false;
91
- }
92
- }
93
- }
94
-
95
- return true;
96
- }
97
-
98
44
  type ExactInAuthorization = {
99
45
  chainIdentifier: string,
100
46
  reqId: string,
101
47
  expiry: number,
102
48
 
103
49
  amount: BN,
104
- destination: string,
105
- cltvDelta: number,
106
- routes: LNRoutes,
50
+ initialInvoice: ParsedPaymentRequest,
107
51
 
108
52
  quotedNetworkFeeInToken: BN,
109
53
  swapFeeInToken: BN,
@@ -144,7 +88,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
144
88
 
145
89
  activeSubscriptions: Set<string> = new Set<string>();
146
90
  lightningLiquidityCache: {
147
- liquidityMTokens: BN,
91
+ liquidity: BN,
148
92
  timestamp: number
149
93
  };
150
94
 
@@ -156,15 +100,18 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
156
100
  [reqId: string]: ExactInAuthorization
157
101
  } = {};
158
102
 
103
+ readonly lightning: ILightningWallet;
104
+
159
105
  constructor(
160
106
  storageDirectory: IIntermediaryStorage<ToBtcLnSwapAbs>,
161
107
  path: string,
162
108
  chainData: MultichainData,
163
- lnd: AuthenticatedLnd,
109
+ lightning: ILightningWallet,
164
110
  swapPricing: ISwapPrice,
165
111
  config: ToBtcLnConfig
166
112
  ) {
167
- super(storageDirectory, path, chainData, lnd, swapPricing);
113
+ super(storageDirectory, path, chainData, swapPricing);
114
+ this.lightning = lightning;
168
115
  const anyConfig = config as any;
169
116
  anyConfig.minTsSendCltv = config.gracePeriod.add(config.bitcoinBlocktime.mul(config.minSendCltv).mul(config.safetyFactor));
170
117
  this.config = anyConfig;
@@ -173,24 +120,6 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
173
120
  this.config.exactInExpiry = this.config.exactInExpiry || 10*1000;
174
121
  }
175
122
 
176
- /**
177
- * Fetches the payment info, returns null if payment not found
178
- *
179
- * @param paymentHash
180
- * @private
181
- */
182
- private async getPayment(paymentHash: string): Promise<any> {
183
- try {
184
- return await lncli.getPayment({
185
- id: paymentHash,
186
- lnd: this.LND
187
- });
188
- } catch (e) {
189
- if (Array.isArray(e) && e[0] === 404 && e[1] === "SentPaymentNotFound") return null;
190
- throw e;
191
- }
192
- }
193
-
194
123
  /**
195
124
  * Cleans up exactIn authorization that are already past their expiry
196
125
  *
@@ -207,12 +136,11 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
207
136
  }
208
137
 
209
138
  protected async processPastSwap(swap: ToBtcLnSwapAbs): Promise<void> {
210
- //Current timestamp plus maximum allowed on-chain time skew
211
- const timestamp = new BN(Math.floor(Date.now()/1000)).sub(new BN(this.config.maxSkew));
139
+ const {swapContract, signer} = this.getChain(swap.chainIdentifier);
212
140
 
213
141
  if (swap.state === ToBtcLnSwapState.SAVED) {
214
142
  //Cancel the swaps where signature is expired
215
- const isSignatureExpired = swap.signatureExpiry!=null && swap.signatureExpiry.lt(timestamp);
143
+ const isSignatureExpired = await swapContract.isInitAuthorizationExpired(swap.data, swap);
216
144
  if(isSignatureExpired) {
217
145
  this.swapLogger.info(swap, "processPastSwap(state=SAVED): signature expired, cancel uncommited swap, invoice: "+swap.pr);
218
146
  await this.removeSwapData(swap, ToBtcLnSwapState.CANCELED);
@@ -220,8 +148,8 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
220
148
  }
221
149
 
222
150
  //Cancel the swaps where lightning invoice is expired
223
- const decodedPR = bolt11.decode(swap.pr);
224
- const isInvoiceExpired = decodedPR.timeExpireDate < Date.now() / 1000;
151
+ const decodedPR = await this.lightning.parsePaymentRequest(swap.pr);
152
+ const isInvoiceExpired = decodedPR.expiryEpochMillis < Date.now();
225
153
  if (isInvoiceExpired) {
226
154
  this.swapLogger.info(swap, "processPastSwap(state=SAVED): invoice expired, cancel uncommited swap, invoice: "+swap.pr);
227
155
  await this.removeSwapData(swap, ToBtcLnSwapState.CANCELED);
@@ -237,8 +165,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
237
165
  if (swap.state === ToBtcLnSwapState.NON_PAYABLE) {
238
166
  //Remove expired swaps (as these can already be unilaterally refunded by the client), so we don't need
239
167
  // to be able to cooperatively refund them
240
- const isSwapExpired = swap.data.getExpiry().lt(timestamp);
241
- if(isSwapExpired) {
168
+ if(swapContract.isExpired(signer.getAddress(), swap.data)) {
242
169
  this.swapLogger.info(swap, "processPastSwap(state=NON_PAYABLE): swap expired, removing swap data, invoice: "+swap.pr);
243
170
  await this.removeSwapData(swap);
244
171
  }
@@ -305,53 +232,51 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
305
232
  * @param swap
306
233
  * @param lnPaymentStatus
307
234
  */
308
- private async processPaymentResult(swap: ToBtcLnSwapAbs, lnPaymentStatus: {is_confirmed?: boolean, is_failed?: boolean, is_pending?: boolean, payment?: any}) {
309
- if(lnPaymentStatus.is_pending) {
310
- return;
311
- }
312
-
313
- if(lnPaymentStatus.is_failed) {
314
- this.swapLogger.info(swap, "processPaymentResult(): invoice payment failed, cancelling swap, invoice: "+swap.pr);
315
- await swap.setState(ToBtcLnSwapState.NON_PAYABLE);
316
- await this.storageManager.saveData(swap.data.getHash(), swap.data.getSequence(), swap);
317
- return;
318
- }
235
+ private async processPaymentResult(swap: ToBtcLnSwapAbs, lnPaymentStatus: OutgoingLightningNetworkPayment) {
236
+ switch(lnPaymentStatus.status) {
237
+ case "pending":
238
+ return;
319
239
 
320
- const {swapContract, signer} = this.getChain(swap.chainIdentifier);
240
+ case "failed":
241
+ this.swapLogger.info(swap, "processPaymentResult(): invoice payment failed, cancelling swap, invoice: "+swap.pr);
242
+ await swap.setState(ToBtcLnSwapState.NON_PAYABLE);
243
+ await this.storageManager.saveData(swap.data.getHash(), swap.data.getSequence(), swap);
244
+ return;
321
245
 
322
- if(lnPaymentStatus.is_confirmed) {
323
- //Save pre-image & real network fee
324
- swap.secret = lnPaymentStatus.payment.secret;
325
- swap.setRealNetworkFee(new BN(lnPaymentStatus.payment.fee_mtokens).div(new BN(1000)));
326
- this.swapLogger.info(swap, "processPaymentResult(): invoice paid, secret: "+swap.secret+" realRoutingFee: "+swap.realNetworkFee.toString(10)+" invoice: "+swap.pr);
327
- await swap.setState(ToBtcLnSwapState.PAID);
328
- await this.storageManager.saveData(swap.data.getHash(), swap.data.getSequence(), swap);
329
-
330
- //Check if escrow state exists
331
- const isCommited = await swapContract.isCommited(swap.data);
332
- if(!isCommited) {
333
- const status = await swapContract.getCommitStatus(signer.getAddress(), swap.data);
334
- if(status===SwapCommitStatus.PAID) {
335
- //This is alright, we got the money
336
- await this.removeSwapData(swap, ToBtcLnSwapState.CLAIMED);
246
+ case "confirmed":
247
+ const {swapContract, signer} = this.getChain(swap.chainIdentifier);
248
+
249
+ swap.secret = lnPaymentStatus.secret;
250
+ swap.setRealNetworkFee(lnPaymentStatus.feeMtokens.div(new BN(1000)));
251
+ this.swapLogger.info(swap, "processPaymentResult(): invoice paid, secret: "+swap.secret+" realRoutingFee: "+swap.realNetworkFee.toString(10)+" invoice: "+swap.pr);
252
+ await swap.setState(ToBtcLnSwapState.PAID);
253
+ await this.storageManager.saveData(swap.data.getHash(), swap.data.getSequence(), swap);
254
+
255
+ //Check if escrow state exists
256
+ const isCommited = await swapContract.isCommited(swap.data);
257
+ if(!isCommited) {
258
+ const status = await swapContract.getCommitStatus(signer.getAddress(), swap.data);
259
+ if(status===SwapCommitStatus.PAID) {
260
+ //This is alright, we got the money
261
+ await this.removeSwapData(swap, ToBtcLnSwapState.CLAIMED);
262
+ return;
263
+ } else if(status===SwapCommitStatus.EXPIRED) {
264
+ //This means the user was able to refund before we were able to claim, no good
265
+ await this.removeSwapData(swap, ToBtcLnSwapState.REFUNDED);
266
+ }
267
+ this.swapLogger.warn(swap, "processPaymentResult(): tried to claim but escrow doesn't exist anymore,"+
268
+ " status: "+status+
269
+ " invoice: "+swap.pr);
337
270
  return;
338
- } else if(status===SwapCommitStatus.EXPIRED) {
339
- //This means the user was able to refund before we were able to claim, no good
340
- await this.removeSwapData(swap, ToBtcLnSwapState.REFUNDED);
341
271
  }
342
- this.swapLogger.warn(swap, "processPaymentResult(): tried to claim but escrow doesn't exist anymore,"+
343
- " status: "+status+
344
- " invoice: "+swap.pr);
272
+
273
+ const success = await this.tryClaimSwap(swap);
274
+ if(success) this.swapLogger.info(swap, "processPaymentResult(): swap claimed successfully, invoice: "+swap.pr);
345
275
  return;
346
- }
347
276
 
348
- const success = await this.tryClaimSwap(swap);
349
- if(success) this.swapLogger.info(swap, "processPaymentResult(): swap claimed successfully, invoice: "+swap.pr);
350
- return;
277
+ default:
278
+ throw new Error("Invalid lnPaymentStatus");
351
279
  }
352
-
353
- //This should never happen
354
- throw new Error("Invalid lnPaymentStatus");
355
280
  }
356
281
 
357
282
  /**
@@ -363,25 +288,11 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
363
288
  const paymentHash = invoiceData.data.getHash();
364
289
  if(this.activeSubscriptions.has(paymentHash)) return false;
365
290
 
366
- const subscription = lncli.subscribeToPastPayment({id: paymentHash, lnd: this.LND});
367
-
368
- const onResult = (lnPaymentStatus: {is_confirmed?: boolean, is_failed?: boolean, payment?: any, error?: any}) => {
369
- const outcome = lnPaymentStatus.is_confirmed ? "success" : lnPaymentStatus.is_failed ? "failure" : null;
370
- this.swapLogger.info(invoiceData, "subscribeToPayment(): result callback, outcome: "+outcome+" invoice: "+invoiceData.pr);
371
- this.processPaymentResult(invoiceData, lnPaymentStatus).catch(e => this.swapLogger.error(invoiceData, "subscribeToPayment(): process payment result", e));
372
- subscription.removeAllListeners();
291
+ this.lightning.waitForPayment(paymentHash).then(result => {
292
+ this.swapLogger.info(invoiceData, "subscribeToPayment(): result callback, outcome: "+result.status+" invoice: "+invoiceData.pr);
293
+ this.processPaymentResult(invoiceData, result).catch(e => this.swapLogger.error(invoiceData, "subscribeToPayment(): process payment result", e));
373
294
  this.activeSubscriptions.delete(paymentHash);
374
- };
375
-
376
- subscription.on('confirmed', (payment) => onResult({
377
- is_confirmed: true,
378
- payment
379
- }));
380
- subscription.on('failed', (data) => onResult({
381
- is_failed: true,
382
- error: data
383
- }));
384
-
295
+ });
385
296
  this.swapLogger.info(invoiceData, "subscribeToPayment(): subscribe to payment outcome, invoice: "+invoiceData.pr);
386
297
 
387
298
  this.activeSubscriptions.add(paymentHash);
@@ -389,7 +300,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
389
300
  }
390
301
 
391
302
  private async sendLightningPayment(swap: ToBtcLnSwapAbs): Promise<void> {
392
- const decodedPR = bolt11.decode(swap.pr);
303
+ const decodedPR = await this.lightning.parsePaymentRequest(swap.pr);
393
304
  const expiryTimestamp: BN = swap.data.getExpiry();
394
305
  const currentTimestamp: BN = new BN(Math.floor(Date.now()/1000));
395
306
 
@@ -400,7 +311,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
400
311
  msg: "Not enough time to reliably pay the invoice"
401
312
  }
402
313
 
403
- const isInvoiceExpired = decodedPR.timeExpireDate < Date.now() / 1000;
314
+ const isInvoiceExpired = decodedPR.expiryEpochMillis < Date.now();
404
315
  if (isInvoiceExpired) throw {
405
316
  code: 90006,
406
317
  msg: "Invoice already expired"
@@ -411,23 +322,22 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
411
322
  const maxUsableCLTVdelta = expiryTimestamp.sub(currentTimestamp).sub(this.config.gracePeriod).div(this.config.bitcoinBlocktime.mul(this.config.safetyFactor));
412
323
 
413
324
  await swap.setState(ToBtcLnSwapState.COMMITED);
414
- await this.storageManager.saveData(decodedPR.tagsObject.payment_hash, swap.data.getSequence(), swap);
325
+ await this.storageManager.saveData(decodedPR.id, swap.data.getSequence(), swap);
415
326
 
416
327
  //Initiate payment
417
- const { current_block_height } = await lncli.getHeight({lnd: this.LND});
418
- const obj: any = {
419
- request: swap.pr,
420
- max_fee: maxFee.toString(10),
421
- max_timeout_height: new BN(current_block_height).add(maxUsableCLTVdelta).toString(10),
422
- lnd: this.LND
423
- };
424
328
  this.swapLogger.info(swap, "sendLightningPayment(): paying lightning network invoice,"+
425
329
  " cltvDelta: "+maxUsableCLTVdelta.toString(10)+
426
330
  " maxFee: "+maxFee.toString(10)+
427
331
  " invoice: "+swap.pr);
428
332
 
333
+ const blockHeight = await this.lightning.getBlockheight();
334
+
429
335
  try {
430
- await lncli.pay(obj)
336
+ await this.lightning.pay({
337
+ request: swap.pr,
338
+ maxFeeMtokens: maxFee.mul(new BN(1000)),
339
+ maxTimeoutHeight: blockHeight+maxUsableCLTVdelta.toNumber()
340
+ })
431
341
  } catch (e) {
432
342
  throw {
433
343
  code: 90007,
@@ -447,7 +357,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
447
357
  */
448
358
  private async processInitialized(swap: ToBtcLnSwapAbs) {
449
359
  //Check if payment was already made
450
- let lnPaymentStatus = await this.getPayment(swap.getHash());
360
+ let lnPaymentStatus = await this.lightning.getPayment(swap.getHash());
451
361
  if(swap.metadata!=null) swap.metadata.times.payPaymentChecked = Date.now();
452
362
 
453
363
  const paymentExists = lnPaymentStatus!=null;
@@ -467,7 +377,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
467
377
  return;
468
378
  }
469
379
 
470
- if(lnPaymentStatus.is_pending) {
380
+ if(lnPaymentStatus.status==="pending") {
471
381
  this.subscribeToPayment(swap);
472
382
  return;
473
383
  }
@@ -559,14 +469,14 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
559
469
  * @param pr
560
470
  * @throws {DefinedRuntimeError} will throw an error if the pr is invalid, without amount or expired
561
471
  */
562
- private checkPaymentRequest(pr: string): {
563
- parsedPR: bolt11.PaymentRequestObject & { tagsObject: bolt11.TagsObject },
472
+ private async checkPaymentRequest(pr: string): Promise<{
473
+ parsedPR: ParsedPaymentRequest,
564
474
  halfConfidence: boolean
565
- } {
566
- let parsedPR: bolt11.PaymentRequestObject & { tagsObject: bolt11.TagsObject };
475
+ }> {
476
+ let parsedPR: ParsedPaymentRequest;
567
477
 
568
478
  try {
569
- parsedPR = bolt11.decode(pr);
479
+ parsedPR = await this.lightning.parsePaymentRequest(pr);
570
480
  } catch (e) {
571
481
  throw {
572
482
  code: 20021,
@@ -574,19 +484,19 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
574
484
  };
575
485
  }
576
486
 
577
- if(parsedPR.millisatoshis==null) throw {
487
+ if(parsedPR.mtokens==null) throw {
578
488
  code: 20022,
579
489
  msg: "Invalid request body (pr - needs to have amount)"
580
490
  };
581
491
 
582
492
  let halfConfidence = false;
583
- if(parsedPR.timeExpireDate < ((Date.now()/1000)+(this.config.authorizationTimeout+(2*60)))) {
493
+ if(parsedPR.expiryEpochMillis < Date.now()+((this.config.authorizationTimeout+(2*60))*1000) ) {
584
494
  if(!this.config.allowShortExpiry) {
585
495
  throw {
586
496
  code: 20020,
587
497
  msg: "Invalid request body (pr - expired)"
588
498
  };
589
- } else if(parsedPR.timeExpireDate < Date.now()/1000) {
499
+ } else if(parsedPR.expiryEpochMillis < Date.now()) {
590
500
  throw {
591
501
  code: 20020,
592
502
  msg: "Invalid request body (pr - expired)"
@@ -623,7 +533,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
623
533
  * @throws {DefinedRuntimeError} will throw an error if payment already exists
624
534
  */
625
535
  private async checkPriorPayment(paymentHash: string, abortSignal: AbortSignal): Promise<void> {
626
- const payment = await this.getPayment(paymentHash);
536
+ const payment = await this.lightning.getPayment(paymentHash);
627
537
  if(payment!=null) throw {
628
538
  code: 20010,
629
539
  msg: "Already processed"
@@ -640,15 +550,14 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
640
550
  * @throws {DefinedRuntimeError} will throw an error if there isn't enough liquidity
641
551
  */
642
552
  private async checkLiquidity(amount: BN, abortSignal: AbortSignal, useCached: boolean = false): Promise<void> {
643
- const amountBDMtokens = amount.mul(new BN(1000));
644
553
  if(!useCached || this.lightningLiquidityCache==null || this.lightningLiquidityCache.timestamp<Date.now()-this.LIGHTNING_LIQUIDITY_CACHE_TIMEOUT) {
645
- const channelBalances = await lncli.getChannelBalance({lnd: this.LND});
554
+ const channelBalances = await this.lightning.getLightningBalance();
646
555
  this.lightningLiquidityCache = {
647
- liquidityMTokens: new BN(channelBalances.channel_balance_mtokens),
556
+ liquidity: channelBalances.localBalance,
648
557
  timestamp: Date.now()
649
558
  }
650
559
  }
651
- if(amountBDMtokens.gt(this.lightningLiquidityCache.liquidityMTokens)) {
560
+ if(amount.gt(this.lightningLiquidityCache.liquidity)) {
652
561
  throw {
653
562
  code: 20002,
654
563
  msg: "Not enough liquidity"
@@ -657,179 +566,6 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
657
566
  abortSignal.throwIfAborted();
658
567
  }
659
568
 
660
- /**
661
- * Computes the route paying to the specified bolt11 invoice, estimating the fee, uses bLIP-39 blinded paths
662
- *
663
- * @param amountSats
664
- * @param maxFee
665
- * @param parsedRequest
666
- * @param maxTimeoutBlockheight
667
- * @param metadata
668
- * @param maxUsableCLTV
669
- * @private
670
- */
671
- private async getRoutesInvoiceBLIP39(
672
- amountSats: BN,
673
- maxFee: BN,
674
- parsedRequest: {destination: string, cltv_delta: number, payment: string, routes: LNRoutes, blindedPaths?: BlindedPayInfo[]},
675
- maxTimeoutBlockheight: BN,
676
- metadata: any,
677
- maxUsableCLTV: BN
678
- ): Promise<ProbeAndRouteResponse> {
679
- metadata.routeReq = [];
680
- const routeReqs = parsedRequest.blindedPaths.map(async (blindedPath) => {
681
- if(new BN(blindedPath.cltv_expiry_delta+10).gt(maxUsableCLTV)) return null;
682
-
683
- const originalMsatAmount = amountSats.mul(new BN(1000));
684
- const blindedFeeTotalMsat = new BN(blindedPath.fee_base_msat)
685
- .add(originalMsatAmount.mul(new BN(blindedPath.fee_proportional_millionths)).div(new BN(1000000)));
686
-
687
- const routeReq = {
688
- destination: blindedPath.introduction_node,
689
- cltv_delta: Math.max(blindedPath.cltv_expiry_delta, parsedRequest.cltv_delta),
690
- mtokens: originalMsatAmount.add(blindedFeeTotalMsat).toString(10),
691
- max_fee_mtokens: maxFee.mul(new BN(1000)).sub(blindedFeeTotalMsat).toString(10),
692
- max_timeout_height: maxTimeoutBlockheight.toString(10),
693
- // total_mtokens: amountSats.mul(new BN(1000)).toString(10),
694
- routes: parsedRequest.routes,
695
- is_ignoring_past_failures: true,
696
- lnd: null
697
- };
698
- metadata.routeReq.push({...routeReq});
699
- routeReq.lnd = this.LND;
700
-
701
- let resp;
702
- try {
703
- resp = await lncli.getRouteToDestination(routeReq);
704
- } catch (e) {
705
- handleLndError(e);
706
- }
707
-
708
- if(resp==null || resp.route==null) return null;
709
-
710
- const adjustedFeeMsats = new BN(resp.route.fee_mtokens).add(blindedFeeTotalMsat);
711
- resp.route.fee_mtokens = adjustedFeeMsats.toString(10);
712
- resp.route.fee = adjustedFeeMsats.div(new BN(1000)).toNumber();
713
- resp.route.safe_fee = adjustedFeeMsats.add(new BN(999)).div(new BN(1000)).toNumber();
714
- const totalAdjustedMsats = new BN(routeReq.mtokens).add(blindedFeeTotalMsat);
715
- resp.route.mtokens = totalAdjustedMsats.toString(10);
716
- resp.route.tokens = totalAdjustedMsats.div(new BN(1000)).toNumber();
717
- resp.route.safe_tokens = totalAdjustedMsats.add(new BN(999)).div(new BN(1000)).toNumber();
718
-
719
- return resp.route as ProbeAndRouteResponse;
720
- });
721
-
722
- const responses = await Promise.all(routeReqs);
723
-
724
- metadata.routeResponsesBLIP39 = responses.map(resp => {return {...resp}});
725
-
726
- return responses.reduce((prev, current) => {
727
- if(prev==null) return current;
728
- if(current==null) return prev;
729
- current.fee_mtokens = BN.max(new BN(prev.fee_mtokens), new BN(current.fee_mtokens)).toString(10);
730
- current.fee = Math.max(prev.fee, current.fee);
731
- current.safe_fee = Math.max(prev.safe_fee, current.safe_fee);
732
- current.mtokens = BN.max(new BN(prev.mtokens), new BN(current.mtokens)).toString(10);
733
- current.tokens = Math.max(prev.tokens, current.tokens);
734
- current.safe_tokens = Math.max(prev.safe_tokens, current.safe_tokens);
735
- current.timeout = Math.max(prev.timeout, current.timeout);
736
- return current;
737
- });
738
- }
739
-
740
- /**
741
- * Computes the route paying to the specified bolt11 invoice, estimating the fee
742
- *
743
- * @param amountSats
744
- * @param maxFee
745
- * @param parsedRequest
746
- * @param maxTimeoutBlockheight
747
- * @param metadata
748
- * @param maxUsableCLTV
749
- * @private
750
- */
751
- private async getRoutesInvoice(
752
- amountSats: BN,
753
- maxFee: BN,
754
- parsedRequest: {destination: string, cltv_delta: number, payment: string, routes: LNRoutes, blindedPaths?: BlindedPayInfo[]},
755
- maxTimeoutBlockheight: BN,
756
- metadata: any,
757
- maxUsableCLTV: BN
758
- ): Promise<ProbeAndRouteResponse> {
759
- if(parsedRequest.blindedPaths!=null && parsedRequest.blindedPaths.length>0)
760
- return await this.getRoutesInvoiceBLIP39(amountSats, maxFee, parsedRequest, maxTimeoutBlockheight, metadata, maxUsableCLTV);
761
-
762
- const routesReq: any = {
763
- destination: parsedRequest.destination,
764
- cltv_delta: parsedRequest.cltv_delta,
765
- mtokens: amountSats.mul(new BN(1000)).toString(10),
766
- max_fee_mtokens: maxFee.mul(new BN(1000)).toString(10),
767
- payment: parsedRequest.payment,
768
- max_timeout_height: maxTimeoutBlockheight.toString(10),
769
- total_mtokens: amountSats.mul(new BN(1000)).toString(10),
770
- routes: parsedRequest.routes,
771
- is_ignoring_past_failures: true
772
- };
773
- metadata.routeReq = {...routesReq};
774
- routesReq.lnd = this.LND;
775
-
776
- let obj;
777
- try {
778
- obj = await lncli.getRouteToDestination(routesReq);
779
- } catch (e) {
780
- handleLndError(e);
781
- }
782
- return obj?.route==null ? null : obj.route;
783
- }
784
-
785
- /**
786
- * Sends a probe payment to the specified bolt11 invoice to check if it is reachable
787
- *
788
- * @param amountSats
789
- * @param maxFee
790
- * @param parsedRequest
791
- * @param maxTimeoutBlockheight
792
- * @param metadata
793
- * @private
794
- */
795
- private async probeInvoice(
796
- amountSats: BN,
797
- maxFee: BN,
798
- parsedRequest: {destination: string, cltv_delta: number, payment: string, routes: LNRoutes},
799
- maxTimeoutBlockheight: BN,
800
- metadata: any
801
- ): Promise<ProbeAndRouteResponse> {
802
- const probeReq: any = {
803
- destination: parsedRequest.destination,
804
- cltv_delta: parsedRequest.cltv_delta,
805
- mtokens: amountSats.mul(new BN(1000)).toString(10),
806
- max_fee_mtokens: maxFee.mul(new BN(1000)).toString(10),
807
- max_timeout_height: maxTimeoutBlockheight.toString(10),
808
- payment: parsedRequest.payment,
809
- total_mtokens: amountSats.mul(new BN(1000)).toString(10),
810
- routes: parsedRequest.routes
811
- };
812
- metadata.probeRequest = {...probeReq};
813
- probeReq.lnd = this.LND;
814
-
815
- let is_snowflake: boolean = false;
816
- if(parsedRequest.routes!=null) {
817
- for(let route of parsedRequest.routes) {
818
- if(SNOWFLAKE_LIST.has(route[0].public_key) || SNOWFLAKE_LIST.has(route[1].public_key)) {
819
- is_snowflake = true;
820
- }
821
- }
822
- }
823
-
824
- let obj;
825
- if(!is_snowflake) try {
826
- obj = await lncli.probeForRoute(probeReq);
827
- } catch (e) {
828
- handleLndError(e);
829
- }
830
- return obj?.route==null ? null : obj.route;
831
- }
832
-
833
569
  /**
834
570
  * Estimates the routing fee & confidence by either probing or routing (if probing fails), the fee is also adjusted
835
571
  * according to routing fee multiplier, and subject to minimums set in config
@@ -845,30 +581,27 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
845
581
  */
846
582
  private async checkAndGetNetworkFee(amountBD: BN, maxFee: BN, expiryTimestamp: BN, currentTimestamp: BN, pr: string, metadata: any, abortSignal: AbortSignal): Promise<{
847
583
  confidence: number,
848
- networkFee: BN,
849
- routes: LNRoutes
584
+ networkFee: BN
850
585
  }> {
851
586
  const maxUsableCLTV: BN = expiryTimestamp.sub(currentTimestamp).sub(this.config.gracePeriod).div(this.config.bitcoinBlocktime.mul(this.config.safetyFactor));
852
587
 
853
- const { current_block_height } = await lncli.getHeight({lnd: this.LND});
588
+ const blockHeight = await this.lightning.getBlockheight();
854
589
  abortSignal.throwIfAborted();
855
590
  metadata.times.blockheightFetched = Date.now();
856
591
 
857
- const maxTimeoutBlockheight = new BN(current_block_height).add(maxUsableCLTV);
858
- const parsedRequest = lncli.parsePaymentRequest({request: pr});
859
- const bolt11Parsed = bolt11.decode(pr);
860
- if(bolt11Parsed.tagsObject.blinded_payinfo!=null && bolt11Parsed.tagsObject.blinded_payinfo.length>0) {
861
- parsedRequest.blindedPaths = bolt11Parsed.tagsObject.blinded_payinfo;
862
- }
592
+ const maxTimeoutBlockheight = new BN(blockHeight).add(maxUsableCLTV);
863
593
 
864
- let probeOrRouteResp: ProbeAndRouteResponse;
594
+ const req: ProbeAndRouteInit = {
595
+ request: pr,
596
+ amountMtokens: amountBD.mul(new BN(1000)),
597
+ maxFeeMtokens: maxFee.mul(new BN(1000)),
598
+ maxTimeoutHeight: maxTimeoutBlockheight.toNumber()
599
+ };
865
600
 
866
- if(parsedRequest.blindedPaths==null) {
867
- probeOrRouteResp = await this.probeInvoice(amountBD, maxFee, parsedRequest, maxTimeoutBlockheight, metadata);
868
- metadata.times.probeResult = Date.now();
869
- metadata.probeResponse = {...probeOrRouteResp};
870
- abortSignal.throwIfAborted();
871
- }
601
+ let probeOrRouteResp: ProbeAndRouteResponse = await this.lightning.probe(req);
602
+ metadata.times.probeResult = Date.now();
603
+ metadata.probeResponse = {...probeOrRouteResp};
604
+ abortSignal.throwIfAborted();
872
605
 
873
606
  if(probeOrRouteResp==null) {
874
607
  if(!this.config.allowProbeFailedSwaps) throw {
@@ -876,7 +609,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
876
609
  msg: "Cannot route the payment!"
877
610
  };
878
611
 
879
- const routeResp = await this.getRoutesInvoice(amountBD, maxFee, parsedRequest, maxTimeoutBlockheight, metadata, maxUsableCLTV);
612
+ const routeResp = await this.lightning.route(req);
880
613
  metadata.times.routingResult = Date.now();
881
614
  metadata.routeResponse = {...routeResp};
882
615
  abortSignal.throwIfAborted();
@@ -887,20 +620,21 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
887
620
  };
888
621
 
889
622
  this.logger.info("checkAndGetNetworkFee(): routing result,"+
890
- " destination: "+parsedRequest.destination+
623
+ " destination: "+routeResp.destination+
891
624
  " confidence: "+routeResp.confidence+
892
- " safe fee: "+routeResp.safe_fee);
625
+ " fee mtokens: "+routeResp.feeMtokens.toString(10));
893
626
 
894
627
  probeOrRouteResp = routeResp;
895
- if(parsedRequest.blindedPaths==null) probeOrRouteResp.confidence = 0;
896
628
  } else {
897
629
  this.logger.info("checkAndGetNetworkFee(): route probed,"+
898
- " destination: "+parsedRequest.destination+
630
+ " destination: "+probeOrRouteResp.destination+
899
631
  " confidence: "+probeOrRouteResp.confidence+
900
- " safe fee: "+probeOrRouteResp.safe_fee);
632
+ " fee mtokens: "+probeOrRouteResp.feeMtokens.toString(10));
901
633
  }
902
634
 
903
- let actualRoutingFee: BN = new BN(probeOrRouteResp.safe_fee).mul(this.config.routingFeeMultiplier);
635
+ const safeFeeTokens = probeOrRouteResp.feeMtokens.add(new BN(999)).div(new BN(1000));
636
+
637
+ let actualRoutingFee: BN = safeFeeTokens.mul(this.config.routingFeeMultiplier);
904
638
 
905
639
  const minRoutingFee: BN = amountBD.mul(this.config.minLnRoutingFeePPM).div(new BN(1000000)).add(this.config.minLnBaseFee);
906
640
  if(actualRoutingFee.lt(minRoutingFee)) {
@@ -916,8 +650,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
916
650
 
917
651
  return {
918
652
  networkFee: actualRoutingFee,
919
- confidence: probeOrRouteResp.confidence,
920
- routes: parsedRequest.routes
653
+ confidence: probeOrRouteResp.confidence
921
654
  };
922
655
  }
923
656
 
@@ -954,14 +687,12 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
954
687
  * @throws {DefinedRuntimeError} will throw an error if the details don't match
955
688
  */
956
689
  private async checkPaymentRequestMatchesInitial(pr: string, parsedAuth: ExactInAuthorization): Promise<void> {
957
- const parsedRequest = await lncli.parsePaymentRequest({
958
- request: pr
959
- });
690
+ const parsedRequest = await this.lightning.parsePaymentRequest(pr);
960
691
 
961
692
  if(
962
- parsedRequest.destination!==parsedAuth.destination ||
963
- parsedRequest.cltv_delta!==parsedAuth.cltvDelta ||
964
- !new BN(parsedRequest.mtokens).eq(parsedAuth.amount.mul(new BN(1000)))
693
+ parsedRequest.destination!==parsedAuth.initialInvoice.destination ||
694
+ parsedRequest.cltvDelta!==parsedAuth.initialInvoice.cltvDelta ||
695
+ !parsedRequest.mtokens.eq(parsedAuth.amount.mul(new BN(1000)))
965
696
  ) {
966
697
  throw {
967
698
  code: 20102,
@@ -969,7 +700,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
969
700
  };
970
701
  }
971
702
 
972
- if(!routesMatch(parsedRequest.routes, parsedAuth.routes)) {
703
+ if(!routesMatch(parsedRequest.routes, parsedAuth.initialInvoice.routes)) {
973
704
  throw {
974
705
  code: 20102,
975
706
  msg: "Provided PR doesn't match initial (routes)!"
@@ -1003,7 +734,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1003
734
 
1004
735
  //Check request params
1005
736
  const parsedAuth = this.checkExactInAuthorization(parsedBody.reqId);
1006
- const {parsedPR, halfConfidence} = this.checkPaymentRequest(parsedBody.pr);
737
+ const {parsedPR, halfConfidence} = await this.checkPaymentRequest(parsedBody.pr);
1007
738
  await this.checkPaymentRequestMatchesInitial(parsedBody.pr, parsedAuth);
1008
739
 
1009
740
  const metadata = parsedAuth.metadata;
@@ -1019,7 +750,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1019
750
  signer.getAddress(),
1020
751
  parsedAuth.token,
1021
752
  parsedAuth.total,
1022
- parsedPR.tagsObject.payment_hash,
753
+ parsedPR.id,
1023
754
  sequence,
1024
755
  parsedAuth.swapExpiry,
1025
756
  new BN(0),
@@ -1040,21 +771,21 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1040
771
  const createdSwap = new ToBtcLnSwapAbs(
1041
772
  parsedAuth.chainIdentifier,
1042
773
  parsedBody.pr,
774
+ parsedPR.mtokens,
1043
775
  parsedAuth.swapFee,
1044
776
  parsedAuth.swapFeeInToken,
1045
777
  parsedAuth.quotedNetworkFee,
1046
- parsedAuth.quotedNetworkFeeInToken,
1047
- new BN(sigData.timeout)
778
+ parsedAuth.quotedNetworkFeeInToken
1048
779
  );
1049
780
  createdSwap.data = payObject;
1050
781
  createdSwap.metadata = metadata;
1051
782
 
1052
783
  await PluginManager.swapCreate(createdSwap);
1053
- await this.storageManager.saveData(parsedPR.tagsObject.payment_hash, sequence, createdSwap);
784
+ await this.storageManager.saveData(parsedPR.id, sequence, createdSwap);
1054
785
 
1055
786
  this.swapLogger.info(createdSwap, "REST: /payInvoiceExactIn: created exact in swap,"+
1056
787
  " reqId: "+parsedBody.reqId+
1057
- " amount: "+new BN(parsedPR.millisatoshis).div(new BN(1000)).toString(10)+
788
+ " mtokens: "+parsedPR.mtokens.toString(10)+
1058
789
  " invoice: "+createdSwap.pr);
1059
790
 
1060
791
  await responseStream.writeParamsAndEnd({
@@ -1144,10 +875,10 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1144
875
  this.checkMaxFee(parsedBody.maxFee);
1145
876
  this.checkExpiry(parsedBody.expiryTimestamp, currentTimestamp);
1146
877
  await this.checkVaultInitialized(chainIdentifier, parsedBody.token);
1147
- const {parsedPR, halfConfidence} = this.checkPaymentRequest(parsedBody.pr);
878
+ const {parsedPR, halfConfidence} = await this.checkPaymentRequest(parsedBody.pr);
1148
879
  const requestedAmount = {
1149
880
  input: !!parsedBody.exactIn,
1150
- amount: !!parsedBody.exactIn ? parsedBody.amount : new BN(parsedPR.millisatoshis).add(new BN(999)).div(new BN(1000))
881
+ amount: !!parsedBody.exactIn ? parsedBody.amount : parsedPR.mtokens.add(new BN(999)).div(new BN(1000))
1151
882
  };
1152
883
  const fees = await this.preCheckAmounts(request, requestedAmount, useToken);
1153
884
  metadata.times.requestChecked = Date.now();
@@ -1159,7 +890,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1159
890
  const {pricePrefetchPromise, signDataPrefetchPromise} = this.getToBtcPrefetches(chainIdentifier, useToken, responseStream, abortController);
1160
891
 
1161
892
  //Check if prior payment has been made
1162
- await this.checkPriorPayment(parsedPR.tagsObject.payment_hash, abortController.signal);
893
+ await this.checkPriorPayment(parsedPR.id, abortController.signal);
1163
894
  metadata.times.priorPaymentChecked = Date.now();
1164
895
 
1165
896
  //Check amounts
@@ -1192,9 +923,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1192
923
  expiry: Date.now() + this.config.exactInExpiry,
1193
924
 
1194
925
  amount: amountBD,
1195
- destination: parsedPR.payeeNodeKey,
1196
- cltvDelta: parsedPR.tagsObject.min_final_cltv_expiry,
1197
- routes: networkFeeData.routes,
926
+ initialInvoice: parsedPR,
1198
927
 
1199
928
  quotedNetworkFeeInToken: networkFeeInToken,
1200
929
  swapFeeInToken,
@@ -1214,7 +943,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1214
943
  this.logger.info("REST: /payInvoice: created exact in swap,"+
1215
944
  " reqId: "+reqId+
1216
945
  " amount: "+amountBD.toString(10)+
1217
- " destination: "+parsedPR.payeeNodeKey);
946
+ " destination: "+parsedPR.destination);
1218
947
 
1219
948
  await responseStream.writeParamsAndEnd({
1220
949
  code: 20000,
@@ -1236,7 +965,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1236
965
  signer.getAddress(),
1237
966
  useToken,
1238
967
  totalInToken,
1239
- parsedPR.tagsObject.payment_hash,
968
+ parsedPR.id,
1240
969
  sequence,
1241
970
  parsedBody.expiryTimestamp,
1242
971
  new BN(0),
@@ -1254,12 +983,24 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1254
983
  metadata.times.swapSigned = Date.now();
1255
984
 
1256
985
  //Create swap
1257
- const createdSwap = new ToBtcLnSwapAbs(chainIdentifier, parsedBody.pr, swapFee, swapFeeInToken, networkFeeData.networkFee, networkFeeInToken, new BN(sigData.timeout));
986
+ const createdSwap = new ToBtcLnSwapAbs(
987
+ chainIdentifier,
988
+ parsedBody.pr,
989
+ parsedPR.mtokens,
990
+ swapFee,
991
+ swapFeeInToken,
992
+ networkFeeData.networkFee,
993
+ networkFeeInToken
994
+ );
1258
995
  createdSwap.data = payObject;
1259
996
  createdSwap.metadata = metadata;
997
+ createdSwap.prefix = sigData.prefix;
998
+ createdSwap.timeout = sigData.timeout;
999
+ createdSwap.signature = sigData.signature
1000
+ createdSwap.feeRate = sigData.feeRate;
1260
1001
 
1261
1002
  await PluginManager.swapCreate(createdSwap);
1262
- await this.storageManager.saveData(parsedPR.tagsObject.payment_hash, sequence, createdSwap);
1003
+ await this.storageManager.saveData(parsedPR.id, sequence, createdSwap);
1263
1004
 
1264
1005
  this.swapLogger.info(createdSwap, "REST: /payInvoice: created swap,"+
1265
1006
  " amount: "+amountBD.toString(10)+
@@ -1309,14 +1050,14 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1309
1050
 
1310
1051
  const isSwapFound = data!=null;
1311
1052
  if(isSwapFound) {
1312
- const isExpired = data.data.getExpiry().lt(new BN(Math.floor(Date.now()/1000)).sub(new BN(this.config.maxSkew)));
1313
- if(isExpired) throw {
1053
+ const {signer, swapContract} = this.getChain(data.chainIdentifier);
1054
+
1055
+ if(swapContract.isExpired(signer.getAddress(), data.data)) throw {
1314
1056
  _httpStatus: 200,
1315
1057
  code: 20010,
1316
1058
  msg: "Payment expired"
1317
1059
  };
1318
1060
 
1319
- const {signer, swapContract} = this.getChain(data.chainIdentifier);
1320
1061
  if(data.state===ToBtcLnSwapState.NON_PAYABLE) {
1321
1062
  const refundSigData = await swapContract.getRefundSignature(signer, data.data, this.config.authorizationTimeout);
1322
1063
 
@@ -1342,7 +1083,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1342
1083
  }
1343
1084
  }
1344
1085
 
1345
- const payment = await this.getPayment(parsedBody.paymentHash);
1086
+ const payment = await this.lightning.getPayment(parsedBody.paymentHash);
1346
1087
 
1347
1088
  if(payment==null) throw {
1348
1089
  _httpStatus: 200,
@@ -1350,54 +1091,29 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1350
1091
  msg: "Payment not found"
1351
1092
  };
1352
1093
 
1353
- if(payment.is_pending) throw {
1094
+ if(payment.status==="pending") throw {
1354
1095
  _httpStatus: 200,
1355
1096
  code: 20008,
1356
1097
  msg: "Payment in-flight"
1357
1098
  };
1358
1099
 
1359
- if(payment.is_confirmed) throw {
1100
+ if(payment.status==="confirmed") throw {
1360
1101
  _httpStatus: 200,
1361
1102
  code: 20006,
1362
1103
  msg: "Already paid",
1363
1104
  data: {
1364
- secret: payment.payment.secret
1105
+ secret: payment.secret
1365
1106
  }
1366
1107
  };
1367
1108
 
1368
- if(payment.is_failed) throw {
1109
+ if(payment.status==="failed") throw {
1369
1110
  _httpStatus: 200,
1370
1111
  code: 20010,
1371
- msg: "Payment expired"
1112
+ msg: "Payment expired",
1113
+ data: {
1114
+ reason: payment.failedReason
1115
+ }
1372
1116
  };
1373
-
1374
- // NOTE: Fixed by not removing swap data until the HTLC is either expired, claimed or refunded.
1375
- // //TODO_old: Fix this by providing chain identifier as part of the invoice description, or maybe just do it the proper
1376
- // // way and just keep storing the data until the HTLC expiry
1377
- // if(payment.is_failed) {
1378
- // //TODO_old: This might not be the best idea with EVM chains
1379
- // const commitedData = await this.swapContract.getCommitedData(parsedBody.paymentHash);
1380
- //
1381
- // if(commitedData==null) throw {
1382
- // code: 20005,
1383
- // msg: "Not committed"
1384
- // };
1385
- //
1386
- // const refundSigData = await this.swapContract.getRefundSignature(commitedData, this.config.authorizationTimeout);
1387
- //
1388
- // this.swapLogger.info(commitedData, "REST: /getRefundAuthorization: returning refund authorization, because invoice payment failed");
1389
- //
1390
- // res.status(200).json({
1391
- // code: 20000,
1392
- // msg: "Success",
1393
- // data: {
1394
- // address: this.swapContract.getAddress(),
1395
- // prefix: refundSigData.prefix,
1396
- // timeout: refundSigData.timeout,
1397
- // signature: refundSigData.signature
1398
- // }
1399
- // });
1400
- // }
1401
1117
  });
1402
1118
 
1403
1119
  restServer.post(this.path+'/getRefundAuthorization', getRefundAuthorization);
@@ -1408,6 +1124,13 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
1408
1124
 
1409
1125
  async init() {
1410
1126
  await this.storageManager.loadData(ToBtcLnSwapAbs);
1127
+ //Check if all swaps contain a valid amount
1128
+ for(let swap of await this.storageManager.query([])) {
1129
+ if(swap.amount==null) {
1130
+ const parsedPR = await this.lightning.parsePaymentRequest(swap.pr);
1131
+ swap.amount = parsedPR.mtokens.add(new BN(999)).div(new BN(1000));
1132
+ }
1133
+ }
1411
1134
  this.subscribeToEvents();
1412
1135
  await PluginManager.serviceInitialize(this);
1413
1136
  }