@atomiqlabs/lp-lib 12.1.0 → 13.0.0-beta.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.
Files changed (119) hide show
  1. package/dist/index.d.ts +18 -13
  2. package/dist/index.js +18 -13
  3. package/dist/plugins/IPlugin.d.ts +35 -12
  4. package/dist/plugins/PluginManager.d.ts +38 -15
  5. package/dist/plugins/PluginManager.js +33 -9
  6. package/dist/prices/BinanceSwapPrice.d.ts +1 -1
  7. package/dist/prices/BinanceSwapPrice.js +1 -1
  8. package/dist/prices/CoinGeckoSwapPrice.d.ts +1 -1
  9. package/dist/prices/CoinGeckoSwapPrice.js +1 -1
  10. package/dist/{swaps → prices}/ISwapPrice.js +4 -0
  11. package/dist/prices/OKXSwapPrice.d.ts +1 -1
  12. package/dist/prices/OKXSwapPrice.js +1 -1
  13. package/dist/swaps/SwapHandler.d.ts +20 -58
  14. package/dist/swaps/SwapHandler.js +17 -186
  15. package/dist/swaps/SwapHandlerSwap.d.ts +8 -23
  16. package/dist/swaps/SwapHandlerSwap.js +7 -39
  17. package/dist/swaps/assertions/AmountAssertions.d.ts +28 -0
  18. package/dist/swaps/assertions/AmountAssertions.js +72 -0
  19. package/dist/swaps/assertions/FromBtcAmountAssertions.d.ts +76 -0
  20. package/dist/swaps/assertions/FromBtcAmountAssertions.js +162 -0
  21. package/dist/swaps/assertions/LightningAssertions.d.ts +44 -0
  22. package/dist/swaps/assertions/LightningAssertions.js +86 -0
  23. package/dist/swaps/assertions/ToBtcAmountAssertions.d.ts +53 -0
  24. package/dist/swaps/{ToBtcBaseSwapHandler.js → assertions/ToBtcAmountAssertions.js} +20 -94
  25. package/dist/swaps/escrow/EscrowHandler.d.ts +51 -0
  26. package/dist/swaps/escrow/EscrowHandler.js +158 -0
  27. package/dist/swaps/escrow/EscrowHandlerSwap.d.ts +35 -0
  28. package/dist/swaps/escrow/EscrowHandlerSwap.js +69 -0
  29. package/dist/swaps/{FromBtcBaseSwap.d.ts → escrow/FromBtcBaseSwap.d.ts} +2 -3
  30. package/dist/swaps/{FromBtcBaseSwap.js → escrow/FromBtcBaseSwap.js} +4 -7
  31. package/dist/swaps/{FromBtcBaseSwapHandler.d.ts → escrow/FromBtcBaseSwapHandler.d.ts} +10 -49
  32. package/dist/swaps/{FromBtcBaseSwapHandler.js → escrow/FromBtcBaseSwapHandler.js} +16 -137
  33. package/dist/swaps/{ToBtcBaseSwap.d.ts → escrow/ToBtcBaseSwap.d.ts} +2 -2
  34. package/dist/swaps/{ToBtcBaseSwap.js → escrow/ToBtcBaseSwap.js} +4 -4
  35. package/dist/swaps/escrow/ToBtcBaseSwapHandler.d.ts +53 -0
  36. package/dist/swaps/escrow/ToBtcBaseSwapHandler.js +81 -0
  37. package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.d.ts +4 -4
  38. package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.js +15 -15
  39. package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.js +1 -1
  40. package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.d.ts +9 -7
  41. package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.js +22 -19
  42. package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.js +3 -3
  43. package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.d.ts +4 -4
  44. package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.js +14 -13
  45. package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.js +3 -3
  46. package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.d.ts +6 -26
  47. package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.js +20 -57
  48. package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.js +3 -3
  49. package/dist/swaps/spv_vault_swap/SpvVault.d.ts +41 -0
  50. package/dist/swaps/spv_vault_swap/SpvVault.js +111 -0
  51. package/dist/swaps/spv_vault_swap/SpvVaultSwap.d.ts +63 -0
  52. package/dist/swaps/spv_vault_swap/SpvVaultSwap.js +145 -0
  53. package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.d.ts +68 -0
  54. package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.js +469 -0
  55. package/dist/swaps/spv_vault_swap/SpvVaults.d.ts +57 -0
  56. package/dist/swaps/spv_vault_swap/SpvVaults.js +369 -0
  57. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.d.ts +10 -13
  58. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.js +25 -30
  59. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.d.ts +9 -4
  60. package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.js +15 -7
  61. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.d.ts +12 -14
  62. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.js +33 -35
  63. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.d.ts +9 -4
  64. package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.js +17 -7
  65. package/dist/utils/Utils.d.ts +13 -5
  66. package/dist/utils/Utils.js +23 -1
  67. package/dist/wallets/IBitcoinWallet.d.ts +6 -0
  68. package/dist/wallets/ISpvVaultSigner.d.ts +7 -0
  69. package/dist/wallets/ISpvVaultSigner.js +2 -0
  70. package/dist/wallets/ISpvVaultWallet.d.ts +42 -0
  71. package/dist/wallets/ISpvVaultWallet.js +2 -0
  72. package/package.json +2 -2
  73. package/src/index.ts +21 -15
  74. package/src/plugins/IPlugin.ts +27 -19
  75. package/src/plugins/PluginManager.ts +51 -26
  76. package/src/prices/BinanceSwapPrice.ts +1 -1
  77. package/src/prices/CoinGeckoSwapPrice.ts +1 -1
  78. package/src/{swaps → prices}/ISwapPrice.ts +4 -0
  79. package/src/prices/OKXSwapPrice.ts +1 -1
  80. package/src/swaps/SwapHandler.ts +22 -205
  81. package/src/swaps/SwapHandlerSwap.ts +10 -46
  82. package/src/swaps/assertions/AmountAssertions.ts +77 -0
  83. package/src/swaps/assertions/FromBtcAmountAssertions.ts +228 -0
  84. package/src/swaps/assertions/LightningAssertions.ts +103 -0
  85. package/src/swaps/{ToBtcBaseSwapHandler.ts → assertions/ToBtcAmountAssertions.ts} +27 -142
  86. package/src/swaps/escrow/EscrowHandler.ts +179 -0
  87. package/src/swaps/escrow/EscrowHandlerSwap.ts +87 -0
  88. package/src/swaps/{FromBtcBaseSwap.ts → escrow/FromBtcBaseSwap.ts} +4 -8
  89. package/src/swaps/{FromBtcBaseSwapHandler.ts → escrow/FromBtcBaseSwapHandler.ts} +30 -190
  90. package/src/swaps/{ToBtcBaseSwap.ts → escrow/ToBtcBaseSwap.ts} +4 -5
  91. package/src/swaps/escrow/ToBtcBaseSwapHandler.ts +130 -0
  92. package/src/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.ts +20 -20
  93. package/src/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.ts +1 -1
  94. package/src/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.ts +29 -25
  95. package/src/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.ts +2 -2
  96. package/src/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.ts +19 -18
  97. package/src/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.ts +2 -2
  98. package/src/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.ts +26 -66
  99. package/src/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.ts +2 -2
  100. package/src/swaps/spv_vault_swap/SpvVault.ts +143 -0
  101. package/src/swaps/spv_vault_swap/SpvVaultSwap.ts +207 -0
  102. package/src/swaps/spv_vault_swap/SpvVaultSwapHandler.ts +606 -0
  103. package/src/swaps/spv_vault_swap/SpvVaults.ts +441 -0
  104. package/src/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.ts +36 -51
  105. package/src/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.ts +18 -8
  106. package/src/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.ts +43 -52
  107. package/src/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.ts +20 -8
  108. package/src/utils/Utils.ts +27 -1
  109. package/src/wallets/IBitcoinWallet.ts +4 -0
  110. package/src/wallets/ISpvVaultSigner.ts +11 -0
  111. package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +0 -26
  112. package/dist/swaps/FromBtcLnBaseSwapHandler.js +0 -46
  113. package/dist/swaps/ToBtcBaseSwapHandler.d.ts +0 -95
  114. package/src/swaps/FromBtcLnBaseSwapHandler.ts +0 -63
  115. /package/dist/{swaps → prices}/ISwapPrice.d.ts +0 -0
  116. /package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.d.ts +0 -0
  117. /package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.d.ts +0 -0
  118. /package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.d.ts +0 -0
  119. /package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.d.ts +0 -0
@@ -1,8 +1,8 @@
1
1
  import {Express, Request, Response} from "express";
2
2
  import {createHash, randomBytes} from "crypto";
3
3
  import {FromBtcLnSwapAbs, FromBtcLnSwapState} from "./FromBtcLnSwapAbs";
4
- import {MultichainData, SwapHandlerType} from "../SwapHandler";
5
- import {ISwapPrice} from "../ISwapPrice";
4
+ import {MultichainData, SwapHandlerType} from "../../SwapHandler";
5
+ import {ISwapPrice} from "../../../prices/ISwapPrice";
6
6
  import {
7
7
  BigIntBufferUtils,
8
8
  ChainSwapType,
@@ -11,21 +11,21 @@ import {
11
11
  RefundEvent,
12
12
  SwapData
13
13
  } from "@atomiqlabs/base";
14
- import {expressHandlerWrapper, HEX_REGEX, isDefinedRuntimeError} from "../../utils/Utils";
15
- import {PluginManager} from "../../plugins/PluginManager";
16
- import {IIntermediaryStorage} from "../../storage/IIntermediaryStorage";
17
- import {FieldTypeEnum, verifySchema} from "../../utils/paramcoders/SchemaVerifier";
18
- import {serverParamDecoder} from "../../utils/paramcoders/server/ServerParamDecoder";
19
- import {ServerParamEncoder} from "../../utils/paramcoders/server/ServerParamEncoder";
20
- import {IParamReader} from "../../utils/paramcoders/IParamReader";
21
- import {FromBtcBaseConfig} from "../FromBtcBaseSwapHandler";
22
- import {FromBtcLnBaseSwapHandler} from "../FromBtcLnBaseSwapHandler";
14
+ import {expressHandlerWrapper, getAbortController, HEX_REGEX, isDefinedRuntimeError} from "../../../utils/Utils";
15
+ import {PluginManager} from "../../../plugins/PluginManager";
16
+ import {IIntermediaryStorage} from "../../../storage/IIntermediaryStorage";
17
+ import {FieldTypeEnum, verifySchema} from "../../../utils/paramcoders/SchemaVerifier";
18
+ import {serverParamDecoder} from "../../../utils/paramcoders/server/ServerParamDecoder";
19
+ import {ServerParamEncoder} from "../../../utils/paramcoders/server/ServerParamEncoder";
20
+ import {IParamReader} from "../../../utils/paramcoders/IParamReader";
21
+ import {FromBtcBaseConfig, FromBtcBaseSwapHandler} from "../FromBtcBaseSwapHandler";
23
22
  import {
24
23
  HodlInvoiceInit,
25
24
  ILightningWallet,
26
25
  LightningNetworkChannel,
27
26
  LightningNetworkInvoice
28
- } from "../../wallets/ILightningWallet";
27
+ } from "../../../wallets/ILightningWallet";
28
+ import { LightningAssertions } from "../../assertions/LightningAssertions";
29
29
 
30
30
  export type FromBtcLnConfig = FromBtcBaseConfig & {
31
31
  invoiceTimeoutSeconds?: number,
@@ -45,11 +45,13 @@ export type FromBtcLnRequestType = {
45
45
  /**
46
46
  * Swap handler handling from BTCLN swaps using submarine swaps
47
47
  */
48
- export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, FromBtcLnSwapState> {
48
+ export class FromBtcLnAbs extends FromBtcBaseSwapHandler<FromBtcLnSwapAbs, FromBtcLnSwapState> {
49
49
  readonly type = SwapHandlerType.FROM_BTCLN;
50
50
  readonly swapType = ChainSwapType.HTLC;
51
51
 
52
52
  readonly config: FromBtcLnConfig;
53
+ readonly lightning: ILightningWallet;
54
+ readonly LightningAssertions: LightningAssertions;
53
55
 
54
56
  constructor(
55
57
  storageDirectory: IIntermediaryStorage<FromBtcLnSwapAbs>,
@@ -59,9 +61,11 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
59
61
  swapPricing: ISwapPrice,
60
62
  config: FromBtcLnConfig
61
63
  ) {
62
- super(storageDirectory, path, chains, lightning, swapPricing);
64
+ super(storageDirectory, path, chains, swapPricing, config);
63
65
  this.config = config;
64
66
  this.config.invoiceTimeoutSeconds = this.config.invoiceTimeoutSeconds || 90;
67
+ this.lightning = lightning;
68
+ this.LightningAssertions = new LightningAssertions(this.logger, lightning);
65
69
  }
66
70
 
67
71
  protected async processPastSwap(swap: FromBtcLnSwapAbs): Promise<"REFUND" | "SETTLE" | "CANCEL" | null> {
@@ -499,8 +503,8 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
499
503
  chainIdentifier = this.chains.default;
500
504
  address = invoice.description;
501
505
  }
502
- const {swapContract} = this.getChain(chainIdentifier);
503
- if(!swapContract.isValidAddress(address)) throw {
506
+ const {chainInterface} = this.getChain(chainIdentifier);
507
+ if(!chainInterface.isValidAddress(address)) throw {
504
508
  _httpStatus: 200,
505
509
  code: 10001,
506
510
  msg: "Invoice expired/canceled"
@@ -542,8 +546,8 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
542
546
  } = {request: {}, times: {}};
543
547
 
544
548
  const chainIdentifier = req.query.chain as string ?? this.chains.default;
545
- const {swapContract, signer} = this.getChain(chainIdentifier);
546
- const depositToken = req.query.depositToken as string ?? swapContract.getNativeCurrencyAddress();
549
+ const {swapContract, signer, chainInterface} = this.getChain(chainIdentifier);
550
+ const depositToken = req.query.depositToken as string ?? chainInterface.getNativeCurrencyAddress();
547
551
  this.checkAllowedDepositToken(chainIdentifier, depositToken);
548
552
 
549
553
  metadata.times.requestReceived = Date.now();
@@ -563,7 +567,7 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
563
567
  const parsedBody: FromBtcLnRequestType = await req.paramReader.getParams({
564
568
  address: (val: string) => val!=null &&
565
569
  typeof(val)==="string" &&
566
- swapContract.isValidAddress(val) ? val : null,
570
+ chainInterface.isValidAddress(val) ? val : null,
567
571
  paymentHash: (val: string) => val!=null &&
568
572
  typeof(val)==="string" &&
569
573
  val.length===64 &&
@@ -581,7 +585,7 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
581
585
  };
582
586
  metadata.request = parsedBody;
583
587
 
584
- const requestedAmount = {input: !parsedBody.exactOut, amount: parsedBody.amount};
588
+ const requestedAmount = {input: !parsedBody.exactOut, amount: parsedBody.amount, token: parsedBody.token};
585
589
  const request = {
586
590
  chainIdentifier,
587
591
  raw: req,
@@ -592,12 +596,12 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
592
596
 
593
597
  //Check request params
594
598
  this.checkDescriptionHash(parsedBody.descriptionHash);
595
- const fees = await this.preCheckAmounts(request, requestedAmount, useToken);
599
+ const fees = await this.AmountAssertions.preCheckFromBtcAmounts(this.type, request, requestedAmount);
596
600
  metadata.times.requestChecked = Date.now();
597
601
 
598
602
  //Create abortController for parallel prefetches
599
603
  const responseStream = res.responseStream;
600
- const abortController = this.getAbortController(responseStream);
604
+ const abortController = getAbortController(responseStream);
601
605
 
602
606
  //Pre-fetch data
603
607
  const {
@@ -606,7 +610,7 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
606
610
  depositTokenPricePrefetchPromise
607
611
  } = this.getFromBtcPricePrefetches(chainIdentifier, useToken, depositToken, abortController);
608
612
  const balancePrefetch: Promise<bigint> = this.getBalancePrefetch(chainIdentifier, useToken, abortController);
609
- const channelsPrefetch: Promise<LightningNetworkChannel[]> = this.getChannelsPrefetch(abortController);
613
+ const channelsPrefetch: Promise<LightningNetworkChannel[]> = this.LightningAssertions.getChannelsPrefetch(abortController);
610
614
 
611
615
  const dummySwapData = await this.getDummySwapData(chainIdentifier, useToken, parsedBody.address, parsedBody.paymentHash);
612
616
  abortController.signal.throwIfAborted();
@@ -627,7 +631,7 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
627
631
  totalInToken,
628
632
  securityDepositApyPPM,
629
633
  securityDepositBaseMultiplierPPM
630
- } = await this.checkFromBtcAmount(request, requestedAmount, fees, useToken, abortController.signal, pricePrefetchPromise);
634
+ } = await this.AmountAssertions.checkFromBtcAmount(this.type, request, {...requestedAmount, pricePrefetch: pricePrefetchPromise}, fees, abortController.signal);
631
635
  metadata.times.priceCalculated = Date.now();
632
636
 
633
637
  if(securityDepositApyPPM!=null) fees.securityDepositApyPPM = securityDepositApyPPM;
@@ -635,7 +639,7 @@ export class FromBtcLnAbs extends FromBtcLnBaseSwapHandler<FromBtcLnSwapAbs, Fro
635
639
 
636
640
  //Check if we have enough funds to honor the request
637
641
  await this.checkBalance(totalInToken, balancePrefetch, abortController.signal)
638
- await this.checkInboundLiquidity(amountBD, channelsPrefetch, abortController.signal);
642
+ await this.LightningAssertions.checkInboundLiquidity(amountBD, channelsPrefetch, abortController.signal);
639
643
  metadata.times.balanceChecked = Date.now();
640
644
 
641
645
  //Create swap
@@ -1,7 +1,7 @@
1
1
  import {SwapData} from "@atomiqlabs/base";
2
- import {SwapHandlerType} from "../..";
2
+ import {SwapHandlerType} from "../../../index";
3
3
  import {FromBtcBaseSwap} from "../FromBtcBaseSwap";
4
- import {deserializeBN, serializeBN} from "../../utils/Utils";
4
+ import {deserializeBN, serializeBN} from "../../../utils/Utils";
5
5
 
6
6
  export enum FromBtcLnSwapState {
7
7
  REFUNDED = -2,
@@ -1,7 +1,7 @@
1
1
  import {Express, Request, Response} from "express";
2
2
  import {ToBtcSwapAbs, ToBtcSwapState} from "./ToBtcSwapAbs";
3
- import {MultichainData, SwapHandlerType} from "../SwapHandler";
4
- import {ISwapPrice} from "../ISwapPrice";
3
+ import {MultichainData, SwapHandlerType} from "../../SwapHandler";
4
+ import {ISwapPrice} from "../../../prices/ISwapPrice";
5
5
  import {
6
6
  BtcTx,
7
7
  ChainSwapType,
@@ -13,17 +13,17 @@ import {
13
13
  BitcoinRpc,
14
14
  BtcBlock, BigIntBufferUtils
15
15
  } from "@atomiqlabs/base";
16
- import {expressHandlerWrapper, HEX_REGEX, isDefinedRuntimeError} from "../../utils/Utils";
17
- import {PluginManager} from "../../plugins/PluginManager";
18
- import {IIntermediaryStorage} from "../../storage/IIntermediaryStorage";
16
+ import {expressHandlerWrapper, getAbortController, HEX_REGEX, isDefinedRuntimeError} from "../../../utils/Utils";
17
+ import {PluginManager} from "../../../plugins/PluginManager";
18
+ import {IIntermediaryStorage} from "../../../storage/IIntermediaryStorage";
19
19
  import {randomBytes} from "crypto";
20
- import {FieldTypeEnum, verifySchema} from "../../utils/paramcoders/SchemaVerifier";
21
- import {serverParamDecoder} from "../../utils/paramcoders/server/ServerParamDecoder";
22
- import {IParamReader} from "../../utils/paramcoders/IParamReader";
23
- import {ServerParamEncoder} from "../../utils/paramcoders/server/ServerParamEncoder";
20
+ import {FieldTypeEnum, verifySchema} from "../../../utils/paramcoders/SchemaVerifier";
21
+ import {serverParamDecoder} from "../../../utils/paramcoders/server/ServerParamDecoder";
22
+ import {IParamReader} from "../../../utils/paramcoders/IParamReader";
23
+ import {ServerParamEncoder} from "../../../utils/paramcoders/server/ServerParamEncoder";
24
24
  import {ToBtcBaseConfig, ToBtcBaseSwapHandler} from "../ToBtcBaseSwapHandler";
25
25
  import {PromiseQueue} from "promise-queue-ts";
26
- import {IBitcoinWallet} from "../../wallets/IBitcoinWallet";
26
+ import {IBitcoinWallet} from "../../../wallets/IBitcoinWallet";
27
27
 
28
28
  const OUTPUT_SCRIPT_MAX_LENGTH = 200;
29
29
 
@@ -75,7 +75,7 @@ export class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState>
75
75
  bitcoinRpc: BitcoinRpc<BtcBlock>,
76
76
  config: ToBtcConfig
77
77
  ) {
78
- super(storageDirectory, path, chainData, swapPricing);
78
+ super(storageDirectory, path, chainData, swapPricing, config);
79
79
  this.bitcoinRpc = bitcoinRpc;
80
80
  this.bitcoin = bitcoin;
81
81
  this.config = config;
@@ -595,7 +595,7 @@ export class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState>
595
595
  } = {request: {}, times: {}};
596
596
 
597
597
  const chainIdentifier = req.query.chain as string ?? this.chains.default;
598
- const {swapContract, signer} = this.getChain(chainIdentifier);
598
+ const {swapContract, signer, chainInterface} = this.getChain(chainIdentifier);
599
599
 
600
600
  metadata.times.requestReceived = Date.now();
601
601
  /**
@@ -623,7 +623,7 @@ export class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState>
623
623
  this.isTokenSupported(chainIdentifier, val) ? val : null,
624
624
  offerer: (val: string) => val!=null &&
625
625
  typeof(val)==="string" &&
626
- swapContract.isValidAddress(val) ? val : null,
626
+ chainInterface.isValidAddress(val) ? val : null,
627
627
  exactIn: FieldTypeEnum.BooleanOptional
628
628
  });
629
629
  if (parsedBody==null) throw {
@@ -632,7 +632,7 @@ export class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState>
632
632
  };
633
633
  metadata.request = parsedBody;
634
634
 
635
- const requestedAmount = {input: !!parsedBody.exactIn, amount: parsedBody.amount};
635
+ const requestedAmount = {input: !!parsedBody.exactIn, amount: parsedBody.amount, token: parsedBody.token};
636
636
  const request = {
637
637
  chainIdentifier,
638
638
  raw: req,
@@ -648,12 +648,12 @@ export class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState>
648
648
  this.checkRequiredConfirmations(parsedBody.confirmations);
649
649
  this.checkAddress(parsedBody.address);
650
650
  await this.checkVaultInitialized(chainIdentifier, parsedBody.token);
651
- const fees = await this.preCheckAmounts(request, requestedAmount, useToken);
651
+ const fees = await this.AmountAssertions.preCheckToBtcAmounts(this.type, request, requestedAmount);
652
652
 
653
653
  metadata.times.requestChecked = Date.now();
654
654
 
655
655
  //Initialize abort controller for the parallel async operations
656
- const abortController = this.getAbortController(responseStream);
656
+ const abortController = getAbortController(responseStream);
657
657
 
658
658
  const {pricePrefetchPromise, signDataPrefetchPromise} = this.getToBtcPrefetches(chainIdentifier, useToken, responseStream, abortController);
659
659
 
@@ -664,12 +664,13 @@ export class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState>
664
664
  swapFee,
665
665
  swapFeeInToken,
666
666
  networkFeeInToken
667
- } = await this.checkToBtcAmount(request, requestedAmount, fees, useToken, async (amount: bigint) => {
667
+ } = await this.AmountAssertions.checkToBtcAmount(this.type, request, {...requestedAmount, pricePrefetch: pricePrefetchPromise}, fees, async (amount: bigint) => {
668
668
  metadata.times.amountsChecked = Date.now();
669
669
  const resp = await this.checkAndGetNetworkFee(parsedBody.address, amount);
670
+ this.logger.debug("checkToBtcAmount(): network fee calculated, amount: "+amount.toString(10)+" fee: "+resp.networkFee.toString(10));
670
671
  metadata.times.chainFeeCalculated = Date.now();
671
672
  return resp;
672
- }, abortController.signal, pricePrefetchPromise);
673
+ }, abortController.signal);
673
674
  metadata.times.priceCalculated = Date.now();
674
675
 
675
676
  const paymentHash = this.getHash(chainIdentifier, parsedBody.address, parsedBody.confirmations, parsedBody.nonce, amountBD).toString("hex");
@@ -1,7 +1,7 @@
1
1
  import {SwapData} from "@atomiqlabs/base";
2
- import {SwapHandlerType} from "../..";
2
+ import {SwapHandlerType} from "../../../index";
3
3
  import {ToBtcBaseSwap} from "../ToBtcBaseSwap";
4
- import {deserializeBN} from "../../utils/Utils";
4
+ import {deserializeBN} from "../../../utils/Utils";
5
5
 
6
6
  export enum ToBtcSwapState {
7
7
  REFUNDED = -3,
@@ -1,7 +1,7 @@
1
1
  import {Express, Request, Response} from "express";
2
2
  import {ToBtcLnSwapAbs, ToBtcLnSwapState} from "./ToBtcLnSwapAbs";
3
- import {MultichainData, SwapHandlerType} from "../SwapHandler";
4
- import {ISwapPrice} from "../ISwapPrice";
3
+ import {MultichainData, SwapHandlerType} from "../../SwapHandler";
4
+ import {ISwapPrice} from "../../../prices/ISwapPrice";
5
5
  import {
6
6
  BigIntBufferUtils,
7
7
  ChainSwapType,
@@ -11,14 +11,14 @@ import {
11
11
  SwapCommitStatus,
12
12
  SwapData
13
13
  } from "@atomiqlabs/base";
14
- import {expressHandlerWrapper, HEX_REGEX, isDefinedRuntimeError} from "../../utils/Utils";
15
- import {PluginManager} from "../../plugins/PluginManager";
16
- import {IIntermediaryStorage} from "../../storage/IIntermediaryStorage";
14
+ import {expressHandlerWrapper, getAbortController, HEX_REGEX, isDefinedRuntimeError} from "../../../utils/Utils";
15
+ import {PluginManager} from "../../../plugins/PluginManager";
16
+ import {IIntermediaryStorage} from "../../../storage/IIntermediaryStorage";
17
17
  import {randomBytes} from "crypto";
18
- import {serverParamDecoder} from "../../utils/paramcoders/server/ServerParamDecoder";
19
- import {IParamReader} from "../../utils/paramcoders/IParamReader";
20
- import {FieldTypeEnum, verifySchema} from "../../utils/paramcoders/SchemaVerifier";
21
- import {ServerParamEncoder} from "../../utils/paramcoders/server/ServerParamEncoder";
18
+ import {serverParamDecoder} from "../../../utils/paramcoders/server/ServerParamDecoder";
19
+ import {IParamReader} from "../../../utils/paramcoders/IParamReader";
20
+ import {FieldTypeEnum, verifySchema} from "../../../utils/paramcoders/SchemaVerifier";
21
+ import {ServerParamEncoder} from "../../../utils/paramcoders/server/ServerParamEncoder";
22
22
  import {ToBtcBaseConfig, ToBtcBaseSwapHandler} from "../ToBtcBaseSwapHandler";
23
23
  import {
24
24
  ILightningWallet,
@@ -27,7 +27,8 @@ import {
27
27
  ProbeAndRouteInit,
28
28
  ProbeAndRouteResponse,
29
29
  routesMatch
30
- } from "../../wallets/ILightningWallet";
30
+ } from "../../../wallets/ILightningWallet";
31
+ import { LightningAssertions } from "../../assertions/LightningAssertions";
31
32
 
32
33
  export type ToBtcLnConfig = ToBtcBaseConfig & {
33
34
  routingFeeMultiplier: bigint,
@@ -86,13 +87,8 @@ export type ToBtcLnRequestType = {
86
87
  * Swap handler handling to BTCLN swaps using submarine swaps
87
88
  */
88
89
  export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwapState> {
89
- protected readonly LIGHTNING_LIQUIDITY_CACHE_TIMEOUT = 5*1000;
90
90
 
91
91
  activeSubscriptions: Set<string> = new Set<string>();
92
- lightningLiquidityCache: {
93
- liquidity: bigint,
94
- timestamp: number
95
- };
96
92
 
97
93
  readonly type = SwapHandlerType.TO_BTCLN;
98
94
  readonly swapType = ChainSwapType.HTLC;
@@ -104,6 +100,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
104
100
  } = {};
105
101
 
106
102
  readonly lightning: ILightningWallet;
103
+ readonly LightningAssertions: LightningAssertions;
107
104
 
108
105
  constructor(
109
106
  storageDirectory: IIntermediaryStorage<ToBtcLnSwapAbs>,
@@ -113,8 +110,9 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
113
110
  swapPricing: ISwapPrice,
114
111
  config: ToBtcLnConfig
115
112
  ) {
116
- super(storageDirectory, path, chainData, swapPricing);
113
+ super(storageDirectory, path, chainData, swapPricing, config);
117
114
  this.lightning = lightning;
115
+ this.LightningAssertions = new LightningAssertions(this.logger, lightning);
118
116
  const anyConfig = config as any;
119
117
  anyConfig.minTsSendCltv = config.gracePeriod + (config.bitcoinBlocktime * config.minSendCltv * config.safetyFactor);
120
118
  this.config = anyConfig;
@@ -522,47 +520,6 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
522
520
  }
523
521
  }
524
522
 
525
- /**
526
- * Checks if the prior payment with the same paymentHash exists
527
- *
528
- * @param paymentHash
529
- * @param abortSignal
530
- * @throws {DefinedRuntimeError} will throw an error if payment already exists
531
- */
532
- private async checkPriorPayment(paymentHash: string, abortSignal: AbortSignal): Promise<void> {
533
- const payment = await this.lightning.getPayment(paymentHash);
534
- if(payment!=null) throw {
535
- code: 20010,
536
- msg: "Already processed"
537
- };
538
- abortSignal.throwIfAborted();
539
- }
540
-
541
- /**
542
- * Checks if the underlying LND backend has enough liquidity in channels to honor the swap
543
- *
544
- * @param amount
545
- * @param abortSignal
546
- * @param useCached Whether to use cached liquidity values
547
- * @throws {DefinedRuntimeError} will throw an error if there isn't enough liquidity
548
- */
549
- private async checkLiquidity(amount: bigint, abortSignal: AbortSignal, useCached: boolean = false): Promise<void> {
550
- if(!useCached || this.lightningLiquidityCache==null || this.lightningLiquidityCache.timestamp<Date.now()-this.LIGHTNING_LIQUIDITY_CACHE_TIMEOUT) {
551
- const channelBalances = await this.lightning.getLightningBalance();
552
- this.lightningLiquidityCache = {
553
- liquidity: channelBalances.localBalance,
554
- timestamp: Date.now()
555
- }
556
- }
557
- if(amount > this.lightningLiquidityCache.liquidity) {
558
- throw {
559
- code: 20002,
560
- msg: "Not enough liquidity"
561
- };
562
- }
563
- abortSignal.throwIfAborted();
564
- }
565
-
566
523
  /**
567
524
  * Estimates the routing fee & confidence by either probing or routing (if probing fails), the fee is also adjusted
568
525
  * according to routing fee multiplier, and subject to minimums set in config
@@ -645,6 +602,8 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
645
602
  actualRoutingFee = maxFee;
646
603
  }
647
604
 
605
+ this.logger.debug("checkAndGetNetworkFee(): network fee calculated, amount: "+amountBD.toString(10)+" fee: "+actualRoutingFee.toString(10));
606
+
648
607
  return {
649
608
  networkFee: actualRoutingFee,
650
609
  confidence: probeOrRouteResp.confidence
@@ -822,7 +781,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
822
781
  } = {request: {}, times: {}};
823
782
 
824
783
  const chainIdentifier = req.query.chain as string ?? this.chains.default;
825
- const {swapContract, signer} = this.getChain(chainIdentifier);
784
+ const {swapContract, signer, chainInterface} = this.getChain(chainIdentifier);
826
785
 
827
786
  metadata.times.requestReceived = Date.now();
828
787
  /**
@@ -847,7 +806,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
847
806
  this.isTokenSupported(chainIdentifier, val) ? val : null,
848
807
  offerer: (val: string) => val!=null &&
849
808
  typeof(val)==="string" &&
850
- swapContract.isValidAddress(val) ? val : null,
809
+ chainInterface.isValidAddress(val) ? val : null,
851
810
  exactIn: FieldTypeEnum.BooleanOptional,
852
811
  amount: FieldTypeEnum.BigIntOptional
853
812
  });
@@ -879,19 +838,20 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
879
838
  const {parsedPR, halfConfidence} = await this.checkPaymentRequest(chainIdentifier, parsedBody.pr);
880
839
  const requestedAmount = {
881
840
  input: !!parsedBody.exactIn,
882
- amount: !!parsedBody.exactIn ? parsedBody.amount : (parsedPR.mtokens + 999n) / 1000n
841
+ amount: !!parsedBody.exactIn ? parsedBody.amount : (parsedPR.mtokens + 999n) / 1000n,
842
+ token: useToken
883
843
  };
884
- const fees = await this.preCheckAmounts(request, requestedAmount, useToken);
844
+ const fees = await this.AmountAssertions.preCheckToBtcAmounts(this.type, request, requestedAmount);
885
845
  metadata.times.requestChecked = Date.now();
886
846
 
887
847
  //Create abort controller for parallel pre-fetches
888
- const abortController = this.getAbortController(responseStream);
848
+ const abortController = getAbortController(responseStream);
889
849
 
890
850
  //Pre-fetch
891
851
  const {pricePrefetchPromise, signDataPrefetchPromise} = this.getToBtcPrefetches(chainIdentifier, useToken, responseStream, abortController);
892
852
 
893
853
  //Check if prior payment has been made
894
- await this.checkPriorPayment(parsedPR.id, abortController.signal);
854
+ await this.LightningAssertions.checkPriorPayment(parsedPR.id, abortController.signal);
895
855
  metadata.times.priorPaymentChecked = Date.now();
896
856
 
897
857
  //Check amounts
@@ -902,9 +862,9 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
902
862
  swapFee,
903
863
  swapFeeInToken,
904
864
  networkFeeInToken
905
- } = await this.checkToBtcAmount(request, requestedAmount, fees, useToken, async (amountBD: bigint) => {
865
+ } = await this.AmountAssertions.checkToBtcAmount(this.type, request, {...requestedAmount, pricePrefetch: pricePrefetchPromise}, fees, async (amountBD: bigint) => {
906
866
  //Check if we have enough liquidity to process the swap
907
- await this.checkLiquidity(amountBD, abortController.signal, true);
867
+ await this.LightningAssertions.checkLiquidity(amountBD, abortController.signal, true);
908
868
  metadata.times.liquidityChecked = Date.now();
909
869
 
910
870
  const maxFee = parsedBody.exactIn ?
@@ -912,7 +872,7 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
912
872
  parsedBody.maxFee;
913
873
 
914
874
  return await this.checkAndGetNetworkFee(amountBD, maxFee, parsedBody.expiryTimestamp, currentTimestamp, parsedBody.pr, metadata, abortController.signal);
915
- }, abortController.signal, pricePrefetchPromise);
875
+ }, abortController.signal);
916
876
  metadata.times.priceCalculated = Date.now();
917
877
 
918
878
  //For exactIn swap, just save and wait for the actual invoice to be submitted
@@ -1,6 +1,6 @@
1
1
  import {SwapData} from "@atomiqlabs/base";
2
- import {SwapHandlerType} from "../..";
3
- import {deserializeBN} from "../../utils/Utils";
2
+ import {SwapHandlerType} from "../../../index";
3
+ import {deserializeBN} from "../../../utils/Utils";
4
4
  import {ToBtcBaseSwap} from "../ToBtcBaseSwap";
5
5
 
6
6
  export enum ToBtcLnSwapState {
@@ -0,0 +1,143 @@
1
+ import {
2
+ Lockable,
3
+ SpvVaultClaimEvent,
4
+ SpvVaultCloseEvent,
5
+ SpvVaultData,
6
+ SpvVaultDepositEvent,
7
+ SpvVaultOpenEvent,
8
+ SpvVaultTokenBalance,
9
+ SpvWithdrawalTransactionData,
10
+ StorageObject
11
+ } from "@atomiqlabs/base";
12
+
13
+ export enum SpvVaultState {
14
+ CLOSED = -1,
15
+ BTC_INITIATED = 0,
16
+ BTC_CONFIRMED = 1,
17
+ OPENED = 2
18
+ }
19
+
20
+ export class SpvVault<
21
+ D extends SpvWithdrawalTransactionData = SpvWithdrawalTransactionData,
22
+ T extends SpvVaultData = SpvVaultData
23
+ > extends Lockable implements StorageObject {
24
+
25
+ readonly chainId: string;
26
+
27
+ readonly initialUtxo: string;
28
+ readonly btcAddress: string;
29
+
30
+ readonly pendingWithdrawals: D[];
31
+ data: T;
32
+
33
+ state: SpvVaultState;
34
+
35
+ balances: SpvVaultTokenBalance[];
36
+
37
+ scOpenTx: {txId: string, rawTx: string};
38
+
39
+ constructor(chainId: string, vault: T, btcAddress: string);
40
+ constructor(obj: any);
41
+ constructor(chainIdOrObj: string | any, vault?: T, btcAddress?: string) {
42
+ super();
43
+ if(typeof(chainIdOrObj)==="string") {
44
+ this.state = SpvVaultState.BTC_INITIATED;
45
+ this.chainId = chainIdOrObj;
46
+ this.data = vault;
47
+ this.initialUtxo = vault.getUtxo();
48
+ this.btcAddress = btcAddress;
49
+ this.pendingWithdrawals = [];
50
+ } else {
51
+ this.state = chainIdOrObj.state;
52
+ this.chainId = chainIdOrObj.chainId;
53
+ this.data = SpvVaultData.deserialize<T>(chainIdOrObj.data);
54
+ this.initialUtxo = chainIdOrObj.initialUtxo;
55
+ this.btcAddress = chainIdOrObj.btcAddress;
56
+ this.pendingWithdrawals = chainIdOrObj.pendingWithdrawals.map(SpvWithdrawalTransactionData.deserialize<D>);
57
+ this.scOpenTx = chainIdOrObj.scOpenTx;
58
+ }
59
+ this.balances = this.data.calculateStateAfter(this.pendingWithdrawals).balances;
60
+ }
61
+
62
+ update(event: SpvVaultOpenEvent | SpvVaultDepositEvent | SpvVaultCloseEvent | SpvVaultClaimEvent): void {
63
+ if(event instanceof SpvVaultClaimEvent || event instanceof SpvVaultCloseEvent) {
64
+ const processedWithdrawalIndex = this.pendingWithdrawals.findIndex(val => val.btcTx.txid === event.btcTxId);
65
+ if(processedWithdrawalIndex!==-1) this.pendingWithdrawals.splice(0, processedWithdrawalIndex + 1);
66
+ }
67
+ this.data.updateState(event);
68
+ this.balances = this.data.calculateStateAfter(this.pendingWithdrawals).balances;
69
+ }
70
+
71
+ addWithdrawal(withdrawalData: D): void {
72
+ //Make sure this is a valid state transition before adding the tx to pending withdrawals
73
+ this.balances = this.data.calculateStateAfter([...this.pendingWithdrawals, withdrawalData]).balances;
74
+ this.pendingWithdrawals.push(withdrawalData);
75
+ }
76
+
77
+ removeWithdrawal(withdrawalData: D): boolean {
78
+ const index = this.pendingWithdrawals.indexOf(withdrawalData);
79
+ if(index===-1) return false;
80
+ this.pendingWithdrawals.splice(index, 1);
81
+ this.balances = this.data.calculateStateAfter(this.pendingWithdrawals).balances;
82
+ return true;
83
+ }
84
+
85
+ toRawAmounts(amounts: bigint[]): bigint[] {
86
+ return amounts.map((amt, index) => {
87
+ const tokenData = this.data.getTokenData()[index];
88
+ if(tokenData==null) throw new Error("Amount index out of bounds!");
89
+ return amt / tokenData.multiplier;
90
+ });
91
+ }
92
+
93
+ fromRawAmounts(rawAmounts: bigint[]): bigint[] {
94
+ return rawAmounts.map((amt, index) => {
95
+ const tokenData = this.data.getTokenData()[index];
96
+ if(tokenData==null) throw new Error("Amount index out of bounds!");
97
+ return amt * tokenData.multiplier;
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Returns the vault balance after processing all currently confirmed (at least 1 btc confirmation) withdrawals
103
+ */
104
+ getConfirmedBalance(): SpvVaultTokenBalance[] {
105
+ return this.data.calculateStateAfter(this.pendingWithdrawals.filter(val => val.btcTx.confirmations>=1)).balances;
106
+ }
107
+
108
+ serialize(): any {
109
+ return {
110
+ state: this.state,
111
+ chainId: this.chainId,
112
+ data: this.data.serialize(),
113
+ initialUtxo: this.initialUtxo,
114
+ btcAddress: this.btcAddress,
115
+ pendingWithdrawals: this.pendingWithdrawals.map(val => val.serialize()),
116
+ scOpenTx: this.scOpenTx
117
+ }
118
+ }
119
+
120
+ getIdentifier(): string {
121
+ return this.chainId+"_"+this.data.getOwner()+"_"+this.data.getVaultId().toString(10);
122
+ }
123
+
124
+ /**
125
+ * Returns the latest vault utxo
126
+ */
127
+ getLatestUtxo(): string {
128
+ if(this.pendingWithdrawals.length===0) {
129
+ return this.data.getUtxo();
130
+ }
131
+ const latestWithdrawal = this.pendingWithdrawals[this.pendingWithdrawals.length - 1];
132
+ if(latestWithdrawal.btcTx.confirmations>=1) return latestWithdrawal.btcTx.txid+":0";
133
+ return null;
134
+ }
135
+
136
+ /**
137
+ * Returns whether the vault is ready for the next swap
138
+ */
139
+ isReady(): boolean {
140
+ return this.data.isOpened() && this.getLatestUtxo()!=null;
141
+ }
142
+
143
+ }