@atomiqlabs/lp-lib 16.0.2 → 16.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/swaps/SwapHandler.d.ts +28 -0
- package/dist/swaps/SwapHandler.js +63 -0
- package/dist/swaps/escrow/frombtc_abstract/FromBtcAbs.d.ts +1 -0
- package/dist/swaps/escrow/frombtc_abstract/FromBtcAbs.js +4 -0
- package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnAbs.d.ts +1 -0
- package/dist/swaps/escrow/frombtcln_abstract/FromBtcLnAbs.js +27 -5
- package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.d.ts +1 -7
- package/dist/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.js +7 -41
- package/dist/swaps/escrow/tobtc_abstract/ToBtcAbs.d.ts +1 -0
- package/dist/swaps/escrow/tobtc_abstract/ToBtcAbs.js +5 -0
- package/dist/swaps/escrow/tobtcln_abstract/ToBtcLnAbs.d.ts +2 -1
- package/dist/swaps/escrow/tobtcln_abstract/ToBtcLnAbs.js +23 -2
- package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.d.ts +1 -0
- package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.js +9 -0
- package/dist/swaps/trusted/frombtc_trusted/FromBtcTrusted.d.ts +1 -0
- package/dist/swaps/trusted/frombtc_trusted/FromBtcTrusted.js +12 -0
- package/dist/swaps/trusted/frombtcln_trusted/FromBtcLnTrusted.d.ts +1 -0
- package/dist/swaps/trusted/frombtcln_trusted/FromBtcLnTrusted.js +12 -0
- package/package.json +1 -1
- package/src/swaps/SwapHandler.ts +69 -1
- package/src/swaps/escrow/frombtc_abstract/FromBtcAbs.ts +5 -0
- package/src/swaps/escrow/frombtcln_abstract/FromBtcLnAbs.ts +24 -6
- package/src/swaps/escrow/frombtcln_autoinit/FromBtcLnAuto.ts +7 -46
- package/src/swaps/escrow/tobtc_abstract/ToBtcAbs.ts +6 -0
- package/src/swaps/escrow/tobtcln_abstract/ToBtcLnAbs.ts +23 -4
- package/src/swaps/spv_vault_swap/SpvVaultSwapHandler.ts +16 -3
- package/src/swaps/trusted/frombtc_trusted/FromBtcTrusted.ts +15 -0
- package/src/swaps/trusted/frombtcln_trusted/FromBtcLnTrusted.ts +15 -1
|
@@ -30,6 +30,10 @@ export type SwapBaseConfig = {
|
|
|
30
30
|
initAuthorizationTimeouts?: {
|
|
31
31
|
[chainId: string]: number;
|
|
32
32
|
};
|
|
33
|
+
minNativeBalances?: {
|
|
34
|
+
[chainId: string]: bigint;
|
|
35
|
+
};
|
|
36
|
+
maxInflightSwaps?: number;
|
|
33
37
|
bitcoinBlocktime: bigint;
|
|
34
38
|
baseFee: bigint;
|
|
35
39
|
feePPM: bigint;
|
|
@@ -76,7 +80,9 @@ export declare abstract class SwapHandler<V extends SwapHandlerSwap<S> = SwapHan
|
|
|
76
80
|
[chainId: string]: Set<string>;
|
|
77
81
|
};
|
|
78
82
|
readonly swapPricing: ISwapPrice;
|
|
83
|
+
abstract readonly inflightSwapStates: Set<S>;
|
|
79
84
|
abstract config: SwapBaseConfig;
|
|
85
|
+
inflightSwaps: Set<SwapHandlerSwap<S>>;
|
|
80
86
|
logger: LoggerType;
|
|
81
87
|
protected swapLogger: {
|
|
82
88
|
debug: (swap: SwapHandlerSwap, msg: string, ...args: any) => void;
|
|
@@ -114,6 +120,28 @@ export declare abstract class SwapHandler<V extends SwapHandlerSwap<S> = SwapHan
|
|
|
114
120
|
*/
|
|
115
121
|
protected removeSwapData(swap: V, ultimateState?: S): Promise<void>;
|
|
116
122
|
protected saveSwapData(swap: V): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Pre-fetches native balance to further check if we have enough reserve in a native token
|
|
125
|
+
*
|
|
126
|
+
* @param chainIdentifier
|
|
127
|
+
* @param abortController
|
|
128
|
+
* @protected
|
|
129
|
+
*/
|
|
130
|
+
protected prefetchNativeBalanceIfNeeded(chainIdentifier: string, abortController: AbortController): Promise<bigint> | null;
|
|
131
|
+
/**
|
|
132
|
+
* Checks if we have enough native balance to facilitate swaps
|
|
133
|
+
*
|
|
134
|
+
* @param chainIdentifier
|
|
135
|
+
* @param balancePrefetch
|
|
136
|
+
* @param signal
|
|
137
|
+
* @throws {DefinedRuntimeError} will throw an error if there are not enough funds in the vault
|
|
138
|
+
*/
|
|
139
|
+
protected checkNativeBalance(chainIdentifier: string, balancePrefetch: Promise<bigint>, signal: AbortSignal | null): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Checks whether there are too many swaps in-flight currently
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
protected checkTooManyInflightSwaps(): void;
|
|
117
145
|
/**
|
|
118
146
|
* Checks if we have enough balance of the token in the swap vault
|
|
119
147
|
*
|
|
@@ -19,6 +19,7 @@ var SwapHandlerType;
|
|
|
19
19
|
*/
|
|
20
20
|
class SwapHandler {
|
|
21
21
|
constructor(storageDirectory, path, chainsData, swapPricing) {
|
|
22
|
+
this.inflightSwaps = new Set();
|
|
22
23
|
this.logger = (0, Utils_1.getLogger)(() => "SwapHandler(" + this.type + "): ");
|
|
23
24
|
this.swapLogger = {
|
|
24
25
|
debug: (swap, msg, ...args) => this.logger.debug(swap.getIdentifier() + ": " + msg, ...args),
|
|
@@ -65,6 +66,8 @@ class SwapHandler {
|
|
|
65
66
|
await this.storageManager.removeData(hash, sequence);
|
|
66
67
|
await this.storageManager.saveData(swap.getIdentifierHash(), swap.getSequence(), swap);
|
|
67
68
|
}
|
|
69
|
+
if (this.inflightSwapStates.has(swap.state))
|
|
70
|
+
this.inflightSwaps.add(swap);
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
/**
|
|
@@ -74,6 +77,7 @@ class SwapHandler {
|
|
|
74
77
|
* @param ultimateState set the ultimate state of the swap before removing
|
|
75
78
|
*/
|
|
76
79
|
async removeSwapData(swap, ultimateState) {
|
|
80
|
+
this.inflightSwaps.delete(swap);
|
|
77
81
|
if (ultimateState != null)
|
|
78
82
|
await swap.setState(ultimateState);
|
|
79
83
|
if (swap != null)
|
|
@@ -82,8 +86,67 @@ class SwapHandler {
|
|
|
82
86
|
await this.storageManager.removeData(swap.getIdentifierHash(), swap.getSequence());
|
|
83
87
|
}
|
|
84
88
|
async saveSwapData(swap) {
|
|
89
|
+
if (this.inflightSwapStates.has(swap.state)) {
|
|
90
|
+
this.inflightSwaps.add(swap);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.inflightSwaps.delete(swap);
|
|
94
|
+
}
|
|
85
95
|
await this.storageManager.saveData(swap.getIdentifierHash(), swap.getSequence(), swap);
|
|
86
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Pre-fetches native balance to further check if we have enough reserve in a native token
|
|
99
|
+
*
|
|
100
|
+
* @param chainIdentifier
|
|
101
|
+
* @param abortController
|
|
102
|
+
* @protected
|
|
103
|
+
*/
|
|
104
|
+
prefetchNativeBalanceIfNeeded(chainIdentifier, abortController) {
|
|
105
|
+
const minNativeTokenReserve = this.config.minNativeBalances?.[chainIdentifier] ?? 0n;
|
|
106
|
+
if (minNativeTokenReserve === 0n)
|
|
107
|
+
return null;
|
|
108
|
+
const { chainInterface, signer } = this.getChain(chainIdentifier);
|
|
109
|
+
return chainInterface.getBalance(signer.getAddress(), chainInterface.getNativeCurrencyAddress()).catch(e => {
|
|
110
|
+
this.logger.error("getBalancePrefetch(): balancePrefetch error: ", e);
|
|
111
|
+
abortController.abort(e);
|
|
112
|
+
return null;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Checks if we have enough native balance to facilitate swaps
|
|
117
|
+
*
|
|
118
|
+
* @param chainIdentifier
|
|
119
|
+
* @param balancePrefetch
|
|
120
|
+
* @param signal
|
|
121
|
+
* @throws {DefinedRuntimeError} will throw an error if there are not enough funds in the vault
|
|
122
|
+
*/
|
|
123
|
+
async checkNativeBalance(chainIdentifier, balancePrefetch, signal) {
|
|
124
|
+
if (signal != null)
|
|
125
|
+
signal.throwIfAborted();
|
|
126
|
+
const minNativeTokenReserve = this.config.minNativeBalances?.[chainIdentifier] ?? 0n;
|
|
127
|
+
if (minNativeTokenReserve === 0n)
|
|
128
|
+
return;
|
|
129
|
+
const balance = await balancePrefetch;
|
|
130
|
+
if (balance == null || balance < minNativeTokenReserve) {
|
|
131
|
+
throw {
|
|
132
|
+
code: 20012,
|
|
133
|
+
msg: "LP ran out of native token to cover gas fees"
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Checks whether there are too many swaps in-flight currently
|
|
139
|
+
* @private
|
|
140
|
+
*/
|
|
141
|
+
checkTooManyInflightSwaps() {
|
|
142
|
+
if (this.config.maxInflightSwaps == null)
|
|
143
|
+
return;
|
|
144
|
+
if (this.inflightSwaps.size >= this.config.maxInflightSwaps)
|
|
145
|
+
throw {
|
|
146
|
+
code: 20013,
|
|
147
|
+
msg: "LP has too many in-flight swaps, retry later!"
|
|
148
|
+
};
|
|
149
|
+
}
|
|
87
150
|
/**
|
|
88
151
|
* Checks if we have enough balance of the token in the swap vault
|
|
89
152
|
*
|
|
@@ -23,6 +23,7 @@ export type FromBtcRequestType = {
|
|
|
23
23
|
export declare class FromBtcAbs extends FromBtcBaseSwapHandler<FromBtcSwapAbs, FromBtcSwapState> {
|
|
24
24
|
readonly type = SwapHandlerType.FROM_BTC;
|
|
25
25
|
readonly swapType = ChainSwapType.CHAIN;
|
|
26
|
+
readonly inflightSwapStates: Set<FromBtcSwapState>;
|
|
26
27
|
readonly config: FromBtcConfig & {
|
|
27
28
|
swapTsCsvDelta: bigint;
|
|
28
29
|
};
|
|
@@ -18,6 +18,7 @@ class FromBtcAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
18
18
|
super(storageDirectory, path, chains, swapPricing, config);
|
|
19
19
|
this.type = SwapHandler_1.SwapHandlerType.FROM_BTC;
|
|
20
20
|
this.swapType = base_1.ChainSwapType.CHAIN;
|
|
21
|
+
this.inflightSwapStates = new Set([FromBtcSwapAbs_1.FromBtcSwapState.COMMITED]);
|
|
21
22
|
this.bitcoin = bitcoin;
|
|
22
23
|
this.config = {
|
|
23
24
|
...config,
|
|
@@ -225,6 +226,7 @@ class FromBtcAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
225
226
|
};
|
|
226
227
|
const useToken = parsedBody.token;
|
|
227
228
|
//Check request params
|
|
229
|
+
this.checkTooManyInflightSwaps();
|
|
228
230
|
this.checkSequence(parsedBody.sequence);
|
|
229
231
|
const fees = await this.AmountAssertions.preCheckFromBtcAmounts(this.type, request, requestedAmount);
|
|
230
232
|
metadata.times.requestChecked = Date.now();
|
|
@@ -235,9 +237,11 @@ class FromBtcAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
235
237
|
const { pricePrefetchPromise, gasTokenPricePrefetchPromise, depositTokenPricePrefetchPromise } = this.getFromBtcPricePrefetches(chainIdentifier, useToken, depositToken, abortController);
|
|
236
238
|
const balancePrefetch = this.getBalancePrefetch(chainIdentifier, useToken, abortController);
|
|
237
239
|
const signDataPrefetchPromise = this.getSignDataPrefetch(chainIdentifier, abortController, responseStream);
|
|
240
|
+
const nativeBalancePrefetch = this.prefetchNativeBalanceIfNeeded(chainIdentifier, abortController);
|
|
238
241
|
const dummySwapData = await this.getDummySwapData(chainIdentifier, useToken, parsedBody.address);
|
|
239
242
|
abortController.signal.throwIfAborted();
|
|
240
243
|
const baseSDPromise = this.getBaseSecurityDepositPrefetch(chainIdentifier, dummySwapData, depositToken, gasTokenPricePrefetchPromise, depositTokenPricePrefetchPromise, abortController);
|
|
244
|
+
await this.checkNativeBalance(chainIdentifier, nativeBalancePrefetch, abortController.signal);
|
|
241
245
|
//Check valid amount specified (min/max)
|
|
242
246
|
const { amountBD, swapFee, swapFeeInToken, totalInToken, securityDepositApyPPM, securityDepositBaseMultiplierPPM } = await this.AmountAssertions.checkFromBtcAmount(this.type, request, { ...requestedAmount, pricePrefetch: pricePrefetchPromise }, fees, abortController.signal);
|
|
243
247
|
metadata.times.priceCalculated = Date.now();
|
|
@@ -26,6 +26,7 @@ export type FromBtcLnRequestType = {
|
|
|
26
26
|
export declare class FromBtcLnAbs extends FromBtcBaseSwapHandler<FromBtcLnSwapAbs, FromBtcLnSwapState> {
|
|
27
27
|
readonly type = SwapHandlerType.FROM_BTCLN;
|
|
28
28
|
readonly swapType = ChainSwapType.HTLC;
|
|
29
|
+
readonly inflightSwapStates: Set<FromBtcLnSwapState>;
|
|
29
30
|
readonly config: FromBtcLnConfig;
|
|
30
31
|
readonly lightning: ILightningWallet;
|
|
31
32
|
readonly LightningAssertions: LightningAssertions;
|
|
@@ -19,6 +19,7 @@ class FromBtcLnAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
19
19
|
super(storageDirectory, path, chains, swapPricing, config);
|
|
20
20
|
this.type = SwapHandler_1.SwapHandlerType.FROM_BTCLN;
|
|
21
21
|
this.swapType = base_1.ChainSwapType.HTLC;
|
|
22
|
+
this.inflightSwapStates = new Set([FromBtcLnSwapAbs_1.FromBtcLnSwapState.RECEIVED, FromBtcLnSwapAbs_1.FromBtcLnSwapState.COMMITED, FromBtcLnSwapAbs_1.FromBtcLnSwapState.CLAIMED]);
|
|
22
23
|
this.config = config;
|
|
23
24
|
this.config.invoiceTimeoutSeconds = this.config.invoiceTimeoutSeconds || 90;
|
|
24
25
|
this.lightning = lightning;
|
|
@@ -48,11 +49,6 @@ class FromBtcLnAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
48
49
|
catch (e) {
|
|
49
50
|
this.swapLogger.error(swap, "processPastSwap(state=CREATED): htlcReceived error", e);
|
|
50
51
|
}
|
|
51
|
-
// @ts-ignore Previous call (htlcReceived) mutates the state of the swap, so this is valid
|
|
52
|
-
if (swap.state === FromBtcLnSwapAbs_1.FromBtcLnSwapState.CANCELED) {
|
|
53
|
-
this.swapLogger.info(swap, "processPastSwap(state=CREATED): invoice CANCELED after htlcReceived(), cancelling, invoice: " + swap.pr);
|
|
54
|
-
return "CANCEL";
|
|
55
|
-
}
|
|
56
52
|
return null;
|
|
57
53
|
}
|
|
58
54
|
if (swap.state === FromBtcLnSwapAbs_1.FromBtcLnSwapState.RECEIVED || swap.state === FromBtcLnSwapAbs_1.FromBtcLnSwapState.COMMITED) {
|
|
@@ -248,6 +244,16 @@ class FromBtcLnAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
248
244
|
invoiceData.metadata.times.htlcReceived = Date.now();
|
|
249
245
|
const useToken = invoiceData.token;
|
|
250
246
|
const escrowAmount = invoiceData.totalTokens;
|
|
247
|
+
try {
|
|
248
|
+
this.checkTooManyInflightSwaps();
|
|
249
|
+
}
|
|
250
|
+
catch (e) {
|
|
251
|
+
if ((0, Utils_1.isDefinedRuntimeError)(e) && invoiceData.metadata != null)
|
|
252
|
+
invoiceData.metadata.htlcReceiveError = e;
|
|
253
|
+
if (invoiceData.state === FromBtcLnSwapAbs_1.FromBtcLnSwapState.CREATED)
|
|
254
|
+
await this.cancelSwapAndInvoice(invoiceData);
|
|
255
|
+
throw e;
|
|
256
|
+
}
|
|
251
257
|
//Create abort controller for parallel fetches
|
|
252
258
|
const abortController = new AbortController();
|
|
253
259
|
//Pre-fetch data
|
|
@@ -267,6 +273,8 @@ class FromBtcLnAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
267
273
|
}
|
|
268
274
|
catch (e) {
|
|
269
275
|
if (!abortController.signal.aborted) {
|
|
276
|
+
if ((0, Utils_1.isDefinedRuntimeError)(e) && invoiceData.metadata != null)
|
|
277
|
+
invoiceData.metadata.htlcReceiveError = e;
|
|
270
278
|
if (invoiceData.state === FromBtcLnSwapAbs_1.FromBtcLnSwapState.CREATED)
|
|
271
279
|
await this.cancelSwapAndInvoice(invoiceData);
|
|
272
280
|
}
|
|
@@ -285,6 +293,17 @@ class FromBtcLnAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
285
293
|
invoiceData.metadata.times.htlcSwapSigned = Date.now();
|
|
286
294
|
//Important to prevent race condition and issuing 2 signed init messages at the same time
|
|
287
295
|
if (invoiceData.state === FromBtcLnSwapAbs_1.FromBtcLnSwapState.CREATED) {
|
|
296
|
+
//Re-check right before signing
|
|
297
|
+
try {
|
|
298
|
+
this.checkTooManyInflightSwaps();
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
if ((0, Utils_1.isDefinedRuntimeError)(e) && invoiceData.metadata != null)
|
|
302
|
+
invoiceData.metadata.htlcReceiveError = e;
|
|
303
|
+
if (invoiceData.state === FromBtcLnSwapAbs_1.FromBtcLnSwapState.CREATED)
|
|
304
|
+
await this.cancelSwapAndInvoice(invoiceData);
|
|
305
|
+
throw e;
|
|
306
|
+
}
|
|
288
307
|
invoiceData.data = payInvoiceObject;
|
|
289
308
|
invoiceData.prefix = sigData.prefix;
|
|
290
309
|
invoiceData.timeout = sigData.timeout;
|
|
@@ -500,6 +519,7 @@ class FromBtcLnAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
500
519
|
};
|
|
501
520
|
const useToken = parsedBody.token;
|
|
502
521
|
//Check request params
|
|
522
|
+
this.checkTooManyInflightSwaps();
|
|
503
523
|
this.checkDescriptionHash(parsedBody.descriptionHash);
|
|
504
524
|
const fees = await this.AmountAssertions.preCheckFromBtcAmounts(this.type, request, requestedAmount);
|
|
505
525
|
metadata.times.requestChecked = Date.now();
|
|
@@ -510,11 +530,13 @@ class FromBtcLnAbs extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
510
530
|
const { pricePrefetchPromise, gasTokenPricePrefetchPromise, depositTokenPricePrefetchPromise } = this.getFromBtcPricePrefetches(chainIdentifier, useToken, depositToken, abortController);
|
|
511
531
|
const balancePrefetch = this.getBalancePrefetch(chainIdentifier, useToken, abortController);
|
|
512
532
|
const channelsPrefetch = this.LightningAssertions.getChannelsPrefetch(abortController);
|
|
533
|
+
const nativeBalancePrefetch = this.prefetchNativeBalanceIfNeeded(chainIdentifier, abortController);
|
|
513
534
|
const dummySwapData = await this.getDummySwapData(chainIdentifier, useToken, parsedBody.address, parsedBody.paymentHash);
|
|
514
535
|
abortController.signal.throwIfAborted();
|
|
515
536
|
const baseSDPromise = this.getBaseSecurityDepositPrefetch(chainIdentifier, dummySwapData, depositToken, gasTokenPricePrefetchPromise, depositTokenPricePrefetchPromise, abortController);
|
|
516
537
|
//Asynchronously send the node's public key to the client
|
|
517
538
|
this.sendPublicKeyAsync(responseStream);
|
|
539
|
+
await this.checkNativeBalance(chainIdentifier, nativeBalancePrefetch, abortController.signal);
|
|
518
540
|
//Check valid amount specified (min/max)
|
|
519
541
|
const { amountBD, swapFee, swapFeeInToken, totalInToken, securityDepositApyPPM, securityDepositBaseMultiplierPPM } = await this.AmountAssertions.checkFromBtcAmount(this.type, request, { ...requestedAmount, pricePrefetch: pricePrefetchPromise }, fees, abortController.signal);
|
|
520
542
|
metadata.times.priceCalculated = Date.now();
|
|
@@ -8,10 +8,6 @@ import { FromBtcBaseConfig, FromBtcBaseSwapHandler } from "../FromBtcBaseSwapHan
|
|
|
8
8
|
import { ILightningWallet } from "../../../wallets/ILightningWallet";
|
|
9
9
|
import { LightningAssertions } from "../../assertions/LightningAssertions";
|
|
10
10
|
export type FromBtcLnAutoConfig = FromBtcBaseConfig & {
|
|
11
|
-
maxInflightHtlcs?: number;
|
|
12
|
-
minNativeBalances?: {
|
|
13
|
-
[chainId: string]: bigint;
|
|
14
|
-
};
|
|
15
11
|
invoiceTimeoutSeconds?: number;
|
|
16
12
|
minCltv: bigint;
|
|
17
13
|
gracePeriod: bigint;
|
|
@@ -36,8 +32,8 @@ export type FromBtcLnAutoRequestType = {
|
|
|
36
32
|
export declare class FromBtcLnAuto extends FromBtcBaseSwapHandler<FromBtcLnAutoSwap, FromBtcLnAutoSwapState> {
|
|
37
33
|
readonly type = SwapHandlerType.FROM_BTCLN_AUTO;
|
|
38
34
|
readonly swapType = ChainSwapType.HTLC;
|
|
35
|
+
readonly inflightSwapStates: Set<FromBtcLnAutoSwapState>;
|
|
39
36
|
activeSubscriptions: Set<string>;
|
|
40
|
-
swapsWithInflighHtlcs: Set<FromBtcLnAutoSwap>;
|
|
41
37
|
readonly config: FromBtcLnAutoConfig;
|
|
42
38
|
readonly lightning: ILightningWallet;
|
|
43
39
|
readonly LightningAssertions: LightningAssertions;
|
|
@@ -110,9 +106,7 @@ export declare class FromBtcLnAuto extends FromBtcBaseSwapHandler<FromBtcLnAutoS
|
|
|
110
106
|
* @returns the fetched lightning invoice
|
|
111
107
|
*/
|
|
112
108
|
private checkInvoiceStatus;
|
|
113
|
-
private checkTooManyInflightHtlcs;
|
|
114
109
|
startRestServer(restServer: Express): void;
|
|
115
110
|
init(): Promise<void>;
|
|
116
111
|
getInfoData(): any;
|
|
117
|
-
protected removeSwapData(swap: FromBtcLnAutoSwap, ultimateState?: FromBtcLnAutoSwapState): Promise<void>;
|
|
118
112
|
}
|
|
@@ -19,8 +19,8 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
19
19
|
super(storageDirectory, path, chains, swapPricing, config);
|
|
20
20
|
this.type = SwapHandler_1.SwapHandlerType.FROM_BTCLN_AUTO;
|
|
21
21
|
this.swapType = base_1.ChainSwapType.HTLC;
|
|
22
|
+
this.inflightSwapStates = new Set([FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.TXS_SENT, FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.COMMITED, FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.CLAIMED]);
|
|
22
23
|
this.activeSubscriptions = new Set();
|
|
23
|
-
this.swapsWithInflighHtlcs = new Set();
|
|
24
24
|
this.config = config;
|
|
25
25
|
this.config.invoiceTimeoutSeconds = this.config.invoiceTimeoutSeconds || 90;
|
|
26
26
|
this.lightning = lightning;
|
|
@@ -64,7 +64,6 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
64
64
|
return null;
|
|
65
65
|
}
|
|
66
66
|
if (swap.state === FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.TXS_SENT || swap.state === FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.COMMITED) {
|
|
67
|
-
this.swapsWithInflighHtlcs.add(swap);
|
|
68
67
|
const onchainStatus = await swapContract.getCommitStatus(signer.getAddress(), swap.data);
|
|
69
68
|
const state = swap.state;
|
|
70
69
|
if (onchainStatus.type === base_1.SwapCommitStateType.PAID) {
|
|
@@ -285,7 +284,7 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
285
284
|
if (invoiceData.state !== FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.RECEIVED)
|
|
286
285
|
return;
|
|
287
286
|
try {
|
|
288
|
-
this.
|
|
287
|
+
this.checkTooManyInflightSwaps();
|
|
289
288
|
}
|
|
290
289
|
catch (e) {
|
|
291
290
|
if ((0, Utils_1.isDefinedRuntimeError)(e) && invoiceData.metadata != null)
|
|
@@ -302,14 +301,10 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
302
301
|
const { swapContract, signer, chainInterface } = this.getChain(invoiceData.chainIdentifier);
|
|
303
302
|
//Create abort controller for parallel fetches
|
|
304
303
|
const abortController = new AbortController();
|
|
305
|
-
//Minimum reserve of native token to be kept in the wallet
|
|
306
|
-
const minNativeTokenReserve = this.config.minNativeBalances?.[invoiceData.chainIdentifier] ?? 0n;
|
|
307
304
|
//Pre-fetch data
|
|
308
305
|
const balancePrefetch = this.getBalancePrefetch(invoiceData.chainIdentifier, useToken, abortController);
|
|
309
306
|
const gasTokenBalancePrefetch = invoiceData.getTotalOutputGasAmount() === 0n || useToken === gasToken ?
|
|
310
307
|
null : this.getBalancePrefetch(invoiceData.chainIdentifier, gasToken, abortController);
|
|
311
|
-
const nativeBalancePrefetch = minNativeTokenReserve === 0n ?
|
|
312
|
-
null : this.getBalancePrefetch(invoiceData.chainIdentifier, chainInterface.getNativeCurrencyAddress(), abortController, false);
|
|
313
308
|
if (await swapContract.getInitAuthorizationExpiry(invoiceData.data, invoiceData) < Date.now()) {
|
|
314
309
|
if (invoiceData.metadata != null)
|
|
315
310
|
invoiceData.metadata.htlcOfferError = "Init authorization expired, before being sent!";
|
|
@@ -318,18 +313,6 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
318
313
|
}
|
|
319
314
|
return false;
|
|
320
315
|
}
|
|
321
|
-
try {
|
|
322
|
-
await this.checkBalance(minNativeTokenReserve, nativeBalancePrefetch, abortController.signal);
|
|
323
|
-
}
|
|
324
|
-
catch (e) {
|
|
325
|
-
if (!abortController.signal.aborted) {
|
|
326
|
-
if ((0, Utils_1.isDefinedRuntimeError)(e) && invoiceData.metadata != null)
|
|
327
|
-
invoiceData.metadata.htlcOfferError = "Not enough native balance!";
|
|
328
|
-
if (invoiceData.state === FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.RECEIVED)
|
|
329
|
-
await this.cancelSwapAndInvoice(invoiceData);
|
|
330
|
-
}
|
|
331
|
-
throw e;
|
|
332
|
-
}
|
|
333
316
|
try {
|
|
334
317
|
//Check if we have enough liquidity to proceed
|
|
335
318
|
if (useToken === gasToken) {
|
|
@@ -360,7 +343,7 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
360
343
|
if (invoiceData.state === FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.RECEIVED) {
|
|
361
344
|
//Re-check the current HTLC count
|
|
362
345
|
try {
|
|
363
|
-
this.
|
|
346
|
+
this.checkTooManyInflightSwaps();
|
|
364
347
|
}
|
|
365
348
|
catch (e) {
|
|
366
349
|
if ((0, Utils_1.isDefinedRuntimeError)(e) && invoiceData.metadata != null)
|
|
@@ -369,8 +352,7 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
369
352
|
await this.cancelSwapAndInvoice(invoiceData);
|
|
370
353
|
throw e;
|
|
371
354
|
}
|
|
372
|
-
this.swapLogger.debug(invoiceData, `offerHtlc(): Sending HTLC offer, current in flight
|
|
373
|
-
this.swapsWithInflighHtlcs.add(invoiceData);
|
|
355
|
+
this.swapLogger.debug(invoiceData, `offerHtlc(): Sending HTLC offer, current in flight swaps: ${this.inflightSwaps.size}, invoice: `, invoiceData.pr);
|
|
374
356
|
//Setting the state variable is done outside the promise, so is done synchronously
|
|
375
357
|
await invoiceData.setState(FromBtcLnAutoSwap_1.FromBtcLnAutoSwapState.TXS_SENT);
|
|
376
358
|
await this.saveSwapData(invoiceData);
|
|
@@ -511,15 +493,6 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
511
493
|
return invoice;
|
|
512
494
|
}
|
|
513
495
|
}
|
|
514
|
-
checkTooManyInflightHtlcs() {
|
|
515
|
-
if (this.config.maxInflightHtlcs == null)
|
|
516
|
-
return;
|
|
517
|
-
if (this.swapsWithInflighHtlcs.size >= this.config.maxInflightHtlcs)
|
|
518
|
-
throw {
|
|
519
|
-
code: 20401,
|
|
520
|
-
msg: "Too many in-flight HTLCs, retry later!"
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
496
|
startRestServer(restServer) {
|
|
524
497
|
restServer.use(this.path + "/createInvoice", (0, ServerParamDecoder_1.serverParamDecoder)(10 * 1000));
|
|
525
498
|
restServer.post(this.path + "/createInvoice", (0, Utils_1.expressHandlerWrapper)(async (req, res) => {
|
|
@@ -600,21 +573,18 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
600
573
|
const gasToken = parsedBody.gasToken;
|
|
601
574
|
//Check request params
|
|
602
575
|
this.checkDescriptionHash(parsedBody.descriptionHash);
|
|
603
|
-
this.
|
|
576
|
+
this.checkTooManyInflightSwaps();
|
|
604
577
|
const fees = await this.AmountAssertions.preCheckFromBtcAmounts(this.type, request, requestedAmount, gasTokenAmount);
|
|
605
578
|
metadata.times.requestChecked = Date.now();
|
|
606
579
|
//Create abortController for parallel prefetches
|
|
607
580
|
const responseStream = res.responseStream;
|
|
608
581
|
const abortController = (0, Utils_1.getAbortController)(responseStream);
|
|
609
|
-
//Minimum reserve of native token to be kept in the wallet
|
|
610
|
-
const minNativeTokenReserve = this.config.minNativeBalances?.[chainIdentifier] ?? 0n;
|
|
611
582
|
//Pre-fetch data
|
|
612
583
|
const { pricePrefetchPromise, gasTokenPricePrefetchPromise } = this.getFromBtcPricePrefetches(chainIdentifier, useToken, gasToken, abortController);
|
|
613
584
|
const balancePrefetch = this.getBalancePrefetch(chainIdentifier, useToken, abortController);
|
|
614
585
|
const gasTokenBalancePrefetch = gasTokenAmount.amount === 0n || useToken === gasToken ?
|
|
615
586
|
null : this.getBalancePrefetch(chainIdentifier, gasToken, abortController);
|
|
616
|
-
const nativeTokenBalancePrefetch =
|
|
617
|
-
null : this.getBalancePrefetch(chainIdentifier, chainInterface.getNativeCurrencyAddress(), abortController, false);
|
|
587
|
+
const nativeTokenBalancePrefetch = this.prefetchNativeBalanceIfNeeded(chainIdentifier, abortController);
|
|
618
588
|
const channelsPrefetch = this.LightningAssertions.getChannelsPrefetch(abortController);
|
|
619
589
|
//Asynchronously send the node's public key to the client
|
|
620
590
|
this.sendPublicKeyAsync(responseStream);
|
|
@@ -623,7 +593,7 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
623
593
|
metadata.times.priceCalculated = Date.now();
|
|
624
594
|
const totalBtcInput = amountBD + amountBDgas;
|
|
625
595
|
//Check if we have at least the minimum needed native balance
|
|
626
|
-
await this.
|
|
596
|
+
await this.checkNativeBalance(chainIdentifier, nativeTokenBalancePrefetch, abortController.signal);
|
|
627
597
|
//Check if we have enough funds to honor the request
|
|
628
598
|
if (useToken === gasToken) {
|
|
629
599
|
await this.checkBalance(totalInToken + totalInGasToken, balancePrefetch, abortController.signal);
|
|
@@ -734,9 +704,5 @@ class FromBtcLnAuto extends FromBtcBaseSwapHandler_1.FromBtcBaseSwapHandler {
|
|
|
734
704
|
gasTokens: mappedDict
|
|
735
705
|
};
|
|
736
706
|
}
|
|
737
|
-
async removeSwapData(swap, ultimateState) {
|
|
738
|
-
this.swapsWithInflighHtlcs.delete(swap);
|
|
739
|
-
return super.removeSwapData(swap, ultimateState);
|
|
740
|
-
}
|
|
741
707
|
}
|
|
742
708
|
exports.FromBtcLnAuto = FromBtcLnAuto;
|
|
@@ -32,6 +32,7 @@ export type ToBtcRequestType = {
|
|
|
32
32
|
export declare class ToBtcAbs extends ToBtcBaseSwapHandler<ToBtcSwapAbs, ToBtcSwapState> {
|
|
33
33
|
readonly type = SwapHandlerType.TO_BTC;
|
|
34
34
|
readonly swapType = ChainSwapType.CHAIN_NONCED;
|
|
35
|
+
readonly inflightSwapStates: Set<ToBtcSwapState>;
|
|
35
36
|
activeSubscriptions: {
|
|
36
37
|
[txId: string]: ToBtcSwapAbs;
|
|
37
38
|
};
|
|
@@ -21,6 +21,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
21
21
|
super(storageDirectory, path, chainData, swapPricing, config);
|
|
22
22
|
this.type = SwapHandler_1.SwapHandlerType.TO_BTC;
|
|
23
23
|
this.swapType = base_1.ChainSwapType.CHAIN_NONCED;
|
|
24
|
+
this.inflightSwapStates = new Set([ToBtcSwapAbs_1.ToBtcSwapState.BTC_SENDING, ToBtcSwapAbs_1.ToBtcSwapState.BTC_SENT]);
|
|
24
25
|
this.activeSubscriptions = {};
|
|
25
26
|
this.bitcoinRpc = bitcoinRpc;
|
|
26
27
|
this.bitcoin = bitcoin;
|
|
@@ -277,6 +278,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
277
278
|
// e.g. that 2 payouts share the same input and would effectively double-spend each other
|
|
278
279
|
return this.bitcoin.execute(async () => {
|
|
279
280
|
//Run checks
|
|
281
|
+
this.checkTooManyInflightSwaps();
|
|
280
282
|
this.checkExpiresTooSoon(swap);
|
|
281
283
|
if (swap.metadata != null)
|
|
282
284
|
swap.metadata.times.payCLTVChecked = Date.now();
|
|
@@ -563,6 +565,7 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
563
565
|
};
|
|
564
566
|
const useToken = parsedBody.token;
|
|
565
567
|
const responseStream = res.responseStream;
|
|
568
|
+
this.checkTooManyInflightSwaps();
|
|
566
569
|
this.checkNonceValid(parsedBody.nonce);
|
|
567
570
|
this.checkConfirmationTarget(parsedBody.confirmationTarget);
|
|
568
571
|
this.checkRequiredConfirmations(parsedBody.confirmations);
|
|
@@ -573,6 +576,8 @@ class ToBtcAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
573
576
|
//Initialize abort controller for the parallel async operations
|
|
574
577
|
const abortController = (0, Utils_1.getAbortController)(responseStream);
|
|
575
578
|
const { pricePrefetchPromise, signDataPrefetchPromise } = this.getToBtcPrefetches(chainIdentifier, useToken, responseStream, abortController);
|
|
579
|
+
const nativeBalancePrefetch = this.prefetchNativeBalanceIfNeeded(chainIdentifier, abortController);
|
|
580
|
+
await this.checkNativeBalance(chainIdentifier, nativeBalancePrefetch, abortController.signal);
|
|
576
581
|
const { amountBD, networkFeeData, totalInToken, swapFee, swapFeeInToken, networkFeeInToken } = await this.AmountAssertions.checkToBtcAmount(this.type, request, { ...requestedAmount, pricePrefetch: pricePrefetchPromise }, fees, async (amount) => {
|
|
577
582
|
metadata.times.amountsChecked = Date.now();
|
|
578
583
|
const resp = await this.checkAndGetNetworkFee(parsedBody.address, amount);
|
|
@@ -55,9 +55,10 @@ export type ToBtcLnRequestType = {
|
|
|
55
55
|
* Swap handler handling to BTCLN swaps using submarine swaps
|
|
56
56
|
*/
|
|
57
57
|
export declare class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwapState> {
|
|
58
|
-
activeSubscriptions: Set<string>;
|
|
59
58
|
readonly type = SwapHandlerType.TO_BTCLN;
|
|
60
59
|
readonly swapType = ChainSwapType.HTLC;
|
|
60
|
+
readonly inflightSwapStates: Set<ToBtcLnSwapState>;
|
|
61
|
+
activeSubscriptions: Set<string>;
|
|
61
62
|
readonly config: ToBtcLnConfig & {
|
|
62
63
|
minTsSendCltv: bigint;
|
|
63
64
|
};
|
|
@@ -18,9 +18,10 @@ const LightningAssertions_1 = require("../../assertions/LightningAssertions");
|
|
|
18
18
|
class ToBtcLnAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
19
19
|
constructor(storageDirectory, path, chainData, lightning, swapPricing, config) {
|
|
20
20
|
super(storageDirectory, path, chainData, swapPricing, config);
|
|
21
|
-
this.activeSubscriptions = new Set();
|
|
22
21
|
this.type = SwapHandler_1.SwapHandlerType.TO_BTCLN;
|
|
23
22
|
this.swapType = base_1.ChainSwapType.HTLC;
|
|
23
|
+
this.inflightSwapStates = new Set([ToBtcLnSwapAbs_1.ToBtcLnSwapState.COMMITED, ToBtcLnSwapAbs_1.ToBtcLnSwapState.PAID]);
|
|
24
|
+
this.activeSubscriptions = new Set();
|
|
24
25
|
this.exactInAuths = {};
|
|
25
26
|
this.lightning = lightning;
|
|
26
27
|
this.LightningAssertions = new LightningAssertions_1.LightningAssertions(this.logger, lightning);
|
|
@@ -288,6 +289,21 @@ class ToBtcLnAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
288
289
|
}
|
|
289
290
|
}
|
|
290
291
|
if (swap.state === ToBtcLnSwapAbs_1.ToBtcLnSwapState.SAVED) {
|
|
292
|
+
try {
|
|
293
|
+
this.checkTooManyInflightSwaps();
|
|
294
|
+
}
|
|
295
|
+
catch (e) {
|
|
296
|
+
this.swapLogger.error(swap, "processInitialized(): checking too many inflight swaps error: ", e);
|
|
297
|
+
if ((0, Utils_1.isDefinedRuntimeError)(e)) {
|
|
298
|
+
if (swap.metadata != null)
|
|
299
|
+
swap.metadata.payError = e;
|
|
300
|
+
await swap.setState(ToBtcLnSwapAbs_1.ToBtcLnSwapState.NON_PAYABLE);
|
|
301
|
+
await this.saveSwapData(swap);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
else
|
|
305
|
+
throw e;
|
|
306
|
+
}
|
|
291
307
|
await swap.setState(ToBtcLnSwapAbs_1.ToBtcLnSwapState.COMMITED);
|
|
292
308
|
await this.saveSwapData(swap);
|
|
293
309
|
try {
|
|
@@ -553,10 +569,11 @@ class ToBtcLnAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
553
569
|
msg: "Invalid request body"
|
|
554
570
|
};
|
|
555
571
|
}
|
|
572
|
+
this.checkTooManyInflightSwaps();
|
|
573
|
+
const parsedAuth = this.checkExactInAuthorization(parsedBody.reqId);
|
|
556
574
|
const responseStream = res.responseStream;
|
|
557
575
|
const abortSignal = responseStream.getAbortSignal();
|
|
558
576
|
//Check request params
|
|
559
|
-
const parsedAuth = this.checkExactInAuthorization(parsedBody.reqId);
|
|
560
577
|
const { parsedPR, halfConfidence } = await this.checkPaymentRequest(parsedAuth.chainIdentifier, parsedBody.pr);
|
|
561
578
|
await this.checkPaymentRequestMatchesInitial(parsedBody.pr, parsedAuth);
|
|
562
579
|
const metadata = parsedAuth.metadata;
|
|
@@ -650,6 +667,7 @@ class ToBtcLnAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
650
667
|
const responseStream = res.responseStream;
|
|
651
668
|
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
652
669
|
//Check request params
|
|
670
|
+
this.checkTooManyInflightSwaps();
|
|
653
671
|
this.checkAmount(parsedBody.amount, parsedBody.exactIn);
|
|
654
672
|
this.checkMaxFee(parsedBody.maxFee);
|
|
655
673
|
this.checkExpiry(parsedBody.expiryTimestamp, currentTimestamp);
|
|
@@ -666,9 +684,12 @@ class ToBtcLnAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
|
|
|
666
684
|
const abortController = (0, Utils_1.getAbortController)(responseStream);
|
|
667
685
|
//Pre-fetch
|
|
668
686
|
const { pricePrefetchPromise, signDataPrefetchPromise } = this.getToBtcPrefetches(chainIdentifier, useToken, responseStream, abortController);
|
|
687
|
+
const nativeBalancePrefetch = this.prefetchNativeBalanceIfNeeded(chainIdentifier, abortController);
|
|
669
688
|
//Check if prior payment has been made
|
|
670
689
|
await this.LightningAssertions.checkPriorPayment(parsedPR.id, abortController.signal);
|
|
671
690
|
metadata.times.priorPaymentChecked = Date.now();
|
|
691
|
+
//Check if we still have enough native balance
|
|
692
|
+
await this.checkNativeBalance(chainIdentifier, nativeBalancePrefetch, abortController.signal);
|
|
672
693
|
//Check amounts
|
|
673
694
|
const { amountBD, networkFeeData, totalInToken, swapFee, swapFeeInToken, networkFeeInToken } = await this.AmountAssertions.checkToBtcAmount(this.type, request, { ...requestedAmount, pricePrefetch: pricePrefetchPromise }, fees, async (amountBD) => {
|
|
674
695
|
//Check if we have enough liquidity to process the swap
|
|
@@ -32,6 +32,7 @@ export type SpvVaultPostQuote = {
|
|
|
32
32
|
};
|
|
33
33
|
export declare class SpvVaultSwapHandler extends SwapHandler<SpvVaultSwap, SpvVaultSwapState> {
|
|
34
34
|
readonly type = SwapHandlerType.FROM_BTC_SPV;
|
|
35
|
+
readonly inflightSwapStates: Set<SpvVaultSwapState>;
|
|
35
36
|
readonly bitcoin: IBitcoinWallet;
|
|
36
37
|
readonly bitcoinRpc: BitcoinRpc<BtcBlock>;
|
|
37
38
|
readonly vaultSigner: ISpvVaultSigner;
|
|
@@ -19,6 +19,7 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
|
|
|
19
19
|
constructor(storageDirectory, vaultStorage, path, chainsData, swapPricing, bitcoin, bitcoinRpc, spvVaultSigner, config) {
|
|
20
20
|
super(storageDirectory, path, chainsData, swapPricing);
|
|
21
21
|
this.type = SwapHandler_1.SwapHandlerType.FROM_BTC_SPV;
|
|
22
|
+
this.inflightSwapStates = new Set([SpvVaultSwap_1.SpvVaultSwapState.SIGNED, SpvVaultSwap_1.SpvVaultSwapState.SENT, SpvVaultSwap_1.SpvVaultSwapState.BTC_CONFIRMED]);
|
|
22
23
|
this.btcTxIdIndex = new Map();
|
|
23
24
|
this.bitcoinRpc = bitcoinRpc;
|
|
24
25
|
this.bitcoin = bitcoin;
|
|
@@ -246,6 +247,7 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
|
|
|
246
247
|
};
|
|
247
248
|
const useToken = parsedBody.token;
|
|
248
249
|
const gasToken = parsedBody.gasToken;
|
|
250
|
+
this.checkTooManyInflightSwaps();
|
|
249
251
|
//Check request params
|
|
250
252
|
const fees = await this.AmountAssertions.preCheckFromBtcAmounts(this.type, request, requestedAmount, gasTokenAmount);
|
|
251
253
|
metadata.times.requestChecked = Date.now();
|
|
@@ -254,6 +256,8 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
|
|
|
254
256
|
const abortController = (0, Utils_1.getAbortController)(responseStream);
|
|
255
257
|
//Pre-fetch data
|
|
256
258
|
const { pricePrefetchPromise, gasTokenPricePrefetchPromise } = this.getPricePrefetches(chainIdentifier, useToken, gasToken, abortController);
|
|
259
|
+
const nativeBalancePrefetch = this.prefetchNativeBalanceIfNeeded(chainIdentifier, abortController);
|
|
260
|
+
await this.checkNativeBalance(chainIdentifier, nativeBalancePrefetch, abortController.signal);
|
|
257
261
|
//Check valid amount specified (min/max)
|
|
258
262
|
let { amountBD, swapFee, swapFeeInToken, totalInToken, amountBDgas, gasSwapFee, gasSwapFeeInToken, totalInGasToken } = await this.AmountAssertions.checkFromBtcAmount(this.type, request, { ...requestedAmount, pricePrefetch: pricePrefetchPromise }, fees, abortController.signal, { ...gasTokenAmount, pricePrefetch: gasTokenPricePrefetchPromise });
|
|
259
263
|
metadata.times.priceCalculated = Date.now();
|
|
@@ -339,6 +343,7 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
|
|
|
339
343
|
const metadata = swap.metadata;
|
|
340
344
|
metadata.times ?? (metadata.times = {});
|
|
341
345
|
metadata.times.requestReceived = requestReceived;
|
|
346
|
+
this.checkTooManyInflightSwaps();
|
|
342
347
|
const vault = await this.Vaults.getVault(swap.chainIdentifier, swap.vaultOwner, swap.vaultId);
|
|
343
348
|
if (vault == null || !vault.isReady()) {
|
|
344
349
|
throw {
|
|
@@ -452,6 +457,8 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
|
|
|
452
457
|
msg: "Invalid quote ID, not found or expired!"
|
|
453
458
|
};
|
|
454
459
|
}
|
|
460
|
+
//Double check in-flight swap count
|
|
461
|
+
this.checkTooManyInflightSwaps();
|
|
455
462
|
swap.btcTxId = signedTx.id;
|
|
456
463
|
swap.state = SpvVaultSwap_1.SpvVaultSwapState.SIGNED;
|
|
457
464
|
swap.sending = true;
|
|
@@ -480,6 +487,8 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
|
|
|
480
487
|
swap.sending = false;
|
|
481
488
|
vault.removeWithdrawal(data);
|
|
482
489
|
await this.Vaults.saveVault(vault);
|
|
490
|
+
if ((0, Utils_1.isDefinedRuntimeError)(e) && swap.metadata != null)
|
|
491
|
+
swap.metadata.postQuoteError = e;
|
|
483
492
|
await this.removeSwapData(swap, SpvVaultSwap_1.SpvVaultSwapState.FAILED);
|
|
484
493
|
throw e;
|
|
485
494
|
}
|
|
@@ -20,6 +20,7 @@ export type FromBtcTrustedRequestType = {
|
|
|
20
20
|
};
|
|
21
21
|
export declare class FromBtcTrusted extends SwapHandler<FromBtcTrustedSwap, FromBtcTrustedSwapState> {
|
|
22
22
|
readonly type = SwapHandlerType.FROM_BTC_TRUSTED;
|
|
23
|
+
readonly inflightSwapStates: Set<FromBtcTrustedSwapState>;
|
|
23
24
|
readonly config: FromBtcTrustedConfig;
|
|
24
25
|
readonly bitcoin: IBitcoinWallet;
|
|
25
26
|
readonly bitcoinRpc: BitcoinRpc<BtcBlock>;
|