@atomiqlabs/sdk 8.6.0 → 8.6.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/http/paramcoders/ParamDecoder.js +9 -4
- package/dist/http/paramcoders/ParamEncoder.js +6 -1
- package/dist/intermediaries/IntermediaryDiscovery.js +4 -3
- package/dist/storage/UnifiedSwapStorage.js +13 -8
- package/dist/swapper/Swapper.d.ts +1 -12
- package/dist/swapper/Swapper.js +31 -28
- 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/dist/utils/RetryUtils.d.ts +2 -1
- package/dist/utils/RetryUtils.js +3 -2
- package/package.json +1 -1
- package/src/http/paramcoders/ParamDecoder.ts +8 -4
- package/src/http/paramcoders/ParamEncoder.ts +5 -1
- package/src/intermediaries/IntermediaryDiscovery.ts +6 -4
- package/src/storage/UnifiedSwapStorage.ts +13 -8
- package/src/swapper/Swapper.ts +35 -28
- 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/utils/RetryUtils.ts +11 -4
|
@@ -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
|
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
ChainSwapType,
|
|
4
4
|
ChainType,
|
|
5
5
|
ClaimEvent,
|
|
6
|
-
InitializeEvent, LightningNetworkApi, Messenger,
|
|
6
|
+
InitializeEvent, LightningNetworkApi, LNNodeLiquidity, Messenger,
|
|
7
7
|
RefundEvent, SwapCommitState, SwapCommitStateType
|
|
8
8
|
} from "@atomiqlabs/base";
|
|
9
9
|
import {Intermediary} from "../../../../intermediaries/Intermediary";
|
|
@@ -174,6 +174,7 @@ export class FromBTCLNAutoWrapper<
|
|
|
174
174
|
super(
|
|
175
175
|
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, swapDataDeserializer, lnApi,
|
|
176
176
|
{
|
|
177
|
+
...options,
|
|
177
178
|
safetyFactor: options?.safetyFactor ?? 2,
|
|
178
179
|
bitcoinBlocktime: options?.bitcoinBlocktime ?? 10*60,
|
|
179
180
|
unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? false
|
|
@@ -210,7 +211,6 @@ export class FromBTCLNAutoWrapper<
|
|
|
210
211
|
return false;
|
|
211
212
|
}
|
|
212
213
|
|
|
213
|
-
swap._commitTxId = event.meta?.txId;
|
|
214
214
|
swap._commitedAt ??= Date.now();
|
|
215
215
|
swap._state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
|
|
216
216
|
if(swap.hasSecretPreimage()) swap._broadcastSecret().catch(e => {
|
|
@@ -227,7 +227,6 @@ export class FromBTCLNAutoWrapper<
|
|
|
227
227
|
*/
|
|
228
228
|
protected processEventClaim(swap: FromBTCLNAutoSwap<T>, event: ClaimEvent<T["Data"]>): Promise<boolean> {
|
|
229
229
|
if(swap._state!==FromBTCLNAutoSwapState.FAILED && swap._state!==FromBTCLNAutoSwapState.CLAIM_CLAIMED) {
|
|
230
|
-
swap._claimTxId = event.meta?.txId;
|
|
231
230
|
swap._state = FromBTCLNAutoSwapState.CLAIM_CLAIMED;
|
|
232
231
|
swap._setSwapSecret(event.result);
|
|
233
232
|
return Promise.resolve(true);
|
|
@@ -241,7 +240,6 @@ export class FromBTCLNAutoWrapper<
|
|
|
241
240
|
*/
|
|
242
241
|
protected processEventRefund(swap: FromBTCLNAutoSwap<T>, event: RefundEvent<T["Data"]>): Promise<boolean> {
|
|
243
242
|
if(swap._state!==FromBTCLNAutoSwapState.CLAIM_CLAIMED && swap._state!==FromBTCLNAutoSwapState.FAILED) {
|
|
244
|
-
swap._refundTxId ??= event.meta?.txId;
|
|
245
243
|
swap._state = FromBTCLNAutoSwapState.FAILED;
|
|
246
244
|
return Promise.resolve(true);
|
|
247
245
|
}
|
|
@@ -435,8 +433,13 @@ export class FromBTCLNAutoWrapper<
|
|
|
435
433
|
this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined
|
|
436
434
|
);
|
|
437
435
|
|
|
436
|
+
let lnCapacityPromise: Promise<LNNodeLiquidity | null> | undefined;
|
|
437
|
+
if(!_options.unsafeSkipLnNodeCheck) {
|
|
438
|
+
lnCapacityPromise = this.preFetchLnCapacity(lnPublicKey);
|
|
439
|
+
} else lnPublicKey.catch(() => {});
|
|
440
|
+
|
|
438
441
|
return {
|
|
439
|
-
lnCapacityPromise
|
|
442
|
+
lnCapacityPromise,
|
|
440
443
|
resp: await response
|
|
441
444
|
};
|
|
442
445
|
}, undefined, RequestError, abortController.signal);
|
|
@@ -493,8 +496,6 @@ export class FromBTCLNAutoWrapper<
|
|
|
493
496
|
exactIn: amountData.exactIn ?? true
|
|
494
497
|
};
|
|
495
498
|
const quote = new FromBTCLNAutoSwap<T>(this, swapInit);
|
|
496
|
-
await quote._save();
|
|
497
|
-
this.logger.debug("create(): Created new FromBTCLNAutoSwap quote, claimHash (pseudo escrowHash): ", quote._getEscrowHash());
|
|
498
499
|
return quote;
|
|
499
500
|
} catch (e) {
|
|
500
501
|
abortController.abort(e);
|
|
@@ -333,8 +333,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
333
333
|
* @inheritDoc
|
|
334
334
|
* @internal
|
|
335
335
|
*/
|
|
336
|
-
protected canCommit(): boolean {
|
|
337
|
-
if(this._state!==FromBTCSwapState.PR_CREATED) return false;
|
|
336
|
+
protected canCommit(skipQuoteExpiryChecks?: boolean): boolean {
|
|
337
|
+
if(this._state!==FromBTCSwapState.PR_CREATED && (!skipQuoteExpiryChecks || this._state!==FromBTCSwapState.QUOTE_SOFT_EXPIRED)) return false;
|
|
338
338
|
if(this.requiredConfirmations==null) return false;
|
|
339
339
|
const expiry = this.wrapper._getOnchainSendTimeout(this._data, this.requiredConfirmations);
|
|
340
340
|
const currentTimestamp = BigInt(Math.floor(Date.now()/1000));
|
|
@@ -900,7 +900,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
900
900
|
);
|
|
901
901
|
|
|
902
902
|
this._commitTxId = result[result.length - 1];
|
|
903
|
-
if(this._state===FromBTCSwapState.PR_CREATED || this._state===FromBTCSwapState.QUOTE_SOFT_EXPIRED) {
|
|
903
|
+
if(this._state===FromBTCSwapState.PR_CREATED || this._state===FromBTCSwapState.QUOTE_SOFT_EXPIRED || this._state===FromBTCSwapState.QUOTE_EXPIRED) {
|
|
904
904
|
await this._saveAndEmit(FromBTCSwapState.CLAIM_COMMITED);
|
|
905
905
|
}
|
|
906
906
|
return this._commitTxId;
|
|
@@ -1191,6 +1191,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1191
1191
|
return changed;
|
|
1192
1192
|
}
|
|
1193
1193
|
|
|
1194
|
+
private btcTxLastChecked?: number;
|
|
1195
|
+
|
|
1194
1196
|
/**
|
|
1195
1197
|
* @inheritDoc
|
|
1196
1198
|
* @internal
|
|
@@ -1222,6 +1224,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1222
1224
|
}
|
|
1223
1225
|
if(this.address==null) return save;
|
|
1224
1226
|
|
|
1227
|
+
this.btcTxLastChecked = Date.now();
|
|
1225
1228
|
const res = await this.getBitcoinPayment();
|
|
1226
1229
|
if(res!=null) {
|
|
1227
1230
|
if(this.txId!==res.txId) {
|
|
@@ -1261,9 +1264,10 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1261
1264
|
return true;
|
|
1262
1265
|
}
|
|
1263
1266
|
case FromBTCSwapState.EXPIRED:
|
|
1264
|
-
//Check if bitcoin payment was received every 2 minutes
|
|
1265
|
-
if(
|
|
1267
|
+
//Check if bitcoin payment was received at least every 2 minutes
|
|
1268
|
+
if(this.btcTxLastChecked==null || Date.now() - this.btcTxLastChecked > 120_000) {
|
|
1266
1269
|
if(this.address!=null) try {
|
|
1270
|
+
this.btcTxLastChecked = Date.now();
|
|
1267
1271
|
const res = await this.getBitcoinPayment();
|
|
1268
1272
|
if(res!=null) {
|
|
1269
1273
|
let shouldSave: boolean = false;
|
|
@@ -150,6 +150,7 @@ export class FromBTCWrapper<
|
|
|
150
150
|
super(
|
|
151
151
|
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, swapDataDeserializer,
|
|
152
152
|
{
|
|
153
|
+
...options,
|
|
153
154
|
bitcoinNetwork: options?.bitcoinNetwork ?? TEST_NETWORK,
|
|
154
155
|
safetyFactor: options?.safetyFactor ?? 2,
|
|
155
156
|
blocksTillTxConfirms: options?.blocksTillTxConfirms ?? 12,
|
|
@@ -472,8 +473,13 @@ export class FromBTCWrapper<
|
|
|
472
473
|
this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined
|
|
473
474
|
);
|
|
474
475
|
|
|
476
|
+
let signDataPromise = _signDataPromise;
|
|
477
|
+
if(signDataPromise==null) {
|
|
478
|
+
signDataPromise = this.preFetchSignData(signDataPrefetch);
|
|
479
|
+
} else signDataPrefetch.catch(() => {});
|
|
480
|
+
|
|
475
481
|
return {
|
|
476
|
-
signDataPromise
|
|
482
|
+
signDataPromise,
|
|
477
483
|
resp: await response
|
|
478
484
|
};
|
|
479
485
|
}, undefined, e => e instanceof RequestError, abortController.signal);
|
|
@@ -506,7 +512,6 @@ export class FromBTCWrapper<
|
|
|
506
512
|
exactIn: amountData.exactIn ?? true,
|
|
507
513
|
requiredConfirmations: resp.confirmations
|
|
508
514
|
} as FromBTCSwapInit<T["Data"]>);
|
|
509
|
-
await quote._save();
|
|
510
515
|
return quote;
|
|
511
516
|
} catch (e) {
|
|
512
517
|
abortController.abort(e);
|
|
@@ -593,7 +593,7 @@ export abstract class IToBTCSwap<
|
|
|
593
593
|
* @throws {Error} When in invalid state (not {@link ToBTCSwapState.CREATED})
|
|
594
594
|
*/
|
|
595
595
|
async txsCommit(skipChecks?: boolean): Promise<T["TX"][]> {
|
|
596
|
-
if(this._state!==ToBTCSwapState.CREATED) throw new Error("Must be in CREATED state!");
|
|
596
|
+
if(this._state!==ToBTCSwapState.CREATED && (!skipChecks || this._state!==ToBTCSwapState.QUOTE_SOFT_EXPIRED)) throw new Error("Must be in CREATED state!");
|
|
597
597
|
if(this.signatureData==null) throw new Error("Init signature data not known, cannot commit!");
|
|
598
598
|
|
|
599
599
|
if(!this.initiated) {
|
|
@@ -90,7 +90,6 @@ export abstract class IToBTCWrapper<
|
|
|
90
90
|
protected async processEventInitialize(swap: D["Swap"], event: InitializeEvent<T["Data"]>): Promise<boolean> {
|
|
91
91
|
if(swap._state===ToBTCSwapState.CREATED || swap._state===ToBTCSwapState.QUOTE_SOFT_EXPIRED) {
|
|
92
92
|
swap._state = ToBTCSwapState.COMMITED;
|
|
93
|
-
if(swap._commitTxId==null) swap._commitTxId = event.meta?.txId;
|
|
94
93
|
return true;
|
|
95
94
|
}
|
|
96
95
|
return false;
|
|
@@ -108,7 +107,6 @@ export abstract class IToBTCWrapper<
|
|
|
108
107
|
this.logger.warn(`processEventClaim(): Failed to set payment result ${event.result}: `, e);
|
|
109
108
|
});
|
|
110
109
|
swap._state = ToBTCSwapState.CLAIMED;
|
|
111
|
-
if(swap._claimTxId==null) swap._claimTxId = event.meta?.txId;
|
|
112
110
|
return true;
|
|
113
111
|
}
|
|
114
112
|
return false;
|
|
@@ -120,7 +118,6 @@ export abstract class IToBTCWrapper<
|
|
|
120
118
|
protected processEventRefund(swap: D["Swap"], event: RefundEvent<T["Data"]>): Promise<boolean> {
|
|
121
119
|
if(swap._state!==ToBTCSwapState.CLAIMED && swap._state!==ToBTCSwapState.REFUNDED) {
|
|
122
120
|
swap._state = ToBTCSwapState.REFUNDED;
|
|
123
|
-
if(swap._refundTxId==null) swap._refundTxId = event.meta?.txId;
|
|
124
121
|
return Promise.resolve(true);
|
|
125
122
|
}
|
|
126
123
|
return Promise.resolve(false);
|
|
@@ -112,6 +112,7 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
112
112
|
super(
|
|
113
113
|
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, swapDataDeserializer,
|
|
114
114
|
{
|
|
115
|
+
...options,
|
|
115
116
|
paymentTimeoutSeconds: options?.paymentTimeoutSeconds ?? 5*24*60*60,
|
|
116
117
|
lightningBaseFee: options?.lightningBaseFee ?? 10,
|
|
117
118
|
lightningFeePPM: options?.lightningFeePPM ?? 2000
|
|
@@ -289,8 +290,13 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
289
290
|
additionalParams
|
|
290
291
|
}, this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined);
|
|
291
292
|
|
|
293
|
+
let signDataPromise = preFetches.signDataPrefetchPromise;
|
|
294
|
+
if(signDataPromise==null) {
|
|
295
|
+
signDataPromise = this.preFetchSignData(signDataPrefetch);
|
|
296
|
+
} else signDataPrefetch.catch(() => {});
|
|
297
|
+
|
|
292
298
|
return {
|
|
293
|
-
signDataPromise
|
|
299
|
+
signDataPromise,
|
|
294
300
|
resp: await response
|
|
295
301
|
};
|
|
296
302
|
}, undefined, e => e instanceof RequestError, abortController.signal);
|
|
@@ -335,7 +341,6 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
335
341
|
pr,
|
|
336
342
|
exactIn: false
|
|
337
343
|
} as IToBTCSwapInit<T["Data"]>);
|
|
338
|
-
await quote._save();
|
|
339
344
|
return quote;
|
|
340
345
|
} catch (e) {
|
|
341
346
|
abortController.abort(e);
|
|
@@ -539,7 +544,6 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
539
544
|
pr: invoice,
|
|
540
545
|
exactIn: true
|
|
541
546
|
} as IToBTCSwapInit<T["Data"]>);
|
|
542
|
-
await quote._save();
|
|
543
547
|
return quote;
|
|
544
548
|
} catch (e) {
|
|
545
549
|
abortController.abort(e);
|
|
@@ -97,6 +97,7 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
97
97
|
super(
|
|
98
98
|
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, swapDataDeserializer,
|
|
99
99
|
{
|
|
100
|
+
...options,
|
|
100
101
|
bitcoinNetwork: options?.bitcoinNetwork ?? TEST_NETWORK,
|
|
101
102
|
safetyFactor: options?.safetyFactor ?? 2,
|
|
102
103
|
maxConfirmations: options?.maxConfirmations ?? 6,
|
|
@@ -272,8 +273,13 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
272
273
|
additionalParams
|
|
273
274
|
}, this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined);
|
|
274
275
|
|
|
276
|
+
let signDataPromise = _signDataPromise;
|
|
277
|
+
if(signDataPromise==null) {
|
|
278
|
+
signDataPromise = this.preFetchSignData(signDataPrefetch);
|
|
279
|
+
} else signDataPrefetch.catch(() => {});
|
|
280
|
+
|
|
275
281
|
return {
|
|
276
|
-
signDataPromise
|
|
282
|
+
signDataPromise,
|
|
277
283
|
resp: await response
|
|
278
284
|
};
|
|
279
285
|
}, undefined, RequestError, abortController.signal);
|
|
@@ -319,7 +325,6 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
319
325
|
requiredConfirmations: _options.confirmations,
|
|
320
326
|
nonce
|
|
321
327
|
} as ToBTCSwapInit<T["Data"]>);
|
|
322
|
-
await quote._save();
|
|
323
328
|
return quote;
|
|
324
329
|
} catch (e) {
|
|
325
330
|
abortController.abort(e);
|