@atomiqlabs/sdk 8.6.0 → 8.6.2
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/storage/UnifiedSwapStorage.js +13 -8
- package/dist/swapper/Swapper.d.ts +1 -12
- package/dist/swapper/Swapper.js +25 -26
- package/dist/swapper/SwapperFactory.d.ts +1 -0
- package/dist/swapper/SwapperFactory.js +9 -4
- package/dist/swaps/ISwap.d.ts +8 -0
- package/dist/swaps/ISwap.js +8 -0
- package/dist/swaps/ISwapWrapper.d.ts +23 -1
- package/dist/swaps/ISwapWrapper.js +88 -28
- package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +4 -1
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +2 -2
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +1 -1
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +2 -2
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +16 -6
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +8 -2
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +1 -1
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +14 -4
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +8 -6
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +2 -1
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +7 -5
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +8 -2
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +1 -1
- package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +0 -6
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +8 -3
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +8 -2
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +1 -0
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +3 -2
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +1 -3
- package/dist/swaps/trusted/ln/LnForGasWrapper.js +0 -1
- package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +0 -1
- package/package.json +1 -1
- package/src/storage/UnifiedSwapStorage.ts +13 -8
- package/src/swapper/Swapper.ts +27 -27
- package/src/swapper/SwapperFactory.ts +12 -6
- package/src/swaps/ISwap.ts +8 -0
- package/src/swaps/ISwapWrapper.ts +104 -28
- package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +5 -1
- package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +3 -3
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +17 -8
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +8 -3
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +13 -5
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +8 -7
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +9 -5
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +7 -2
- package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +1 -1
- package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +0 -3
- package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +7 -3
- package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +7 -2
- package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +5 -2
- package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +1 -3
- package/src/swaps/trusted/ln/LnForGasWrapper.ts +0 -1
- package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +0 -1
package/src/swapper/Swapper.ts
CHANGED
|
@@ -316,7 +316,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
316
316
|
bitcoinSynchronizer: (btcRelay: BtcRelay<any, any, any>) => RelaySynchronizer<any, any, any>,
|
|
317
317
|
chainsData: CtorMultiChainData<T>,
|
|
318
318
|
pricing: ISwapPrice<T>,
|
|
319
|
-
tokens:
|
|
319
|
+
tokens: SCToken[],
|
|
320
320
|
messenger: Messenger,
|
|
321
321
|
options?: SwapperOptions
|
|
322
322
|
) {
|
|
@@ -347,22 +347,10 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
347
347
|
this._tokens = {};
|
|
348
348
|
this._tokensByTicker = {};
|
|
349
349
|
for(let tokenData of tokens) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
this._tokens[chainId][chainData.address] = this._tokensByTicker[chainId][tokenData.ticker] = {
|
|
355
|
-
chain: "SC",
|
|
356
|
-
chainId,
|
|
357
|
-
ticker: tokenData.ticker,
|
|
358
|
-
name: tokenData.name,
|
|
359
|
-
decimals: chainData.decimals,
|
|
360
|
-
displayDecimals: chainData.displayDecimals,
|
|
361
|
-
address: chainData.address,
|
|
362
|
-
equals: (other: Token) => other.chainId===chainId && other.ticker===tokenData.ticker && other.address===chainData.address,
|
|
363
|
-
toString: () => `${chainId}-${tokenData.ticker}`
|
|
364
|
-
}
|
|
365
|
-
}
|
|
350
|
+
const chainId = tokenData.chainId;
|
|
351
|
+
this._tokens[chainId] ??= {};
|
|
352
|
+
this._tokensByTicker[chainId] ??= {};
|
|
353
|
+
this._tokens[chainId][tokenData.address] = this._tokensByTicker[chainId][tokenData.ticker] = tokenData;
|
|
366
354
|
}
|
|
367
355
|
|
|
368
356
|
this.swapStateListener = (swap: ISwap) => {
|
|
@@ -395,6 +383,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
395
383
|
{
|
|
396
384
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
397
385
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
386
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
398
387
|
}
|
|
399
388
|
);
|
|
400
389
|
wrappers[SwapType.TO_BTC] = new ToBTCWrapper<T[InputKey]>(
|
|
@@ -410,6 +399,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
410
399
|
{
|
|
411
400
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
412
401
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
402
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
413
403
|
bitcoinNetwork: this._btcNetwork
|
|
414
404
|
}
|
|
415
405
|
);
|
|
@@ -426,6 +416,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
426
416
|
{
|
|
427
417
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
428
418
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
419
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
429
420
|
unsafeSkipLnNodeCheck: this.bitcoinNetwork===BitcoinNetwork.TESTNET4 || this.bitcoinNetwork===BitcoinNetwork.REGTEST
|
|
430
421
|
}
|
|
431
422
|
);
|
|
@@ -444,6 +435,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
444
435
|
{
|
|
445
436
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
446
437
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
438
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
447
439
|
bitcoinNetwork: this._btcNetwork
|
|
448
440
|
}
|
|
449
441
|
);
|
|
@@ -456,7 +448,8 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
456
448
|
this._tokens[chainId],
|
|
457
449
|
{
|
|
458
450
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
459
|
-
postRequestTimeout: this.options.postRequestTimeout
|
|
451
|
+
postRequestTimeout: this.options.postRequestTimeout,
|
|
452
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
460
453
|
}
|
|
461
454
|
);
|
|
462
455
|
wrappers[SwapType.TRUSTED_FROM_BTC] = new OnchainForGasWrapper<T[InputKey]>(
|
|
@@ -470,6 +463,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
470
463
|
{
|
|
471
464
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
472
465
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
466
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
473
467
|
bitcoinNetwork: this._btcNetwork
|
|
474
468
|
}
|
|
475
469
|
);
|
|
@@ -490,6 +484,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
490
484
|
{
|
|
491
485
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
492
486
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
487
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
493
488
|
bitcoinNetwork: this._btcNetwork
|
|
494
489
|
}
|
|
495
490
|
);
|
|
@@ -510,6 +505,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
510
505
|
{
|
|
511
506
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
512
507
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
508
|
+
saveUninitializedSwaps: this.options.saveUninitializedSwaps,
|
|
513
509
|
unsafeSkipLnNodeCheck: this.bitcoinNetwork===BitcoinNetwork.TESTNET4 || this.bitcoinNetwork===BitcoinNetwork.REGTEST
|
|
514
510
|
}
|
|
515
511
|
);
|
|
@@ -659,7 +655,10 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
659
655
|
*/
|
|
660
656
|
async init(): Promise<void> {
|
|
661
657
|
if(this.initialized) return;
|
|
662
|
-
if(this.initPromise!=null)
|
|
658
|
+
if(this.initPromise!=null) {
|
|
659
|
+
await this.initPromise;
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
663
662
|
|
|
664
663
|
try {
|
|
665
664
|
const promise = this._init();
|
|
@@ -856,10 +855,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
856
855
|
if(swapLimitsChanged) this.emit("swapLimitsChanged");
|
|
857
856
|
|
|
858
857
|
const quote = quotes[0].quote;
|
|
859
|
-
|
|
860
|
-
quote._setInitiated();
|
|
861
|
-
await quote._save();
|
|
862
|
-
}
|
|
858
|
+
await quote._save();
|
|
863
859
|
return quote;
|
|
864
860
|
} catch (e) {
|
|
865
861
|
if(swapLimitsChanged) this.emit("swapLimitsChanged");
|
|
@@ -1334,13 +1330,15 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1334
1330
|
* @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
|
|
1335
1331
|
* @throws {Error} If no trusted intermediary specified
|
|
1336
1332
|
*/
|
|
1337
|
-
createTrustedLNForGasSwap<C extends ChainIds<T>>(chainIdentifier: C, recipient: string, amount: bigint, trustedIntermediaryOrUrl?: Intermediary | string): Promise<LnForGasSwap<T[C]>> {
|
|
1333
|
+
async createTrustedLNForGasSwap<C extends ChainIds<T>>(chainIdentifier: C, recipient: string, amount: bigint, trustedIntermediaryOrUrl?: Intermediary | string): Promise<LnForGasSwap<T[C]>> {
|
|
1338
1334
|
if(this._chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
|
|
1339
1335
|
if(!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true)) throw new Error("Invalid "+chainIdentifier+" address");
|
|
1340
1336
|
recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
|
|
1341
1337
|
const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
|
|
1342
1338
|
if(useUrl==null) throw new Error("No trusted intermediary specified!");
|
|
1343
|
-
|
|
1339
|
+
const swap = await this._chains[chainIdentifier as C].wrappers[SwapType.TRUSTED_FROM_BTCLN].create(recipient, amount, useUrl);
|
|
1340
|
+
await swap._save();
|
|
1341
|
+
return swap;
|
|
1344
1342
|
}
|
|
1345
1343
|
|
|
1346
1344
|
/**
|
|
@@ -1353,7 +1351,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1353
1351
|
* @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
|
|
1354
1352
|
* @throws {Error} If no trusted intermediary specified
|
|
1355
1353
|
*/
|
|
1356
|
-
createTrustedOnchainForGasSwap<C extends ChainIds<T>>(
|
|
1354
|
+
async createTrustedOnchainForGasSwap<C extends ChainIds<T>>(
|
|
1357
1355
|
chainIdentifier: C, recipient: string,
|
|
1358
1356
|
amount: bigint, refundAddress?: string,
|
|
1359
1357
|
trustedIntermediaryOrUrl?: Intermediary | string
|
|
@@ -1363,7 +1361,9 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1363
1361
|
recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
|
|
1364
1362
|
const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
|
|
1365
1363
|
if(useUrl==null) throw new Error("No trusted intermediary specified!");
|
|
1366
|
-
|
|
1364
|
+
const swap = await this._chains[chainIdentifier as C].wrappers[SwapType.TRUSTED_FROM_BTC].create(recipient, amount, useUrl, refundAddress);
|
|
1365
|
+
await swap._save();
|
|
1366
|
+
return swap;
|
|
1367
1367
|
}
|
|
1368
1368
|
|
|
1369
1369
|
/**
|
|
@@ -9,7 +9,7 @@ import {SmartChainAssets, SmartChainAssetTickers} from "../SmartChainAssets";
|
|
|
9
9
|
import {NostrMessenger} from "@atomiqlabs/messenger-nostr";
|
|
10
10
|
import {Swapper, SwapperOptions} from "./Swapper";
|
|
11
11
|
import {CustomPriceProvider} from "../prices/providers/CustomPriceProvider";
|
|
12
|
-
import {BitcoinTokens, BtcToken, SCToken} from "../types/Token";
|
|
12
|
+
import {BitcoinTokens, BtcToken, SCToken, Token} from "../types/Token";
|
|
13
13
|
import {SwapType} from "../enums/SwapType";
|
|
14
14
|
import {SwapTypeMapping} from "../utils/SwapUtils";
|
|
15
15
|
import {RedundantSwapPrice, RedundantSwapPriceAssets} from "../prices/RedundantSwapPrice";
|
|
@@ -191,6 +191,8 @@ export class SwapperFactory<T extends readonly ChainInitializer<any, ChainType,
|
|
|
191
191
|
*/
|
|
192
192
|
TokenResolver: TypedTokenResolvers<T> = {} as any;
|
|
193
193
|
|
|
194
|
+
private smartChainTokens: SCToken[] = [];
|
|
195
|
+
|
|
194
196
|
constructor(readonly initializers: T) {
|
|
195
197
|
this.initializers = initializers;
|
|
196
198
|
initializers.forEach(initializer => {
|
|
@@ -200,15 +202,19 @@ export class SwapperFactory<T extends readonly ChainInitializer<any, ChainType,
|
|
|
200
202
|
|
|
201
203
|
for(let ticker in initializer.tokens) {
|
|
202
204
|
const assetData = initializer.tokens[ticker] as any;
|
|
203
|
-
|
|
205
|
+
const token: SCToken = {
|
|
204
206
|
chain: "SC",
|
|
205
207
|
chainId: initializer.chainId,
|
|
206
|
-
|
|
208
|
+
ticker,
|
|
207
209
|
name: SmartChainAssets[ticker as SmartChainAssetTickers]?.name ?? ticker,
|
|
208
210
|
decimals: assetData.decimals,
|
|
209
211
|
displayDecimals: assetData.displayDecimals,
|
|
210
|
-
|
|
211
|
-
|
|
212
|
+
address: assetData.address,
|
|
213
|
+
equals: (other: Token) => other.chainId===initializer.chainId && other.ticker===ticker && other.address===assetData.address,
|
|
214
|
+
toString: () => `${initializer.chainId}-${ticker}`
|
|
215
|
+
};
|
|
216
|
+
this.smartChainTokens.push(token);
|
|
217
|
+
tokens[ticker] = addressMap[assetData.address] = token;
|
|
212
218
|
}
|
|
213
219
|
|
|
214
220
|
this.TokenResolver[initializer.chainId as keyof TypedTokenResolvers<T>] = {
|
|
@@ -280,7 +286,7 @@ export class SwapperFactory<T extends readonly ChainInitializer<any, ChainType,
|
|
|
280
286
|
(btcRelay: BtcRelay<any, any, any>) => new MempoolBtcRelaySynchronizer(btcRelay, bitcoinRpc),
|
|
281
287
|
chains as any,
|
|
282
288
|
swapPricing,
|
|
283
|
-
|
|
289
|
+
this.smartChainTokens,
|
|
284
290
|
options.messenger,
|
|
285
291
|
options
|
|
286
292
|
);
|
package/src/swaps/ISwap.ts
CHANGED
|
@@ -132,6 +132,14 @@ export abstract class ISwap<
|
|
|
132
132
|
* @internal
|
|
133
133
|
*/
|
|
134
134
|
_randomNonce: string;
|
|
135
|
+
/**
|
|
136
|
+
* Whether the swap is saved in the persistent storage or not.
|
|
137
|
+
*
|
|
138
|
+
* @remarks This field itself is not persisted but is instead derived during runtime
|
|
139
|
+
*
|
|
140
|
+
* @internal
|
|
141
|
+
*/
|
|
142
|
+
_persisted: boolean = false;
|
|
135
143
|
|
|
136
144
|
|
|
137
145
|
/**
|
|
@@ -13,6 +13,9 @@ import {PriceInfoType} from "../types/PriceInfoType";
|
|
|
13
13
|
import {fromHumanReadableString} from "../utils/TokenUtils";
|
|
14
14
|
import {UserError} from "../errors/UserError";
|
|
15
15
|
|
|
16
|
+
export const DEFAULT_MAX_PARALLEL_SWAP_TICKS = 50;
|
|
17
|
+
export const DEFAULT_MAX_PARALLEL_SWAP_SYNCS = 50;
|
|
18
|
+
|
|
16
19
|
/**
|
|
17
20
|
* Options for swap wrapper configuration
|
|
18
21
|
*
|
|
@@ -20,7 +23,19 @@ import {UserError} from "../errors/UserError";
|
|
|
20
23
|
*/
|
|
21
24
|
export type ISwapWrapperOptions = {
|
|
22
25
|
getRequestTimeout?: number,
|
|
23
|
-
postRequestTimeout?: number
|
|
26
|
+
postRequestTimeout?: number,
|
|
27
|
+
/**
|
|
28
|
+
* How many swaps to call `_tick()` for in parallel
|
|
29
|
+
*/
|
|
30
|
+
maxParallelSwapTicks?: number,
|
|
31
|
+
/**
|
|
32
|
+
* How many swaps to call `_sync()` for in parallel
|
|
33
|
+
*/
|
|
34
|
+
maxParallelSwapSyncs?: number,
|
|
35
|
+
/**
|
|
36
|
+
* Whether to save swaps that are not initialized into the persistent storage
|
|
37
|
+
*/
|
|
38
|
+
saveUninitializedSwaps?: boolean
|
|
24
39
|
};
|
|
25
40
|
|
|
26
41
|
/**
|
|
@@ -101,6 +116,11 @@ export abstract class ISwapWrapper<
|
|
|
101
116
|
* @internal
|
|
102
117
|
*/
|
|
103
118
|
protected tickInterval?: NodeJS.Timeout;
|
|
119
|
+
/**
|
|
120
|
+
* An internal abort controller for the running tick handler
|
|
121
|
+
* @internal
|
|
122
|
+
*/
|
|
123
|
+
protected tickAbortController?: AbortController;
|
|
104
124
|
|
|
105
125
|
|
|
106
126
|
/**
|
|
@@ -152,6 +172,11 @@ export abstract class ISwapWrapper<
|
|
|
152
172
|
options: O,
|
|
153
173
|
events?: EventEmitter<{swapState: [ISwap]}>
|
|
154
174
|
) {
|
|
175
|
+
if(options?.maxParallelSwapTicks!=null && options.maxParallelSwapTicks < 1)
|
|
176
|
+
throw new Error("maxParallelSwapTicks must be at least 1!");
|
|
177
|
+
if(options?.maxParallelSwapSyncs!=null && options.maxParallelSwapSyncs < 1)
|
|
178
|
+
throw new Error("maxParallelSwapSyncs must be at least 1!");
|
|
179
|
+
|
|
155
180
|
this.unifiedStorage = unifiedStorage;
|
|
156
181
|
this.unifiedChainEvents = unifiedChainEvents;
|
|
157
182
|
|
|
@@ -274,9 +299,20 @@ export abstract class ISwapWrapper<
|
|
|
274
299
|
*/
|
|
275
300
|
protected startTickInterval(): void {
|
|
276
301
|
if(this.tickSwapState==null || this.tickSwapState.length===0) return;
|
|
277
|
-
this.
|
|
278
|
-
|
|
279
|
-
|
|
302
|
+
if(this.tickAbortController!=null) this.tickAbortController.abort("New tick interval has been started!");
|
|
303
|
+
const abortController = this.tickAbortController = new AbortController();
|
|
304
|
+
let run: () => Promise<void>;
|
|
305
|
+
run = async () => {
|
|
306
|
+
if(!this.isInitialized) return;
|
|
307
|
+
await this.tick(undefined, abortController.signal).catch(e => {
|
|
308
|
+
if(abortController.signal.aborted) return;
|
|
309
|
+
this.logger.warn("startTickInterval(): Tick on swaps failed, error: ", e);
|
|
310
|
+
});
|
|
311
|
+
if(abortController.signal.aborted) return;
|
|
312
|
+
if(!this.isInitialized) return;
|
|
313
|
+
this.tickInterval = setTimeout(run, 1000);
|
|
314
|
+
}
|
|
315
|
+
run();
|
|
280
316
|
}
|
|
281
317
|
|
|
282
318
|
/**
|
|
@@ -343,11 +379,11 @@ export abstract class ISwapWrapper<
|
|
|
343
379
|
|
|
344
380
|
if(this.processEvent!=null) this.unifiedChainEvents.registerListener(this.TYPE, this.processEvent.bind(this), this._swapDeserializer.bind(null, this));
|
|
345
381
|
|
|
382
|
+
this.isInitialized = true;
|
|
383
|
+
|
|
346
384
|
if(!noTimers) this.startTickInterval();
|
|
347
385
|
|
|
348
386
|
// this.logger.info("init(): Swap wrapper initialized");
|
|
349
|
-
|
|
350
|
-
this.isInitialized = true;
|
|
351
387
|
}
|
|
352
388
|
|
|
353
389
|
/**
|
|
@@ -357,12 +393,21 @@ export abstract class ISwapWrapper<
|
|
|
357
393
|
this.isInitialized = false;
|
|
358
394
|
this.unifiedChainEvents.unregisterListener(this.TYPE);
|
|
359
395
|
this.logger.info("stop(): Swap wrapper stopped");
|
|
360
|
-
if(this.tickInterval!=null)
|
|
396
|
+
if(this.tickInterval!=null) {
|
|
397
|
+
clearTimeout(this.tickInterval);
|
|
398
|
+
delete this.tickInterval;
|
|
399
|
+
}
|
|
400
|
+
if(this.tickAbortController!=null) {
|
|
401
|
+
this.tickAbortController.abort("Wrapper instance stopped!");
|
|
402
|
+
delete this.tickAbortController;
|
|
403
|
+
}
|
|
361
404
|
}
|
|
362
405
|
|
|
363
406
|
/**
|
|
364
407
|
* Runs checks on all the known pending swaps, syncing their state from on-chain data
|
|
365
408
|
*
|
|
409
|
+
* @remarks Doesn't work properly if you pass non-persisted swaps
|
|
410
|
+
*
|
|
366
411
|
* @param pastSwaps Optional array of past swaps to check, otherwise all relevant swaps will be fetched
|
|
367
412
|
* from the persistent storage
|
|
368
413
|
* @param noSave Whether to skip saving the swap changes in the persistent storage
|
|
@@ -373,18 +418,25 @@ export abstract class ISwapWrapper<
|
|
|
373
418
|
(val: any) => new this._swapDeserializer(this, val)
|
|
374
419
|
);
|
|
375
420
|
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
changedSwaps
|
|
382
|
-
|
|
421
|
+
const maxParallelSyncs = this._options.maxParallelSwapSyncs ?? DEFAULT_MAX_PARALLEL_SWAP_SYNCS;
|
|
422
|
+
|
|
423
|
+
const totalRemoveSwaps: D["Swap"][] = [];
|
|
424
|
+
const totalChangedSwaps: D["Swap"][] = [];
|
|
425
|
+
for(let i=0; i<pastSwaps.length; i+=maxParallelSyncs) {
|
|
426
|
+
const {removeSwaps, changedSwaps} = await this._checkPastSwaps(pastSwaps.slice(i, i+maxParallelSyncs));
|
|
427
|
+
if (!noSave) {
|
|
428
|
+
await this.unifiedStorage.removeAll(removeSwaps);
|
|
429
|
+
await this.unifiedStorage.saveAll(changedSwaps);
|
|
430
|
+
changedSwaps.forEach(swap => swap._emitEvent());
|
|
431
|
+
removeSwaps.forEach(swap => swap._emitEvent());
|
|
432
|
+
}
|
|
433
|
+
totalRemoveSwaps.push(...removeSwaps);
|
|
434
|
+
totalChangedSwaps.push(...changedSwaps);
|
|
383
435
|
}
|
|
384
436
|
|
|
385
437
|
return {
|
|
386
|
-
removeSwaps,
|
|
387
|
-
changedSwaps
|
|
438
|
+
removeSwaps: totalRemoveSwaps,
|
|
439
|
+
changedSwaps: totalChangedSwaps
|
|
388
440
|
}
|
|
389
441
|
}
|
|
390
442
|
|
|
@@ -393,21 +445,43 @@ export abstract class ISwapWrapper<
|
|
|
393
445
|
*
|
|
394
446
|
* @param swaps Optional array of swaps to invoke `_tick()` on, otherwise all relevant swaps will be fetched
|
|
395
447
|
* from the persistent storage
|
|
448
|
+
* @param abortSignal Abort signal
|
|
396
449
|
*/
|
|
397
|
-
public async tick(swaps?: D["Swap"][]): Promise<void> {
|
|
450
|
+
public async tick(swaps?: D["Swap"][], abortSignal?: AbortSignal): Promise<void> {
|
|
398
451
|
if(swaps==null) swaps = await this.unifiedStorage.query<D["Swap"]>(
|
|
399
452
|
[[{key: "type", value: this.TYPE}, {key: "state", value: this.tickSwapState}]],
|
|
400
453
|
(val: any) => new this._swapDeserializer(this, val)
|
|
401
454
|
);
|
|
455
|
+
abortSignal?.throwIfAborted();
|
|
402
456
|
|
|
457
|
+
const parallelTicks = this._options.maxParallelSwapTicks ?? DEFAULT_MAX_PARALLEL_SWAP_TICKS;
|
|
458
|
+
|
|
459
|
+
let promises: Promise<any>[] = [];
|
|
403
460
|
for(let pendingSwap of this.pendingSwaps.values()) {
|
|
404
461
|
const value = pendingSwap.deref();
|
|
405
|
-
if(value != null) value._tick(true)
|
|
462
|
+
if(value != null) promises.push(value._tick(true).catch(e => {
|
|
463
|
+
this.logger.warn(`tick(): Error ticking swap ${value.getId()}: `, e);
|
|
464
|
+
}));
|
|
465
|
+
if(promises.length >= parallelTicks) {
|
|
466
|
+
await Promise.all(promises);
|
|
467
|
+
abortSignal?.throwIfAborted();
|
|
468
|
+
promises = [];
|
|
469
|
+
}
|
|
406
470
|
}
|
|
407
471
|
|
|
408
|
-
|
|
409
|
-
value._tick(true)
|
|
410
|
-
|
|
472
|
+
for(let value of swaps) {
|
|
473
|
+
promises.push(value._tick(true).catch(e => {
|
|
474
|
+
this.logger.warn(`tick(): Error ticking swap ${value.getId()}: `, e);
|
|
475
|
+
}));
|
|
476
|
+
if(promises.length >= parallelTicks) {
|
|
477
|
+
await Promise.all(promises);
|
|
478
|
+
abortSignal?.throwIfAborted();
|
|
479
|
+
promises = [];
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if(promises.length>0) await Promise.all(promises);
|
|
484
|
+
abortSignal?.throwIfAborted();
|
|
411
485
|
}
|
|
412
486
|
|
|
413
487
|
/**
|
|
@@ -426,12 +500,14 @@ export abstract class ISwapWrapper<
|
|
|
426
500
|
* @internal
|
|
427
501
|
*/
|
|
428
502
|
_saveSwapData(swap: D["Swap"]): Promise<void> {
|
|
429
|
-
if(!
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
503
|
+
if(!this._options.saveUninitializedSwaps) {
|
|
504
|
+
if(!swap.isInitiated()) {
|
|
505
|
+
this.logger.debug("saveSwapData(): Swap "+swap.getId()+" not initiated, saving to pending swaps");
|
|
506
|
+
this.pendingSwaps.set(swap.getId(), new WeakRef<D["Swap"]>(swap));
|
|
507
|
+
return Promise.resolve();
|
|
508
|
+
} else {
|
|
509
|
+
this.pendingSwaps.delete(swap.getId());
|
|
510
|
+
}
|
|
435
511
|
}
|
|
436
512
|
return this.unifiedStorage.save(swap);
|
|
437
513
|
}
|
|
@@ -445,7 +521,7 @@ export abstract class ISwapWrapper<
|
|
|
445
521
|
*/
|
|
446
522
|
_removeSwapData(swap: D["Swap"]): Promise<void> {
|
|
447
523
|
this.pendingSwaps.delete(swap.getId());
|
|
448
|
-
if(!swap.
|
|
524
|
+
if(!swap._persisted) return Promise.resolve();
|
|
449
525
|
return this.unifiedStorage.remove(swap);
|
|
450
526
|
}
|
|
451
527
|
|
|
@@ -66,7 +66,11 @@ export abstract class IEscrowSwapWrapper<
|
|
|
66
66
|
* @internal
|
|
67
67
|
*/
|
|
68
68
|
protected preFetchSignData(signDataPrefetch: Promise<any | null>): Promise<T["PreFetchVerification"] | undefined> {
|
|
69
|
-
if(this._contract.preFetchForInitSignatureVerification==null)
|
|
69
|
+
if(this._contract.preFetchForInitSignatureVerification==null) {
|
|
70
|
+
// Catch promise rejections, should they happen
|
|
71
|
+
signDataPrefetch.catch(() => {});
|
|
72
|
+
return Promise.resolve(undefined);
|
|
73
|
+
}
|
|
70
74
|
return signDataPrefetch.then(obj => {
|
|
71
75
|
if(obj==null) return undefined;
|
|
72
76
|
return this._contract.preFetchForInitSignatureVerification!(obj);
|
|
@@ -71,7 +71,7 @@ export abstract class IFromBTCSelfInitSwap<
|
|
|
71
71
|
* Returns if the swap can be committed
|
|
72
72
|
* @internal
|
|
73
73
|
*/
|
|
74
|
-
protected abstract canCommit(): boolean;
|
|
74
|
+
protected abstract canCommit(skipQuoteExpiryChecks?: boolean): boolean;
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
77
|
* @inheritDoc
|
|
@@ -239,7 +239,7 @@ export abstract class IFromBTCSelfInitSwap<
|
|
|
239
239
|
* @throws {Error} When in invalid state to commit the swap
|
|
240
240
|
*/
|
|
241
241
|
async txsCommit(skipChecks?: boolean): Promise<T["TX"][]> {
|
|
242
|
-
if(!this.canCommit()) throw new Error("Must be in CREATED state!");
|
|
242
|
+
if(!this.canCommit(skipChecks)) throw new Error("Must be in CREATED state!");
|
|
243
243
|
if(this._data==null || this.signatureData==null) throw new Error("data or signature data is null, invalid state?");
|
|
244
244
|
|
|
245
245
|
if(!this.initiated) {
|
|
@@ -285,7 +285,7 @@ export abstract class IFromBTCSelfInitSwap<
|
|
|
285
285
|
/**
|
|
286
286
|
* @inheritDoc
|
|
287
287
|
*/
|
|
288
|
-
abstract txsClaim(signer?: T["Signer"]): Promise<T["TX"][]>;
|
|
288
|
+
abstract txsClaim(signer?: string | T["Signer"] | T["NativeSigner"]): Promise<T["TX"][]>;
|
|
289
289
|
|
|
290
290
|
/**
|
|
291
291
|
* @inheritDoc
|
|
@@ -282,8 +282,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
|
|
|
282
282
|
* @inheritDoc
|
|
283
283
|
* @internal
|
|
284
284
|
*/
|
|
285
|
-
protected canCommit(): boolean {
|
|
286
|
-
return this._state===FromBTCLNSwapState.PR_PAID;
|
|
285
|
+
protected canCommit(skipQuoteExpiryChecks?: boolean): boolean {
|
|
286
|
+
return this._state===FromBTCLNSwapState.PR_PAID || (!!skipQuoteExpiryChecks && this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED);
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/**
|
|
@@ -899,7 +899,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
|
|
|
899
899
|
);
|
|
900
900
|
|
|
901
901
|
this._commitTxId = result[result.length-1];
|
|
902
|
-
if(this._state===FromBTCLNSwapState.PR_PAID || this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) {
|
|
902
|
+
if(this._state===FromBTCLNSwapState.PR_PAID || this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED || this._state===FromBTCLNSwapState.QUOTE_EXPIRED) {
|
|
903
903
|
await this._saveAndEmit(FromBTCLNSwapState.CLAIM_COMMITED);
|
|
904
904
|
}
|
|
905
905
|
return this._commitTxId;
|
|
@@ -953,7 +953,18 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
|
|
|
953
953
|
*
|
|
954
954
|
* @internal
|
|
955
955
|
*/
|
|
956
|
-
private async _txsClaim(_signer?: T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
|
|
956
|
+
private async _txsClaim(_signer?: string | T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
|
|
957
|
+
let address: string | undefined = undefined;
|
|
958
|
+
if(_signer!=null) {
|
|
959
|
+
if (typeof (_signer) === "string") {
|
|
960
|
+
address = _signer;
|
|
961
|
+
} else if (isAbstractSigner(_signer)) {
|
|
962
|
+
address = _signer.getAddress();
|
|
963
|
+
} else {
|
|
964
|
+
address = (await this.wrapper._chain.wrapSigner(_signer)).getAddress();
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
957
968
|
if(this._data==null) throw new Error("Unknown data, wrong state?");
|
|
958
969
|
const useSecret = secret ?? this.secret;
|
|
959
970
|
if(useSecret==null)
|
|
@@ -962,9 +973,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
|
|
|
962
973
|
throw new Error("Invalid swap secret pre-image provided!");
|
|
963
974
|
|
|
964
975
|
return this.wrapper._contract.txsClaimWithSecret(
|
|
965
|
-
|
|
966
|
-
this._getInitiator() :
|
|
967
|
-
(isAbstractSigner(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer)),
|
|
976
|
+
address ?? this._getInitiator(),
|
|
968
977
|
this._data, useSecret, true, true
|
|
969
978
|
);
|
|
970
979
|
}
|
|
@@ -978,7 +987,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
|
|
|
978
987
|
*
|
|
979
988
|
* @throws {Error} If in invalid state (must be {@link FromBTCLNSwapState.CLAIM_COMMITED})
|
|
980
989
|
*/
|
|
981
|
-
async txsClaim(_signer?: T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
|
|
990
|
+
async txsClaim(_signer?: string | T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
|
|
982
991
|
if(this._state!==FromBTCLNSwapState.CLAIM_COMMITED) throw new Error("Must be in CLAIM_COMMITED state!");
|
|
983
992
|
return this._txsClaim(_signer, secret);
|
|
984
993
|
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
ChainSwapType,
|
|
5
5
|
ChainType,
|
|
6
6
|
ClaimEvent,
|
|
7
|
-
InitializeEvent, LightningNetworkApi,
|
|
7
|
+
InitializeEvent, LightningNetworkApi, LNNodeLiquidity,
|
|
8
8
|
RefundEvent, SwapCommitState, SwapCommitStateType
|
|
9
9
|
} from "@atomiqlabs/base";
|
|
10
10
|
import {Intermediary} from "../../../../intermediaries/Intermediary";
|
|
@@ -137,6 +137,7 @@ export class FromBTCLNWrapper<
|
|
|
137
137
|
super(
|
|
138
138
|
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, swapDataDeserializer, lnApi,
|
|
139
139
|
{
|
|
140
|
+
...options,
|
|
140
141
|
safetyFactor: options?.safetyFactor ?? 2,
|
|
141
142
|
bitcoinBlocktime: options?.bitcoinBlocktime ?? 10*60,
|
|
142
143
|
unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? false
|
|
@@ -317,8 +318,13 @@ export class FromBTCLNWrapper<
|
|
|
317
318
|
this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined
|
|
318
319
|
);
|
|
319
320
|
|
|
321
|
+
let lnCapacityPromise: Promise<LNNodeLiquidity | null> | undefined;
|
|
322
|
+
if(!_options.unsafeSkipLnNodeCheck) {
|
|
323
|
+
lnCapacityPromise = this.preFetchLnCapacity(lnPublicKey);
|
|
324
|
+
} else lnPublicKey.catch(() => {});
|
|
325
|
+
|
|
320
326
|
return {
|
|
321
|
-
lnCapacityPromise
|
|
327
|
+
lnCapacityPromise,
|
|
322
328
|
resp: await response
|
|
323
329
|
};
|
|
324
330
|
}, undefined, RequestError, abortController.signal);
|
|
@@ -356,7 +362,6 @@ export class FromBTCLNWrapper<
|
|
|
356
362
|
secret: secret?.toString("hex"),
|
|
357
363
|
exactIn: amountData.exactIn ?? true
|
|
358
364
|
} as FromBTCLNSwapInit<T["Data"]>);
|
|
359
|
-
await quote._save();
|
|
360
365
|
return quote;
|
|
361
366
|
} catch (e) {
|
|
362
367
|
abortController.abort(e);
|
|
@@ -566,7 +566,7 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
566
566
|
* @internal
|
|
567
567
|
*/
|
|
568
568
|
protected getInputAmountWithoutFee(): bigint | null {
|
|
569
|
-
if(this.btcAmountGas==null || this.btcAmountSwap) return null;
|
|
569
|
+
if(this.btcAmountGas==null || this.btcAmountSwap==null) return null;
|
|
570
570
|
return this.getInputSwapAmountWithoutFee()! + this.getInputGasAmountWithoutFee()! - this.getWatchtowerFeeAmountBtc()!;
|
|
571
571
|
}
|
|
572
572
|
|
|
@@ -1144,7 +1144,17 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
1144
1144
|
*
|
|
1145
1145
|
* @throws {Error} If in invalid state (must be {@link FromBTCLNAutoSwapState.CLAIM_COMMITED})
|
|
1146
1146
|
*/
|
|
1147
|
-
async txsClaim(_signer?: T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
|
|
1147
|
+
async txsClaim(_signer?: string | T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
|
|
1148
|
+
let address: string | undefined = undefined;
|
|
1149
|
+
if(_signer!=null) {
|
|
1150
|
+
if (typeof (_signer) === "string") {
|
|
1151
|
+
address = _signer;
|
|
1152
|
+
} else if (isAbstractSigner(_signer)) {
|
|
1153
|
+
address = _signer.getAddress();
|
|
1154
|
+
} else {
|
|
1155
|
+
address = (await this.wrapper._chain.wrapSigner(_signer)).getAddress();
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1148
1158
|
if(this._state!==FromBTCLNAutoSwapState.CLAIM_COMMITED) throw new Error("Must be in CLAIM_COMMITED state!");
|
|
1149
1159
|
if(this._data==null) throw new Error("Unknown data, wrong state?");
|
|
1150
1160
|
|
|
@@ -1155,9 +1165,7 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
1155
1165
|
throw new Error("Invalid swap secret pre-image provided!");
|
|
1156
1166
|
|
|
1157
1167
|
return await this.wrapper._contract.txsClaimWithSecret(
|
|
1158
|
-
|
|
1159
|
-
this._getInitiator() :
|
|
1160
|
-
(isAbstractSigner(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer)),
|
|
1168
|
+
address ?? this._getInitiator(),
|
|
1161
1169
|
this._data, useSecret, true, true
|
|
1162
1170
|
);
|
|
1163
1171
|
}
|