@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
@@ -11,31 +11,23 @@ function objectBigIntsToString(obj: Object) {
11
11
  return obj;
12
12
  }
13
13
 
14
- export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> extends Lockable implements StorageObject {
14
+ export abstract class SwapHandlerSwap<S = any> extends Lockable implements StorageObject {
15
+ type: SwapHandlerType;
15
16
 
16
17
  chainIdentifier: string;
17
18
  state: S;
18
19
 
19
- type: SwapHandlerType;
20
- data: T;
21
20
  metadata: {
22
21
  request: any,
23
22
  times: {[key: string]: number},
24
23
  [key: string]: any
25
24
  };
26
25
  txIds: {
27
- init?: string,
28
- claim?: string,
29
- refund?: string
26
+ [key: string]: string
30
27
  } = {};
31
28
  readonly swapFee: bigint;
32
29
  readonly swapFeeInToken: bigint;
33
30
 
34
- prefix: string;
35
- timeout: string;
36
- signature: string;
37
- feeRate: string;
38
-
39
31
  protected constructor(chainIdentifier: string, swapFee: bigint, swapFeeInToken: bigint);
40
32
  protected constructor(obj: any);
41
33
 
@@ -47,33 +39,23 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
47
39
  this.swapFeeInToken = swapFeeInToken;
48
40
  return;
49
41
  } else {
50
- this.data = obj.data==null ? null : SwapData.deserialize(obj.data);
51
42
  this.metadata = obj.metadata;
52
43
  this.chainIdentifier = obj.chainIdentifier;
53
44
  this.txIds = obj.txIds || {};
54
45
  this.state = obj.state;
55
46
  this.swapFee = deserializeBN(obj.swapFee);
56
47
  this.swapFeeInToken = deserializeBN(obj.swapFeeInToken);
57
- this.prefix = obj.prefix;
58
- this.timeout = obj.timeout;
59
- this.signature = obj.signature;
60
- this.feeRate = obj.feeRate;
61
48
  }
62
49
  }
63
50
 
64
51
  serialize(): any {
65
52
  return {
66
53
  state: this.state,
67
- data: this.data==null ? null : this.data.serialize(),
68
54
  chainIdentifier: this.chainIdentifier,
69
55
  metadata: objectBigIntsToString(this.metadata),
70
56
  txIds: this.txIds,
71
57
  swapFee: serializeBN(this.swapFee),
72
- swapFeeInToken: serializeBN(this.swapFeeInToken),
73
- prefix: this.prefix,
74
- timeout: this.timeout,
75
- signature: this.signature,
76
- feeRate: this.feeRate
58
+ swapFeeInToken: serializeBN(this.swapFeeInToken)
77
59
  }
78
60
  }
79
61
 
@@ -88,31 +70,13 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
88
70
  return PluginManager.swapStateChange(this, oldState);
89
71
  }
90
72
 
91
- /**
92
- * Returns the escrow hash - i.e. hash of the escrow data
93
- */
94
- getEscrowHash(): string {
95
- return this.data.getEscrowHash();
96
- }
97
-
98
- /**
99
- * Returns the claim data hash - i.e. hash passed to the claim handler
100
- */
101
- getClaimHash(): string {
102
- return this.data.getClaimHash();
103
- }
104
-
105
73
  /**
106
74
  * Returns the identification hash of the swap, usually claim data hash, but can be overriden, e.g. for
107
75
  * lightning swaps the identifier hash is used instead of claim data hash
108
76
  */
109
- getIdentifierHash(): string {
110
- return this.getClaimHash();
111
- }
77
+ abstract getIdentifierHash(): string;
112
78
 
113
- getSequence(): bigint | null {
114
- return this.data?.getSequence==null ? null : this.data.getSequence();
115
- }
79
+ abstract getSequence(): bigint | null;
116
80
 
117
81
  /**
118
82
  * Returns unique identifier of the swap in the form <hash>_<sequence> or just <hash> if the swap type doesn't
@@ -128,9 +92,7 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
128
92
  /**
129
93
  * Returns the smart chain token used for the swap
130
94
  */
131
- getToken(): string {
132
- return this.data?.getToken();
133
- }
95
+ abstract getToken(): string
134
96
 
135
97
  /**
136
98
  * Checks whether the swap is finished, such that it is final and either successful or failed
@@ -157,7 +119,9 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
157
119
  /**
158
120
  * Returns the input amount paid by the user (excluding fees)
159
121
  */
160
- abstract getInputAmount(): bigint;
122
+ getInputAmount(): bigint {
123
+ return this.getTotalInputAmount() - this.getSwapFee().inInputToken;
124
+ }
161
125
 
162
126
  /**
163
127
  * Returns the total input amount paid by the user (including all fees)
@@ -0,0 +1,77 @@
1
+ import {ISwapPrice} from "../../prices/ISwapPrice";
2
+ import {isQuoteAmountTooHigh, isQuoteAmountTooLow, isQuoteThrow} from "../../plugins/IPlugin";
3
+
4
+ export type AmountAssertionsConfig = {min: bigint, max: bigint, baseFee: bigint, feePPM: bigint};
5
+
6
+ export abstract class AmountAssertions {
7
+
8
+ readonly config: AmountAssertionsConfig;
9
+ readonly swapPricing: ISwapPrice;
10
+
11
+ constructor(config: AmountAssertionsConfig, swapPricing: ISwapPrice) {
12
+ this.config = config;
13
+ this.swapPricing = swapPricing;
14
+ }
15
+
16
+ /**
17
+ * Checks whether the bitcoin amount is within specified min/max bounds
18
+ *
19
+ * @param amount
20
+ * @protected
21
+ * @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
22
+ */
23
+ protected checkBtcAmountInBounds(amount: bigint): void {
24
+ if (amount < this.config.min) {
25
+ throw {
26
+ code: 20003,
27
+ msg: "Amount too low!",
28
+ data: {
29
+ min: this.config.min.toString(10),
30
+ max: this.config.max.toString(10)
31
+ }
32
+ };
33
+ }
34
+
35
+ if(amount > this.config.max) {
36
+ throw {
37
+ code: 20004,
38
+ msg: "Amount too high!",
39
+ data: {
40
+ min: this.config.min.toString(10),
41
+ max: this.config.max.toString(10)
42
+ }
43
+ };
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Handles and throws plugin errors
49
+ *
50
+ * @param res Response as returned from the PluginManager.onHandlePost{To,From}BtcQuote
51
+ * @protected
52
+ * @throws {DefinedRuntimeError} will throw an error if the response is an error
53
+ */
54
+ static handlePluginErrorResponses(res: any): void {
55
+ if(isQuoteThrow(res)) throw {
56
+ code: 29999,
57
+ msg: res.message
58
+ };
59
+ if(isQuoteAmountTooHigh(res)) throw {
60
+ code: 20004,
61
+ msg: "Amount too high!",
62
+ data: {
63
+ min: res.data.min.toString(10),
64
+ max: res.data.max.toString(10)
65
+ }
66
+ };
67
+ if(isQuoteAmountTooLow(res)) throw {
68
+ code: 20003,
69
+ msg: "Amount too low!",
70
+ data: {
71
+ min: res.data.min.toString(10),
72
+ max: res.data.max.toString(10)
73
+ }
74
+ };
75
+ }
76
+
77
+ }
@@ -0,0 +1,228 @@
1
+ import {FromBtcLnRequestType} from "../escrow/frombtcln_abstract/FromBtcLnAbs";
2
+ import {FromBtcRequestType} from "../escrow/frombtc_abstract/FromBtcAbs";
3
+ import {FromBtcLnTrustedRequestType} from "../trusted/frombtcln_trusted/FromBtcLnTrusted";
4
+ import {PluginManager} from "../../plugins/PluginManager";
5
+ import {isPluginQuote, isQuoteSetFees} from "../../plugins/IPlugin";
6
+ import {RequestData, SwapHandlerType} from "../SwapHandler";
7
+ import {AmountAssertions, AmountAssertionsConfig} from "./AmountAssertions";
8
+ import {ISwapPrice} from "../../prices/ISwapPrice";
9
+ import {FromBtcTrustedRequestType} from "../trusted/frombtc_trusted/FromBtcTrusted";
10
+ import {SpvVaultSwapRequestType} from "../spv_vault_swap/SpvVaultSwapHandler";
11
+
12
+ export type FromBtcAmountAssertionsConfig = AmountAssertionsConfig & {
13
+ gasTokenMax?: {[chainId: string]: bigint}
14
+ };
15
+
16
+ export class FromBtcAmountAssertions extends AmountAssertions {
17
+
18
+ readonly config: FromBtcAmountAssertionsConfig;
19
+
20
+ constructor(config: FromBtcAmountAssertionsConfig, swapPricing: ISwapPrice) {
21
+ super(config, swapPricing)
22
+ this.config = config;
23
+ }
24
+
25
+ /**
26
+ * Checks minimums/maximums, calculates the fee & total amount
27
+ *
28
+ * @param swapType
29
+ * @param request
30
+ * @param requestedAmount
31
+ * @param gasAmount
32
+ * @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
33
+ */
34
+ async preCheckFromBtcAmounts(
35
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
36
+ request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
37
+ requestedAmount: {input: boolean, amount: bigint, token: string},
38
+ gasAmount?: {input: false, amount: bigint, token: string}
39
+ ): Promise<{
40
+ baseFee: bigint,
41
+ feePPM: bigint,
42
+ securityDepositApyPPM?: bigint,
43
+ securityDepositBaseMultiplierPPM?: bigint,
44
+ }> {
45
+ const res = await PluginManager.onHandlePreFromBtcQuote(
46
+ swapType,
47
+ request,
48
+ requestedAmount,
49
+ request.chainIdentifier,
50
+ {minInBtc: this.config.min, maxInBtc: this.config.max},
51
+ {baseFeeInBtc: this.config.baseFee, feePPM: this.config.feePPM},
52
+ gasAmount
53
+ );
54
+ if(res!=null) {
55
+ AmountAssertions.handlePluginErrorResponses(res);
56
+ if(isQuoteSetFees(res)) {
57
+ return {
58
+ baseFee: res.baseFee || this.config.baseFee,
59
+ feePPM: res.feePPM || this.config.feePPM,
60
+ securityDepositApyPPM: res.securityDepositApyPPM,
61
+ securityDepositBaseMultiplierPPM: res.securityDepositBaseMultiplierPPM
62
+ }
63
+ }
64
+ }
65
+ if(requestedAmount.input) this.checkBtcAmountInBounds(requestedAmount.amount);
66
+
67
+ if(gasAmount!=null && gasAmount.amount!==0n) {
68
+ if(gasAmount.amount > (this.config.gasTokenMax?.[request.chainIdentifier] ?? 0n)) {
69
+ throw {
70
+ code: 20504,
71
+ msg: "Gas token amount too high!",
72
+ data: {
73
+ max: (this.config.gasTokenMax?.[request.chainIdentifier] ?? 0n).toString(10)
74
+ }
75
+ };
76
+ }
77
+ }
78
+
79
+ return {
80
+ baseFee: this.config.baseFee,
81
+ feePPM: this.config.feePPM
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Checks minimums/maximums, calculates the fee & total amount
87
+ *
88
+ * @param swapType
89
+ * @param request
90
+ * @param requestedAmount
91
+ * @param fees
92
+ * @param signal
93
+ * @param gasTokenAmount
94
+ * @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
95
+ */
96
+ async checkFromBtcAmount(
97
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
98
+ request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
99
+ requestedAmount: {input: boolean, amount: bigint, token: string, pricePrefetch?: Promise<bigint>},
100
+ fees: {baseFee: bigint, feePPM: bigint},
101
+ signal: AbortSignal,
102
+ gasTokenAmount?: {input: false, amount: bigint, token: string, pricePrefetch?: Promise<bigint>}
103
+ ): Promise<{
104
+ amountBD: bigint,
105
+ swapFee: bigint, //Swap fee in BTC
106
+ swapFeeInToken: bigint, //Swap fee in token on top of what should be paid out to the user
107
+ totalInToken: bigint, //Total to be paid out to the user
108
+ amountBDgas?: bigint
109
+ gasSwapFee?: bigint
110
+ gasSwapFeeInToken?: bigint,
111
+ totalInGasToken?: bigint,
112
+ securityDepositApyPPM?: bigint,
113
+ securityDepositBaseMultiplierPPM?: bigint
114
+ }> {
115
+ const chainIdentifier = request.chainIdentifier;
116
+
117
+ let securityDepositApyPPM: bigint;
118
+ let securityDepositBaseMultiplierPPM: bigint;
119
+
120
+ const res = await PluginManager.onHandlePostFromBtcQuote(
121
+ swapType,
122
+ request,
123
+ requestedAmount,
124
+ chainIdentifier,
125
+ {minInBtc: this.config.min, maxInBtc: this.config.max},
126
+ {baseFeeInBtc: fees.baseFee, feePPM: fees.feePPM},
127
+ gasTokenAmount
128
+ );
129
+ signal.throwIfAborted();
130
+ if(res!=null) {
131
+ AmountAssertions.handlePluginErrorResponses(res);
132
+ if(isQuoteSetFees(res)) {
133
+ if(res.baseFee!=null) fees.baseFee = res.baseFee;
134
+ if(res.feePPM!=null) fees.feePPM = res.feePPM;
135
+ if(res.securityDepositApyPPM!=null) securityDepositApyPPM = res.securityDepositApyPPM;
136
+ if(res.securityDepositBaseMultiplierPPM!=null) securityDepositBaseMultiplierPPM = res.securityDepositBaseMultiplierPPM;
137
+ }
138
+ if(isPluginQuote(res)) {
139
+ if(!requestedAmount.input) {
140
+ return {
141
+ amountBD: res.amount.amount + res.swapFee.inInputTokens,
142
+ swapFee: res.swapFee.inInputTokens,
143
+ swapFeeInToken: res.swapFee.inOutputTokens,
144
+ totalInToken: requestedAmount.amount
145
+ }
146
+ } else {
147
+ return {
148
+ amountBD: requestedAmount.amount,
149
+ swapFee: res.swapFee.inInputTokens,
150
+ swapFeeInToken: res.swapFee.inOutputTokens,
151
+ totalInToken: res.amount.amount
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ let amountBDgas: bigint = 0n;
158
+ if(gasTokenAmount!=null) {
159
+ amountBDgas = await this.swapPricing.getToBtcSwapAmount(gasTokenAmount.amount, gasTokenAmount.token, chainIdentifier, true, gasTokenAmount.pricePrefetch);
160
+ }
161
+
162
+ let amountBD: bigint;
163
+ if(!requestedAmount.input) {
164
+ amountBD = await this.swapPricing.getToBtcSwapAmount(requestedAmount.amount, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
165
+ signal.throwIfAborted();
166
+
167
+ // amt = (amt+base_fee)/(1-fee)
168
+ amountBD = (amountBD + fees.baseFee) * 1000000n / (1000000n - fees.feePPM);
169
+ amountBDgas = amountBDgas * 1000000n / (1000000n - fees.feePPM);
170
+
171
+ const tooLow = amountBD < (this.config.min * 95n / 100n);
172
+ const tooHigh = amountBD > (this.config.max * 105n / 100n);
173
+ if(tooLow || tooHigh) {
174
+ const adjustedMin = this.config.min * (1000000n - fees.feePPM) / (1000000n - fees.baseFee);
175
+ const adjustedMax = this.config.max * (1000000n - fees.feePPM) / (1000000n - fees.baseFee);
176
+ const minIn = await this.swapPricing.getFromBtcSwapAmount(
177
+ adjustedMin, requestedAmount.token, chainIdentifier, null, requestedAmount.pricePrefetch
178
+ );
179
+ const maxIn = await this.swapPricing.getFromBtcSwapAmount(
180
+ adjustedMax, requestedAmount.token, chainIdentifier, null, requestedAmount.pricePrefetch
181
+ );
182
+ throw {
183
+ code: tooLow ? 20003 : 20004,
184
+ msg: tooLow ? "Amount too low!" : "Amount too high!",
185
+ data: {
186
+ min: minIn.toString(10),
187
+ max: maxIn.toString(10)
188
+ }
189
+ };
190
+ }
191
+ } else {
192
+ amountBD = requestedAmount.amount - amountBDgas;
193
+ this.checkBtcAmountInBounds(amountBD);
194
+ }
195
+
196
+ const swapFee = fees.baseFee + (amountBD * fees.feePPM / 1000000n);
197
+ const swapFeeInToken = await this.swapPricing.getFromBtcSwapAmount(swapFee, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
198
+ signal.throwIfAborted();
199
+
200
+ const gasSwapFee = ((amountBDgas * fees.feePPM) + 999999n) / 1000000n;
201
+ const gasSwapFeeInToken = gasTokenAmount==null ?
202
+ 0n :
203
+ await this.swapPricing.getFromBtcSwapAmount(gasSwapFee, gasTokenAmount.token, chainIdentifier, true, gasTokenAmount.pricePrefetch);
204
+ signal.throwIfAborted();
205
+
206
+ let totalInToken: bigint;
207
+ if(!requestedAmount.input) {
208
+ totalInToken = requestedAmount.amount;
209
+ } else {
210
+ totalInToken = await this.swapPricing.getFromBtcSwapAmount(amountBD - swapFee - gasSwapFee, requestedAmount.token, chainIdentifier, null, requestedAmount.pricePrefetch);
211
+ signal.throwIfAborted();
212
+ }
213
+
214
+ return {
215
+ amountBD,
216
+ swapFee,
217
+ swapFeeInToken,
218
+ totalInToken,
219
+ amountBDgas,
220
+ gasSwapFee,
221
+ gasSwapFeeInToken,
222
+ totalInGasToken: gasTokenAmount?.amount,
223
+ securityDepositApyPPM,
224
+ securityDepositBaseMultiplierPPM
225
+ }
226
+ }
227
+
228
+ }
@@ -0,0 +1,103 @@
1
+ import {ILightningWallet, LightningNetworkChannel} from "../../wallets/ILightningWallet";
2
+ import {LoggerType} from "../../utils/Utils";
3
+ import {ISwapPrice} from "../../prices/ISwapPrice";
4
+
5
+ export class LightningAssertions {
6
+
7
+ protected readonly LIGHTNING_LIQUIDITY_CACHE_TIMEOUT = 5*1000;
8
+ lightningLiquidityCache: {
9
+ liquidity: bigint,
10
+ timestamp: number
11
+ };
12
+
13
+ readonly lightning: ILightningWallet;
14
+ readonly logger: LoggerType;
15
+
16
+ constructor(
17
+ logger: LoggerType,
18
+ lightning: ILightningWallet
19
+ ) {
20
+ this.logger = logger;
21
+ this.lightning = lightning;
22
+ }
23
+
24
+ /**
25
+ * Checks if the prior payment with the same paymentHash exists
26
+ *
27
+ * @param paymentHash
28
+ * @param abortSignal
29
+ * @throws {DefinedRuntimeError} will throw an error if payment already exists
30
+ */
31
+ async checkPriorPayment(paymentHash: string, abortSignal: AbortSignal): Promise<void> {
32
+ const payment = await this.lightning.getPayment(paymentHash);
33
+ if(payment!=null) throw {
34
+ code: 20010,
35
+ msg: "Already processed"
36
+ };
37
+ abortSignal.throwIfAborted();
38
+ }
39
+
40
+ /**
41
+ * Checks if the underlying LND backend has enough liquidity in channels to honor the swap
42
+ *
43
+ * @param amount
44
+ * @param abortSignal
45
+ * @param useCached Whether to use cached liquidity values
46
+ * @throws {DefinedRuntimeError} will throw an error if there isn't enough liquidity
47
+ */
48
+ async checkLiquidity(amount: bigint, abortSignal: AbortSignal, useCached: boolean = false): Promise<void> {
49
+ if(!useCached || this.lightningLiquidityCache==null || this.lightningLiquidityCache.timestamp<Date.now()-this.LIGHTNING_LIQUIDITY_CACHE_TIMEOUT) {
50
+ const channelBalances = await this.lightning.getLightningBalance();
51
+ this.lightningLiquidityCache = {
52
+ liquidity: channelBalances.localBalance,
53
+ timestamp: Date.now()
54
+ }
55
+ }
56
+ if(amount > this.lightningLiquidityCache.liquidity) {
57
+ throw {
58
+ code: 20002,
59
+ msg: "Not enough liquidity"
60
+ };
61
+ }
62
+ abortSignal.throwIfAborted();
63
+ }
64
+
65
+ /**
66
+ * Checks if we have enough inbound liquidity to be able to receive an LN payment (without MPP)
67
+ *
68
+ * @param amountBD
69
+ * @param channelsPrefetch
70
+ * @param signal
71
+ * @throws {DefinedRuntimeError} will throw an error if there isn't enough inbound liquidity to receive the LN payment
72
+ */
73
+ async checkInboundLiquidity(amountBD: bigint, channelsPrefetch: Promise<LightningNetworkChannel[]>, signal: AbortSignal) {
74
+ const channelsResponse = await channelsPrefetch;
75
+
76
+ signal.throwIfAborted();
77
+
78
+ let hasEnoughInboundLiquidity = false;
79
+ channelsResponse.forEach(channel => {
80
+ if(channel.remoteBalance >= amountBD) hasEnoughInboundLiquidity = true;
81
+ });
82
+ if(!hasEnoughInboundLiquidity) {
83
+ throw {
84
+ code: 20050,
85
+ msg: "Not enough LN inbound liquidity"
86
+ };
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Starts LN channels pre-fetch
92
+ *
93
+ * @param abortController
94
+ */
95
+ getChannelsPrefetch(abortController: AbortController): Promise<LightningNetworkChannel[]> {
96
+ return this.lightning.getChannels(true).catch(e => {
97
+ this.logger.error("getChannelsPrefetch(): error", e);
98
+ abortController.abort(e);
99
+ return null;
100
+ });
101
+ }
102
+
103
+ }