@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,17 +1,18 @@
1
- import {BitcoinRpc, SwapData} from "@atomiqlabs/base";
1
+ import {BitcoinRpc, SpvWithdrawalTransactionData, SwapData} from "@atomiqlabs/base";
2
2
  import {
3
3
  FromBtcLnRequestType,
4
- FromBtcRequestType,
5
- ISwapPrice, MultichainData, RequestData,
6
- SwapHandler,
4
+ FromBtcRequestType, FromBtcTrustedRequestType,
5
+ ISwapPrice, MultichainData, RequestData, SpvVaultSwapRequestType,
6
+ SwapHandler, SwapHandlerType,
7
7
  ToBtcLnRequestType,
8
8
  ToBtcRequestType
9
9
  } from "..";
10
10
  import {SwapHandlerSwap} from "../swaps/SwapHandlerSwap";
11
11
  import {Command} from "@atomiqlabs/server-base";
12
- import {FromBtcLnTrustedRequestType} from "../swaps/frombtcln_trusted/FromBtcLnTrusted";
12
+ import {FromBtcLnTrustedRequestType} from "../swaps/trusted/frombtcln_trusted/FromBtcLnTrusted";
13
13
  import {IBitcoinWallet} from "../wallets/IBitcoinWallet";
14
14
  import {ILightningWallet} from "../wallets/ILightningWallet";
15
+ import {SpvVault} from "../swaps/spv_vault_swap/SpvVault";
15
16
 
16
17
  export type QuoteThrow = {
17
18
  type: "throw",
@@ -115,41 +116,48 @@ export interface IPlugin {
115
116
  onSwapRemove?(swap: SwapHandlerSwap): Promise<void>;
116
117
 
117
118
  onHandlePreFromBtcQuote?(
118
- request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType>,
119
- requestedAmount: {input: boolean, amount: bigint},
119
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
120
+ request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
121
+ requestedAmount: {input: boolean, amount: bigint, token: string},
120
122
  chainIdentifier: string,
121
- token: string,
122
123
  constraints: {minInBtc: bigint, maxInBtc: bigint},
123
- fees: {baseFeeInBtc: bigint, feePPM: bigint}
124
+ fees: {baseFeeInBtc: bigint, feePPM: bigint},
125
+ gasTokenAmount?: {input: false, amount: bigint, token: string}
124
126
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh>;
125
127
  onHandlePostFromBtcQuote?(
126
- request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType>,
127
- requestedAmount: {input: boolean, amount: bigint},
128
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
129
+ request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
130
+ requestedAmount: {input: boolean, amount: bigint, token: string, pricePrefetch?: Promise<bigint>},
128
131
  chainIdentifier: string,
129
- token: string,
130
132
  constraints: {minInBtc: bigint, maxInBtc: bigint},
131
133
  fees: {baseFeeInBtc: bigint, feePPM: bigint},
132
- pricePrefetchPromise?: Promise<bigint> | null
134
+ gasTokenAmount?: {input: false, amount: bigint, token: string, pricePrefetch?: Promise<bigint>}
133
135
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh | PluginQuote>;
134
136
 
135
137
  onHandlePreToBtcQuote?(
138
+ swapType: SwapHandlerType.TO_BTCLN | SwapHandlerType.TO_BTC,
136
139
  request: RequestData<ToBtcLnRequestType | ToBtcRequestType>,
137
- requestedAmount: {input: boolean, amount: bigint},
140
+ requestedAmount: {input: boolean, amount: bigint, token: string},
138
141
  chainIdentifier: string,
139
- token: string,
140
142
  constraints: {minInBtc: bigint, maxInBtc: bigint},
141
143
  fees: {baseFeeInBtc: bigint, feePPM: bigint}
142
144
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh>;
143
145
  onHandlePostToBtcQuote?(
146
+ swapType: SwapHandlerType.TO_BTCLN | SwapHandlerType.TO_BTC,
144
147
  request: RequestData<ToBtcLnRequestType | ToBtcRequestType>,
145
- requestedAmount: {input: boolean, amount: bigint},
148
+ requestedAmount: {input: boolean, amount: bigint, token: string, pricePrefetch?: Promise<bigint>},
146
149
  chainIdentifier: string,
147
- token: string,
148
150
  constraints: {minInBtc: bigint, maxInBtc: bigint},
149
- fees: {baseFeeInBtc: bigint, feePPM: bigint, networkFeeGetter: (amount: bigint) => Promise<bigint>},
150
- pricePrefetchPromise?: Promise<bigint> | null
151
+ fees: {baseFeeInBtc: bigint, feePPM: bigint, networkFeeGetter: (amount: bigint) => Promise<bigint>}
151
152
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh | ToBtcPluginQuote>;
152
153
 
154
+ onVaultSelection?(
155
+ chainIdentifier: string,
156
+ totalSats: bigint,
157
+ requestedAmount: {amount: bigint, token: string},
158
+ gasAmount: {amount: bigint, token: string}
159
+ ): Promise<SpvVault | QuoteThrow | QuoteAmountTooHigh | QuoteAmountTooLow | null>;
160
+
153
161
  /**
154
162
  * Returns whitelisted bitcoin txIds that are OK to spend even with 0-confs
155
163
  */
@@ -1,4 +1,4 @@
1
- import {BitcoinRpc, SwapData} from "@atomiqlabs/base";
1
+ import {BitcoinRpc, SpvWithdrawalTransactionData, SwapData} from "@atomiqlabs/base";
2
2
  import {
3
3
  IPlugin, isPluginQuote, isQuoteAmountTooHigh, isQuoteAmountTooLow, isQuoteSetFees,
4
4
  isQuoteThrow, isToBtcPluginQuote, PluginQuote,
@@ -9,18 +9,19 @@ import {
9
9
  } from "./IPlugin";
10
10
  import {
11
11
  FromBtcLnRequestType,
12
- FromBtcRequestType,
13
- ISwapPrice, MultichainData, RequestData,
14
- SwapHandler,
12
+ FromBtcRequestType, FromBtcTrustedRequestType,
13
+ ISwapPrice, MultichainData, RequestData, SpvVaultSwapRequestType,
14
+ SwapHandler, SwapHandlerType,
15
15
  ToBtcLnRequestType,
16
16
  ToBtcRequestType
17
17
  } from "..";
18
18
  import {SwapHandlerSwap} from "../swaps/SwapHandlerSwap";
19
19
  import * as fs from "fs";
20
20
  import {getLogger} from "../utils/Utils";
21
- import {FromBtcLnTrustedRequestType} from "../swaps/frombtcln_trusted/FromBtcLnTrusted";
21
+ import {FromBtcLnTrustedRequestType} from "../swaps/trusted/frombtcln_trusted/FromBtcLnTrusted";
22
22
  import {IBitcoinWallet} from "../wallets/IBitcoinWallet";
23
23
  import {ILightningWallet} from "../wallets/ILightningWallet";
24
+ import {SpvVault} from "../swaps/spv_vault_swap/SpvVault";
24
25
 
25
26
  export type FailSwapResponse = {
26
27
  type: "fail",
@@ -135,7 +136,7 @@ export class PluginManager {
135
136
  }
136
137
  }
137
138
 
138
- static async swapStateChange<T extends SwapData>(swap: SwapHandlerSwap<T>, oldState?: any) {
139
+ static async swapStateChange(swap: SwapHandlerSwap, oldState?: any) {
139
140
  for(let plugin of PluginManager.plugins.values()) {
140
141
  try {
141
142
  if(plugin.onSwapStateChange!=null) await plugin.onSwapStateChange(swap);
@@ -145,7 +146,7 @@ export class PluginManager {
145
146
  }
146
147
  }
147
148
 
148
- static async swapCreate<T extends SwapData>(swap: SwapHandlerSwap<T>) {
149
+ static async swapCreate(swap: SwapHandlerSwap) {
149
150
  for(let plugin of PluginManager.plugins.values()) {
150
151
  try {
151
152
  if(plugin.onSwapCreate!=null) await plugin.onSwapCreate(swap);
@@ -155,7 +156,7 @@ export class PluginManager {
155
156
  }
156
157
  }
157
158
 
158
- static async swapRemove<T extends SwapData>(swap: SwapHandlerSwap<T>) {
159
+ static async swapRemove(swap: SwapHandlerSwap) {
159
160
  for(let plugin of PluginManager.plugins.values()) {
160
161
  try {
161
162
  if(plugin.onSwapRemove!=null) await plugin.onSwapRemove(swap);
@@ -166,18 +167,18 @@ export class PluginManager {
166
167
  }
167
168
 
168
169
  static async onHandlePostFromBtcQuote(
169
- request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType>,
170
- requestedAmount: {input: boolean, amount: bigint},
170
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
171
+ request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
172
+ requestedAmount: {input: boolean, amount: bigint, token: string, pricePrefetch?: Promise<bigint>},
171
173
  chainIdentifier: string,
172
- token: string,
173
174
  constraints: {minInBtc: bigint, maxInBtc: bigint},
174
175
  fees: {baseFeeInBtc: bigint, feePPM: bigint},
175
- pricePrefetchPromise?: Promise<bigint> | null
176
+ gasTokenAmount?: {input: false, amount: bigint, token: string, pricePrefetch?: Promise<bigint>}
176
177
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh | PluginQuote> {
177
178
  for(let plugin of PluginManager.plugins.values()) {
178
179
  try {
179
180
  if(plugin.onHandlePostFromBtcQuote!=null) {
180
- const result = await plugin.onHandlePostFromBtcQuote(request, requestedAmount, chainIdentifier, token, constraints, fees, pricePrefetchPromise);
181
+ const result = await plugin.onHandlePostFromBtcQuote(swapType, request, requestedAmount, chainIdentifier, constraints, fees, gasTokenAmount);
181
182
  if(result!=null) {
182
183
  if(isQuoteSetFees(result)) return result;
183
184
  if(isQuoteThrow(result)) return result;
@@ -197,17 +198,18 @@ export class PluginManager {
197
198
  }
198
199
 
199
200
  static async onHandlePreFromBtcQuote(
200
- request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType>,
201
- requestedAmount: {input: boolean, amount: bigint},
201
+ swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
202
+ request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
203
+ requestedAmount: {input: boolean, amount: bigint, token: string},
202
204
  chainIdentifier: string,
203
- token: string,
204
205
  constraints: {minInBtc: bigint, maxInBtc: bigint},
205
- fees: {baseFeeInBtc: bigint, feePPM: bigint}
206
+ fees: {baseFeeInBtc: bigint, feePPM: bigint},
207
+ gasTokenAmount?: {input: false, amount: bigint, token: string}
206
208
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh> {
207
209
  for(let plugin of PluginManager.plugins.values()) {
208
210
  try {
209
211
  if(plugin.onHandlePreFromBtcQuote!=null) {
210
- const result = await plugin.onHandlePreFromBtcQuote(request, requestedAmount, chainIdentifier, token, constraints, fees);
212
+ const result = await plugin.onHandlePreFromBtcQuote(swapType, request, requestedAmount, chainIdentifier, constraints, fees, gasTokenAmount);
211
213
  if(result!=null) {
212
214
  if(isQuoteSetFees(result)) return result;
213
215
  if(isQuoteThrow(result)) return result;
@@ -223,26 +225,25 @@ export class PluginManager {
223
225
  }
224
226
 
225
227
  static async onHandlePostToBtcQuote<T extends {networkFee: bigint}>(
228
+ swapType: SwapHandlerType.TO_BTCLN | SwapHandlerType.TO_BTC,
226
229
  request: RequestData<ToBtcLnRequestType | ToBtcRequestType>,
227
- requestedAmount: {input: boolean, amount: bigint},
230
+ requestedAmount: {input: boolean, amount: bigint, token: string, pricePrefetch?: Promise<bigint>},
228
231
  chainIdentifier: string,
229
- token: string,
230
232
  constraints: {minInBtc: bigint, maxInBtc: bigint},
231
233
  fees: {baseFeeInBtc: bigint, feePPM: bigint, networkFeeGetter: (amount: bigint) => Promise<T>},
232
- pricePrefetchPromise?: Promise<bigint> | null
233
234
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh | (ToBtcPluginQuote & {networkFeeData: T})> {
234
235
  for(let plugin of PluginManager.plugins.values()) {
235
236
  try {
236
237
  if(plugin.onHandlePostToBtcQuote!=null) {
237
238
  let networkFeeData: T;
238
- const result = await plugin.onHandlePostToBtcQuote(request, requestedAmount, chainIdentifier, token, constraints, {
239
+ const result = await plugin.onHandlePostToBtcQuote(swapType, request, requestedAmount, chainIdentifier, constraints, {
239
240
  baseFeeInBtc: fees.baseFeeInBtc,
240
241
  feePPM: fees.feePPM,
241
242
  networkFeeGetter: async (amount: bigint) => {
242
243
  networkFeeData = await fees.networkFeeGetter(amount);
243
244
  return networkFeeData.networkFee;
244
245
  }
245
- }, pricePrefetchPromise);
246
+ });
246
247
  if(result!=null) {
247
248
  if(isQuoteSetFees(result)) return result;
248
249
  if(isQuoteThrow(result)) return result;
@@ -265,17 +266,17 @@ export class PluginManager {
265
266
  }
266
267
 
267
268
  static async onHandlePreToBtcQuote(
269
+ swapType: SwapHandlerType.TO_BTCLN | SwapHandlerType.TO_BTC,
268
270
  request: RequestData<ToBtcLnRequestType | ToBtcRequestType>,
269
- requestedAmount: {input: boolean, amount: bigint},
271
+ requestedAmount: {input: boolean, amount: bigint, token: string},
270
272
  chainIdentifier: string,
271
- token: string,
272
273
  constraints: {minInBtc: bigint, maxInBtc: bigint},
273
274
  fees: {baseFeeInBtc: bigint, feePPM: bigint}
274
275
  ): Promise<QuoteThrow | QuoteSetFees | QuoteAmountTooLow | QuoteAmountTooHigh> {
275
276
  for(let plugin of PluginManager.plugins.values()) {
276
277
  try {
277
278
  if(plugin.onHandlePreToBtcQuote!=null) {
278
- const result = await plugin.onHandlePreToBtcQuote(request, requestedAmount, chainIdentifier, token, constraints, fees);
279
+ const result = await plugin.onHandlePreToBtcQuote(swapType, request, requestedAmount, chainIdentifier, constraints, fees);
279
280
  if(result!=null) {
280
281
  if(isQuoteSetFees(result)) return result;
281
282
  if(isQuoteThrow(result)) return result;
@@ -290,6 +291,30 @@ export class PluginManager {
290
291
  return null;
291
292
  }
292
293
 
294
+ static async onVaultSelection(
295
+ chainIdentifier: string,
296
+ totalSats: bigint,
297
+ requestedAmount: {amount: bigint, token: string},
298
+ gasAmount: {amount: bigint, token: string}
299
+ ): Promise<SpvVault | QuoteThrow | QuoteAmountTooHigh | QuoteAmountTooLow> {
300
+ for(let plugin of PluginManager.plugins.values()) {
301
+ try {
302
+ if(plugin.onVaultSelection!=null) {
303
+ const result = await plugin.onVaultSelection(chainIdentifier, totalSats, requestedAmount, gasAmount);
304
+ if(result!=null) {
305
+ if(isQuoteThrow(result)) return result;
306
+ if(isQuoteAmountTooHigh(result)) return result;
307
+ if(isQuoteAmountTooLow(result)) return result;
308
+ if(result instanceof SpvVault) return result;
309
+ }
310
+ }
311
+ } catch (e) {
312
+ pluginLogger.error(plugin, "onVaultSelection(): plugin error", e);
313
+ }
314
+ }
315
+ return null;
316
+ }
317
+
293
318
  static getWhitelistedTxIds(): Set<string> {
294
319
  const whitelist: Set<string> = new Set<string>();
295
320
 
@@ -1,4 +1,4 @@
1
- import {ISwapPrice} from "../swaps/ISwapPrice";
1
+ import {ISwapPrice} from "./ISwapPrice";
2
2
 
3
3
  const CACHE_DURATION = 15000;
4
4
 
@@ -1,4 +1,4 @@
1
- import {ISwapPrice} from "../swaps/ISwapPrice";
1
+ import {ISwapPrice} from "./ISwapPrice";
2
2
 
3
3
  const CACHE_DURATION = 15000;
4
4
 
@@ -51,6 +51,8 @@ export abstract class ISwapPrice<T extends {decimals: number} = {decimals: numbe
51
51
  roundUp?: boolean,
52
52
  preFetch?: Promise<bigint>
53
53
  ): Promise<bigint> {
54
+ if(fromAmount===0n) return 0n;
55
+
54
56
  const coin = this.getTokenData(fromToken, tokenChainIdentification);
55
57
 
56
58
  const price = (preFetch==null ? null : await preFetch) || await this.getPrice(coin);
@@ -74,6 +76,8 @@ export abstract class ISwapPrice<T extends {decimals: number} = {decimals: numbe
74
76
  roundUp?: boolean,
75
77
  preFetch?: Promise<bigint>
76
78
  ): Promise<bigint> {
79
+ if(fromAmount===0n) return 0n;
80
+
77
81
  const coin = this.getTokenData(toToken, tokenChainIdentification);
78
82
 
79
83
  const price = (preFetch==null ? null : await preFetch) || await this.getPrice(coin);
@@ -1,4 +1,4 @@
1
- import {ISwapPrice} from "../swaps/ISwapPrice";
1
+ import {ISwapPrice} from "./ISwapPrice";
2
2
 
3
3
  const CACHE_DURATION = 15000;
4
4
 
@@ -1,22 +1,12 @@
1
1
  import {Express, Request} from "express";
2
- import {ISwapPrice} from "./ISwapPrice";
2
+ import {ISwapPrice} from "../prices/ISwapPrice";
3
3
  import {
4
4
  ChainSwapType,
5
- ChainType,
6
- ClaimEvent,
7
- InitializeEvent, RefundEvent,
8
- SwapData,
9
- SwapEvent
5
+ ChainType
10
6
  } from "@atomiqlabs/base";
11
7
  import {SwapHandlerSwap} from "./SwapHandlerSwap";
12
8
  import {PluginManager} from "../plugins/PluginManager";
13
9
  import {IIntermediaryStorage} from "../storage/IIntermediaryStorage";
14
- import {ServerParamEncoder} from "../utils/paramcoders/server/ServerParamEncoder";
15
- import {
16
- isQuoteAmountTooHigh,
17
- isQuoteAmountTooLow,
18
- isQuoteThrow,
19
- } from "../plugins/IPlugin";
20
10
  import {IParamReader} from "../utils/paramcoders/IParamReader";
21
11
 
22
12
  export enum SwapHandlerType {
@@ -26,6 +16,7 @@ export enum SwapHandlerType {
26
16
  FROM_BTCLN = "FROM_BTCLN",
27
17
  FROM_BTCLN_TRUSTED = "FROM_BTCLN_TRUSTED",
28
18
  FROM_BTC_TRUSTED = "FROM_BTC_TRUSTED",
19
+ FROM_BTC_SPV = "FROM_BTC_SPV"
29
20
  }
30
21
 
31
22
  export type SwapHandlerInfoType = {
@@ -62,8 +53,11 @@ export type MultichainData = {
62
53
  export type ChainData<T extends ChainType = ChainType> = {
63
54
  signer: T["Signer"],
64
55
  swapContract: T["Contract"],
56
+ spvVaultContract: T["SpvVaultContract"],
57
+ chainInterface: T["ChainInterface"],
65
58
  chainEvents: T["Events"],
66
59
  allowedTokens: string[],
60
+ tokenMultipliers?: {[tokenAddress: string]: bigint},
67
61
  allowedDepositTokens?: string[],
68
62
  btcRelay?: T["BtcRelay"]
69
63
  }
@@ -78,13 +72,11 @@ export type RequestData<T> = {
78
72
  /**
79
73
  * An abstract class defining a singular swap service
80
74
  */
81
- export abstract class SwapHandler<V extends SwapHandlerSwap<SwapData, S> = SwapHandlerSwap, S = any> {
75
+ export abstract class SwapHandler<V extends SwapHandlerSwap<S> = SwapHandlerSwap, S = any> {
82
76
 
83
77
  abstract readonly type: SwapHandlerType;
84
- abstract readonly swapType: ChainSwapType;
85
78
 
86
79
  readonly storageManager: IIntermediaryStorage<V>;
87
- readonly escrowHashMap: Map<string, V> = new Map();
88
80
  readonly path: string;
89
81
 
90
82
  readonly chains: MultichainData;
@@ -101,10 +93,10 @@ export abstract class SwapHandler<V extends SwapHandlerSwap<SwapData, S> = SwapH
101
93
  };
102
94
 
103
95
  protected swapLogger = {
104
- debug: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.debug(this.getIdentifier(swap)+": "+msg, ...args),
105
- info: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.info(this.getIdentifier(swap)+": "+msg, ...args),
106
- warn: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.warn(this.getIdentifier(swap)+": "+msg, ...args),
107
- error: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.error(this.getIdentifier(swap)+": "+msg, ...args)
96
+ debug: (swap: SwapHandlerSwap, msg: string, ...args: any) => this.logger.debug(swap.getIdentifier()+": "+msg, ...args),
97
+ info: (swap: SwapHandlerSwap, msg: string, ...args: any) => this.logger.info(swap.getIdentifier()+": "+msg, ...args),
98
+ warn: (swap: SwapHandlerSwap, msg: string, ...args: any) => this.logger.warn(swap.getIdentifier()+": "+msg, ...args),
99
+ error: (swap: SwapHandlerSwap, msg: string, ...args: any) => this.logger.error(swap.getIdentifier()+": "+msg, ...args)
108
100
  };
109
101
 
110
102
  protected constructor(
@@ -151,61 +143,6 @@ export abstract class SwapHandler<V extends SwapHandlerSwap<SwapData, S> = SwapH
151
143
  await rerun();
152
144
  }
153
145
 
154
- protected abstract processInitializeEvent?(chainIdentifier: string, swap: V, event: InitializeEvent<SwapData>): Promise<void>;
155
- protected abstract processClaimEvent?(chainIdentifier: string, swap: V, event: ClaimEvent<SwapData>): Promise<void>;
156
- protected abstract processRefundEvent?(chainIdentifier: string, swap: V, event: RefundEvent<SwapData>): Promise<void>;
157
-
158
- /**
159
- * Chain event processor
160
- *
161
- * @param chainIdentifier
162
- * @param eventData
163
- */
164
- protected async processEvent(chainIdentifier: string, eventData: SwapEvent<SwapData>[]): Promise<boolean> {
165
- if(this.swapType==null) return true;
166
-
167
- for(let event of eventData) {
168
- if(event instanceof InitializeEvent) {
169
- if(event.swapType!==this.swapType) continue;
170
- const swap = this.getSwapByEscrowHash(chainIdentifier, event.escrowHash);
171
- if(swap==null) continue;
172
-
173
- swap.txIds.init = (event as any).meta?.txId;
174
- if(swap.metadata!=null) swap.metadata.times.initTxReceived = Date.now();
175
-
176
- await this.processInitializeEvent(chainIdentifier, swap, event);
177
- } else if(event instanceof ClaimEvent) {
178
- const swap = this.getSwapByEscrowHash(chainIdentifier, event.escrowHash);
179
- if(swap==null) continue;
180
-
181
- swap.txIds.claim = (event as any).meta?.txId;
182
- if(swap.metadata!=null) swap.metadata.times.claimTxReceived = Date.now();
183
-
184
- await this.processClaimEvent(chainIdentifier, swap, event);
185
- } else if(event instanceof RefundEvent) {
186
- const swap = this.getSwapByEscrowHash(chainIdentifier, event.escrowHash);
187
- if(swap==null) continue;
188
-
189
- swap.txIds.refund = (event as any).meta?.txId;
190
- if(swap.metadata!=null) swap.metadata.times.refundTxReceived = Date.now();
191
-
192
- await this.processRefundEvent(chainIdentifier, swap, event);
193
- }
194
- }
195
-
196
- return true;
197
- }
198
-
199
- /**
200
- * Initializes chain events subscription
201
- */
202
- protected subscribeToEvents() {
203
- for(let key in this.chains.chains) {
204
- this.chains.chains[key].chainEvents.registerListener((events: SwapEvent<SwapData>[]) => this.processEvent(key, events));
205
- }
206
- this.logger.info("SC: Events: subscribed to smartchain events");
207
- }
208
-
209
146
  /**
210
147
  * Initializes swap handler, loads data and subscribes to chain events
211
148
  */
@@ -223,7 +160,6 @@ export abstract class SwapHandler<V extends SwapHandlerSwap<SwapData, S> = SwapH
223
160
  await this.storageManager.removeData(hash, sequence);
224
161
  await this.storageManager.saveData(swap.getIdentifierHash(), swap.getSequence(), swap);
225
162
  }
226
- this.saveSwapToEscrowHashMap(swap);
227
163
  }
228
164
  }
229
165
 
@@ -266,152 +202,33 @@ export abstract class SwapHandler<V extends SwapHandlerSwap<SwapData, S> = SwapH
266
202
  }
267
203
  if(swap!=null) await PluginManager.swapRemove(swap);
268
204
  this.swapLogger.debug(swap, "removeSwapData(): removing swap final state: "+swap.state);
269
- this.removeSwapFromEscrowHashMap(swap);
270
205
  await this.storageManager.removeData(swap.getIdentifierHash(), swap.getSequence());
271
206
  }
272
207
 
273
208
  protected async saveSwapData(swap: V) {
274
- this.saveSwapToEscrowHashMap(swap);
275
209
  await this.storageManager.saveData(swap.getIdentifierHash(), swap.getSequence(), swap);
276
210
  }
277
211
 
278
- protected saveSwapToEscrowHashMap(swap: V) {
279
- if(swap.data!=null) this.escrowHashMap.set(swap.chainIdentifier+"_"+swap.getEscrowHash(), swap);
280
- }
281
-
282
- protected removeSwapFromEscrowHashMap(swap: V) {
283
- if(swap.data!=null) this.escrowHashMap.delete(swap.chainIdentifier+"_"+swap.data.getEscrowHash());
284
- }
285
-
286
- protected getSwapByEscrowHash(chainIdentifier: string, escrowHash: string) {
287
- return this.escrowHashMap.get(chainIdentifier+"_"+escrowHash);
288
- }
289
-
290
212
  /**
291
- * Checks whether the bitcoin amount is within specified min/max bounds
213
+ * Checks if we have enough balance of the token in the swap vault
292
214
  *
293
- * @param amount
294
- * @protected
295
- * @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
215
+ * @param totalInToken
216
+ * @param balancePrefetch
217
+ * @param signal
218
+ * @throws {DefinedRuntimeError} will throw an error if there are not enough funds in the vault
296
219
  */
297
- protected checkBtcAmountInBounds(amount: bigint): void {
298
- if (amount < this.config.min) {
299
- throw {
300
- code: 20003,
301
- msg: "Amount too low!",
302
- data: {
303
- min: this.config.min.toString(10),
304
- max: this.config.max.toString(10)
305
- }
306
- };
307
- }
220
+ protected async checkBalance(totalInToken: bigint, balancePrefetch: Promise<bigint>, signal: AbortSignal | null): Promise<void> {
221
+ const balance = await balancePrefetch;
222
+ if(signal!=null) signal.throwIfAborted();
308
223
 
309
- if(amount > this.config.max) {
224
+ if(balance==null || balance < totalInToken) {
310
225
  throw {
311
- code: 20004,
312
- msg: "Amount too high!",
313
- data: {
314
- min: this.config.min.toString(10),
315
- max: this.config.max.toString(10)
316
- }
226
+ code: 20002,
227
+ msg: "Not enough liquidity"
317
228
  };
318
229
  }
319
230
  }
320
231
 
321
- /**
322
- * Handles and throws plugin errors
323
- *
324
- * @param res Response as returned from the PluginManager.onHandlePost{To,From}BtcQuote
325
- * @protected
326
- * @throws {DefinedRuntimeError} will throw an error if the response is an error
327
- */
328
- protected handlePluginErrorResponses(res: any): void {
329
- if(isQuoteThrow(res)) throw {
330
- code: 29999,
331
- msg: res.message
332
- };
333
- if(isQuoteAmountTooHigh(res)) throw {
334
- code: 20004,
335
- msg: "Amount too high!",
336
- data: {
337
- min: res.data.min.toString(10),
338
- max: res.data.max.toString(10)
339
- }
340
- };
341
- if(isQuoteAmountTooLow(res)) throw {
342
- code: 20003,
343
- msg: "Amount too low!",
344
- data: {
345
- min: res.data.min.toString(10),
346
- max: res.data.max.toString(10)
347
- }
348
- };
349
- }
350
-
351
- /**
352
- * Creates an abort controller that extends the responseStream's abort signal
353
- *
354
- * @param responseStream
355
- */
356
- protected getAbortController(responseStream: ServerParamEncoder): AbortController {
357
- const abortController = new AbortController();
358
- if(responseStream==null || responseStream.getAbortSignal==null) return abortController;
359
- const responseStreamAbortController = responseStream.getAbortSignal();
360
- responseStreamAbortController.addEventListener("abort", () => abortController.abort(responseStreamAbortController.reason));
361
- return abortController;
362
- }
363
-
364
- /**
365
- * Starts a pre-fetch for signature data
366
- *
367
- * @param chainIdentifier
368
- * @param abortController
369
- * @param responseStream
370
- */
371
- protected getSignDataPrefetch(chainIdentifier: string, abortController: AbortController, responseStream?: ServerParamEncoder): Promise<any> {
372
- const {swapContract} = this.getChain(chainIdentifier);
373
- let signDataPrefetchPromise: Promise<any> = swapContract.preFetchBlockDataForSignatures!=null ? swapContract.preFetchBlockDataForSignatures().catch(e => {
374
- this.logger.error("getSignDataPrefetch(): signDataPrefetch: ", e);
375
- abortController.abort(e);
376
- return null;
377
- }) : null;
378
-
379
- if(signDataPrefetchPromise!=null && responseStream!=null) {
380
- signDataPrefetchPromise = signDataPrefetchPromise.then(val => val==null || abortController.signal.aborted ? null : responseStream.writeParams({
381
- signDataPrefetch: val
382
- }).then(() => val).catch(e => {
383
- this.logger.error("getSignDataPrefetch(): signDataPreFetch: error when sending sign data to the client: ", e);
384
- abortController.abort(e);
385
- return null;
386
- }));
387
- }
388
-
389
- return signDataPrefetchPromise;
390
- }
391
-
392
- protected getIdentifierFromEvent(event: SwapEvent<SwapData>): string {
393
- const foundSwap = this.escrowHashMap.get(event.escrowHash);
394
- if(foundSwap!=null) {
395
- return foundSwap.getIdentifier();
396
- }
397
- return "UNKNOWN_"+event.escrowHash;
398
- }
399
-
400
- protected getIdentifierFromSwapData(swapData: SwapData): string {
401
- if(swapData.getSequence==null) return swapData.getClaimHash();
402
- return swapData.getClaimHash()+"_"+swapData.getSequence().toString(16);
403
- }
404
-
405
- protected getIdentifier(swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData) {
406
- if(swap instanceof SwapHandlerSwap) {
407
- return swap.getIdentifier();
408
- }
409
- if(swap instanceof SwapEvent) {
410
- return this.getIdentifierFromEvent(swap);
411
- }
412
- return this.getIdentifierFromSwapData(swap);
413
- }
414
-
415
232
  /**
416
233
  * Checks if the sequence number is between 0-2^64
417
234
  *