@atomiqlabs/sdk 8.6.2 → 8.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/events/UnifiedSwapEventListener.js +4 -2
- package/dist/http/paramcoders/ParamDecoder.js +9 -4
- package/dist/http/paramcoders/ParamEncoder.js +6 -1
- package/dist/intermediaries/Intermediary.d.ts +21 -0
- package/dist/intermediaries/Intermediary.js +25 -1
- package/dist/intermediaries/IntermediaryDiscovery.d.ts +15 -3
- package/dist/intermediaries/IntermediaryDiscovery.js +25 -6
- package/dist/intermediaries/apis/IntermediaryAPI.d.ts +1 -0
- package/dist/swapper/Swapper.d.ts +9 -4
- package/dist/swapper/Swapper.js +94 -42
- package/dist/swapper/SwapperUtils.js +2 -1
- package/dist/swaps/ISwap.d.ts +5 -0
- package/dist/swaps/ISwap.js +4 -1
- package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +5 -5
- package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +4 -0
- package/dist/swaps/escrow_swaps/IEscrowSwap.js +4 -3
- package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +19 -6
- package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +54 -21
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +7 -3
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +3 -4
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +3 -3
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +8 -2
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +12 -8
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +18 -18
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +12 -6
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +38 -24
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +9 -9
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +14 -7
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +54 -38
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +5 -5
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +18 -7
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +61 -33
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +12 -12
- package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +8 -2
- package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +13 -8
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +1 -1
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +13 -4
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +44 -28
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +2 -2
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +8 -4
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +29 -21
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +1 -0
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +13 -12
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +21 -10
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +136 -73
- package/dist/swaps/trusted/ln/LnForGasWrapper.js +2 -1
- package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +2 -1
- package/dist/utils/RetryUtils.d.ts +2 -1
- package/dist/utils/RetryUtils.js +3 -2
- package/dist/utils/Utils.d.ts +9 -0
- package/dist/utils/Utils.js +15 -1
- package/package.json +2 -2
- package/src/events/UnifiedSwapEventListener.ts +4 -2
- package/src/http/paramcoders/ParamDecoder.ts +8 -4
- package/src/http/paramcoders/ParamEncoder.ts +5 -1
- package/src/intermediaries/Intermediary.ts +31 -1
- package/src/intermediaries/IntermediaryDiscovery.ts +33 -12
- package/src/intermediaries/apis/IntermediaryAPI.ts +2 -1
- package/src/swapper/Swapper.ts +141 -62
- package/src/swapper/SwapperUtils.ts +3 -1
- package/src/swaps/ISwap.ts +10 -2
- package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +5 -5
- package/src/swaps/escrow_swaps/IEscrowSwap.ts +10 -3
- package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +64 -26
- package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +8 -5
- package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +3 -3
- package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +22 -12
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +18 -18
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +52 -31
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +9 -9
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +76 -52
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +5 -5
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +82 -38
- package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +12 -12
- package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +21 -9
- package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +1 -1
- package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +56 -33
- package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +2 -2
- package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +40 -22
- package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +17 -13
- package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +149 -83
- package/src/swaps/trusted/ln/LnForGasWrapper.ts +2 -1
- package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +2 -1
- package/src/utils/RetryUtils.ts +11 -4
- package/src/utils/Utils.ts +14 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Intermediary, ServicesType} from "./Intermediary";
|
|
2
2
|
import {SwapType} from "../enums/SwapType";
|
|
3
|
-
import {SwapContract} from "@atomiqlabs/base";
|
|
3
|
+
import {SpvVaultContract, SwapContract} from "@atomiqlabs/base";
|
|
4
4
|
import {EventEmitter} from "events";
|
|
5
5
|
import {Buffer} from "buffer";
|
|
6
6
|
import {bigIntMax, bigIntMin, extendAbortController} from "../utils/Utils";
|
|
@@ -169,7 +169,7 @@ export class IntermediaryDiscovery extends EventEmitter {
|
|
|
169
169
|
/**
|
|
170
170
|
* Swap contracts for checking intermediary signatures
|
|
171
171
|
*/
|
|
172
|
-
swapContracts: {[
|
|
172
|
+
swapContracts: {[chainIdentifier: string]: {[contractVersion: string]: {swapContract: SwapContract, spvVaultContract: SpvVaultContract}}};
|
|
173
173
|
/**
|
|
174
174
|
* Registry URL used as a source for the list of intermediaries, this should be a link to a
|
|
175
175
|
* github-hosted JSON file
|
|
@@ -193,7 +193,7 @@ export class IntermediaryDiscovery extends EventEmitter {
|
|
|
193
193
|
private overrideNodeUrls?: string[];
|
|
194
194
|
|
|
195
195
|
constructor(
|
|
196
|
-
swapContracts: {[
|
|
196
|
+
swapContracts: {[chainIdentifier: string]: {[contractVersion: string]: {swapContract: SwapContract, spvVaultContract: SpvVaultContract}}},
|
|
197
197
|
registryUrl: string = REGISTRY_URL,
|
|
198
198
|
nodeUrls?: string[],
|
|
199
199
|
httpRequestTimeout?: number,
|
|
@@ -236,26 +236,39 @@ export class IntermediaryDiscovery extends EventEmitter {
|
|
|
236
236
|
* @param url
|
|
237
237
|
* @param abortSignal
|
|
238
238
|
*/
|
|
239
|
-
private async getNodeInfo(url: string, abortSignal?: AbortSignal) : Promise<{
|
|
239
|
+
private async getNodeInfo(url: string, abortSignal?: AbortSignal) : Promise<{
|
|
240
|
+
addresses: {[chainIdentifier: string]: string},
|
|
241
|
+
contractVersions: {[chainIdentifier: string]: string},
|
|
242
|
+
info: InfoHandlerResponseEnvelope
|
|
243
|
+
}> {
|
|
240
244
|
const response = await tryWithRetries(
|
|
241
245
|
() => IntermediaryAPI.getIntermediaryInfo(url, this.httpRequestTimeout, abortSignal),
|
|
242
246
|
{maxRetries: 3, delay: 100, exponential: true},
|
|
243
247
|
undefined,
|
|
244
|
-
abortSignal
|
|
248
|
+
abortSignal,
|
|
249
|
+
"debug"
|
|
245
250
|
);
|
|
246
251
|
abortSignal?.throwIfAborted();
|
|
247
252
|
|
|
248
253
|
const promises: Promise<void>[] = [];
|
|
249
|
-
const addresses: {[
|
|
254
|
+
const addresses: {[chainIdentifier: string]: string} = {};
|
|
255
|
+
const contractVersions: {[chainIdentifier: string]: string} = {};
|
|
250
256
|
for(let chain in response.chains) {
|
|
251
257
|
if(this.swapContracts[chain]!=null) {
|
|
258
|
+
const {signature, address, contractVersion} = response.chains[chain];
|
|
259
|
+
const _contractVersion = contractVersion ?? "v1";
|
|
260
|
+
const contract = this.swapContracts[chain][_contractVersion];
|
|
261
|
+
if(contract==null) {
|
|
262
|
+
logger.warn("getNodeInfo(): Unknown chain contract version "+_contractVersion+" for "+chain+" reported by intermediary: "+url);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
252
265
|
promises.push((async () => {
|
|
253
|
-
const {signature, address} = response.chains[chain];
|
|
254
266
|
try {
|
|
255
|
-
await
|
|
267
|
+
await contract.swapContract.isValidDataSignature(Buffer.from(response.envelope), signature, address);
|
|
256
268
|
addresses[chain] = address;
|
|
269
|
+
contractVersions[chain] = _contractVersion;
|
|
257
270
|
} catch (e) {
|
|
258
|
-
logger.warn("Failed to verify "+chain+" signature for intermediary: "+url);
|
|
271
|
+
logger.warn("getNodeInfo(): Failed to verify "+chain+" signature for intermediary: "+url);
|
|
259
272
|
}
|
|
260
273
|
})());
|
|
261
274
|
}
|
|
@@ -284,6 +297,7 @@ export class IntermediaryDiscovery extends EventEmitter {
|
|
|
284
297
|
|
|
285
298
|
return {
|
|
286
299
|
addresses,
|
|
300
|
+
contractVersions,
|
|
287
301
|
info
|
|
288
302
|
};
|
|
289
303
|
}
|
|
@@ -302,9 +316,10 @@ export class IntermediaryDiscovery extends EventEmitter {
|
|
|
302
316
|
for(let key in nodeInfo.info.services) {
|
|
303
317
|
services[swapHandlerTypeToSwapType(key as SwapHandlerType)] = nodeInfo.info.services[key as SwapHandlerType];
|
|
304
318
|
}
|
|
305
|
-
return new Intermediary(url, nodeInfo.addresses, services);
|
|
306
|
-
} catch (e) {
|
|
307
|
-
logger.warn("fetchIntermediaries():
|
|
319
|
+
return new Intermediary(url, nodeInfo.addresses, services, undefined, nodeInfo.contractVersions);
|
|
320
|
+
} catch (e: any) {
|
|
321
|
+
logger.warn("fetchIntermediaries(): Intermediary "+url+` is unreachable due to ${e.name ?? e.message} error, skipping...`);
|
|
322
|
+
logger.debug("fetchIntermediaries(): Error contacting intermediary "+url+": ", e);
|
|
308
323
|
return null;
|
|
309
324
|
}
|
|
310
325
|
}
|
|
@@ -474,6 +489,8 @@ export class IntermediaryDiscovery extends EventEmitter {
|
|
|
474
489
|
/**
|
|
475
490
|
* Returns swap candidates for a specific swap type & token address
|
|
476
491
|
*
|
|
492
|
+
* @remark Also filters the LPs based on supported swap versions
|
|
493
|
+
*
|
|
477
494
|
* @param chainIdentifier Chain identifier of the smart chain
|
|
478
495
|
* @param swapType Swap protocol type
|
|
479
496
|
* @param tokenAddress Token address
|
|
@@ -489,6 +506,10 @@ export class IntermediaryDiscovery extends EventEmitter {
|
|
|
489
506
|
if(swapService.chainTokens==null) return false;
|
|
490
507
|
if(swapService.chainTokens[chainIdentifier]==null) return false;
|
|
491
508
|
if(!swapService.chainTokens[chainIdentifier].includes(tokenAddress.toString())) return false;
|
|
509
|
+
const contracts = this.swapContracts[chainIdentifier][e.getContractVersion(chainIdentifier) ?? "v1"];
|
|
510
|
+
if(contracts==null) return false;
|
|
511
|
+
if(swapType===SwapType.FROM_BTCLN_AUTO && !contracts.swapContract?.supportsInitWithoutClaimer) return false;
|
|
512
|
+
if(swapType===SwapType.SPV_VAULT_FROM_BTC && contracts.spvVaultContract==null) return false;
|
|
492
513
|
return true;
|
|
493
514
|
});
|
|
494
515
|
|
package/src/swapper/Swapper.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ChainSwapType,
|
|
7
7
|
ChainType, LightningNetworkApi,
|
|
8
8
|
Messenger,
|
|
9
|
-
RelaySynchronizer
|
|
9
|
+
RelaySynchronizer, SpvWithdrawalClaimedState, SpvWithdrawalFrontedState, SwapCommitState, SwapContract, SwapData
|
|
10
10
|
} from "@atomiqlabs/base";
|
|
11
11
|
import {
|
|
12
12
|
ToBTCLNOptions,
|
|
@@ -190,14 +190,20 @@ type ChainSpecificData<T extends ChainType> = {
|
|
|
190
190
|
[SwapType.FROM_BTCLN_AUTO]: FromBTCLNAutoWrapper<T>
|
|
191
191
|
}
|
|
192
192
|
chainEvents: T["Events"],
|
|
193
|
-
swapContract: T["Contract"],
|
|
194
|
-
spvVaultContract: T["SpvVaultContract"],
|
|
195
193
|
chainInterface: T["ChainInterface"],
|
|
196
|
-
btcRelay: BtcRelay<any, T["TX"], BtcBlock, T["Signer"]>,
|
|
197
|
-
synchronizer: RelaySynchronizer<any, T["TX"], BtcBlock>,
|
|
198
194
|
unifiedChainEvents: UnifiedSwapEventListener<T>,
|
|
199
195
|
unifiedSwapStorage: UnifiedSwapStorage<T>,
|
|
200
|
-
reviver: (val: any) => ISwap<T
|
|
196
|
+
reviver: (val: any) => ISwap<T>,
|
|
197
|
+
defaultVersion: string,
|
|
198
|
+
|
|
199
|
+
versionedContracts: {
|
|
200
|
+
[contractVersion: string]: {
|
|
201
|
+
swapContract: T["Contract"],
|
|
202
|
+
spvVaultContract: T["SpvVaultContract"],
|
|
203
|
+
btcRelay: BtcRelay<any, T["TX"], BtcBlock, T["Signer"]>,
|
|
204
|
+
synchronizer: RelaySynchronizer<any, T["TX"], BtcBlock>,
|
|
205
|
+
}
|
|
206
|
+
}
|
|
201
207
|
};
|
|
202
208
|
|
|
203
209
|
type MultiChainData<T extends MultiChain> = {
|
|
@@ -358,12 +364,37 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
358
364
|
};
|
|
359
365
|
|
|
360
366
|
this._chains = objectMap<CtorMultiChainData<T>, MultiChainData<T>>(chainsData, <InputKey extends keyof CtorMultiChainData<T>>(chainData: CtorMultiChainData<T>[InputKey], key: string) => {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
367
|
+
let {
|
|
368
|
+
chainInterface, chainEvents, chainId,
|
|
369
|
+
btcRelay,
|
|
370
|
+
swapContract, swapDataConstructor,
|
|
371
|
+
spvVaultContract, spvVaultWithdrawalDataConstructor, spvVaultDataConstructor,
|
|
372
|
+
defaultVersion, versions
|
|
365
373
|
} = chainData;
|
|
366
|
-
|
|
374
|
+
|
|
375
|
+
defaultVersion ??= "v1";
|
|
376
|
+
|
|
377
|
+
if(versions==null) {
|
|
378
|
+
versions = {
|
|
379
|
+
[defaultVersion]: {
|
|
380
|
+
btcRelay,
|
|
381
|
+
swapContract,
|
|
382
|
+
swapDataConstructor,
|
|
383
|
+
spvVaultContract,
|
|
384
|
+
spvVaultDataConstructor,
|
|
385
|
+
spvVaultWithdrawalDataConstructor
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const versionedContracts = objectMap(versions, (value, key) => {
|
|
391
|
+
return {
|
|
392
|
+
swapContract: value.swapContract,
|
|
393
|
+
spvVaultContract: value.spvVaultContract,
|
|
394
|
+
btcRelay: value.btcRelay,
|
|
395
|
+
synchronizer: bitcoinSynchronizer(value.btcRelay)
|
|
396
|
+
};
|
|
397
|
+
});
|
|
367
398
|
|
|
368
399
|
const storageHandler = swapStorage(storagePrefix + chainId);
|
|
369
400
|
const unifiedSwapStorage = new UnifiedSwapStorage<T[InputKey]>(storageHandler, this.options.noSwapCache);
|
|
@@ -376,10 +407,9 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
376
407
|
unifiedSwapStorage,
|
|
377
408
|
unifiedChainEvents,
|
|
378
409
|
chainInterface,
|
|
379
|
-
swapContract,
|
|
380
410
|
pricing,
|
|
381
411
|
this._tokens[chainId],
|
|
382
|
-
|
|
412
|
+
versions,
|
|
383
413
|
{
|
|
384
414
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
385
415
|
postRequestTimeout: this.options.postRequestTimeout,
|
|
@@ -391,10 +421,9 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
391
421
|
unifiedSwapStorage,
|
|
392
422
|
unifiedChainEvents,
|
|
393
423
|
chainInterface,
|
|
394
|
-
swapContract,
|
|
395
424
|
pricing,
|
|
396
425
|
this._tokens[chainId],
|
|
397
|
-
|
|
426
|
+
versions,
|
|
398
427
|
this._bitcoinRpc,
|
|
399
428
|
{
|
|
400
429
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
@@ -408,10 +437,9 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
408
437
|
unifiedSwapStorage,
|
|
409
438
|
unifiedChainEvents,
|
|
410
439
|
chainInterface,
|
|
411
|
-
swapContract,
|
|
412
440
|
pricing,
|
|
413
441
|
this._tokens[chainId],
|
|
414
|
-
|
|
442
|
+
versions,
|
|
415
443
|
lightningApi,
|
|
416
444
|
{
|
|
417
445
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
@@ -425,12 +453,10 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
425
453
|
unifiedSwapStorage,
|
|
426
454
|
unifiedChainEvents,
|
|
427
455
|
chainInterface,
|
|
428
|
-
swapContract,
|
|
429
456
|
pricing,
|
|
430
457
|
this._tokens[chainId],
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
synchronizer,
|
|
458
|
+
versions,
|
|
459
|
+
versionedContracts,
|
|
434
460
|
this._bitcoinRpc,
|
|
435
461
|
{
|
|
436
462
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
@@ -468,18 +494,17 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
468
494
|
}
|
|
469
495
|
);
|
|
470
496
|
|
|
497
|
+
// This is gated on the default version of the contracts
|
|
471
498
|
if(spvVaultContract!=null) {
|
|
472
499
|
wrappers[SwapType.SPV_VAULT_FROM_BTC] = new SpvFromBTCWrapper<T[InputKey]>(
|
|
473
500
|
key,
|
|
474
501
|
unifiedSwapStorage,
|
|
475
502
|
unifiedChainEvents,
|
|
476
503
|
chainInterface,
|
|
477
|
-
spvVaultContract,
|
|
478
504
|
pricing,
|
|
479
505
|
this._tokens[chainId],
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
synchronizer,
|
|
506
|
+
versions,
|
|
507
|
+
versionedContracts,
|
|
483
508
|
bitcoinRpc,
|
|
484
509
|
{
|
|
485
510
|
getRequestTimeout: this.options.getRequestTimeout,
|
|
@@ -490,16 +515,16 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
490
515
|
);
|
|
491
516
|
}
|
|
492
517
|
|
|
518
|
+
// This is gated on the default version of the contracts
|
|
493
519
|
if(swapContract.supportsInitWithoutClaimer) {
|
|
494
520
|
wrappers[SwapType.FROM_BTCLN_AUTO] = new FromBTCLNAutoWrapper<T[InputKey]>(
|
|
495
521
|
key,
|
|
496
522
|
unifiedSwapStorage,
|
|
497
523
|
unifiedChainEvents,
|
|
498
524
|
chainInterface,
|
|
499
|
-
swapContract,
|
|
500
525
|
pricing,
|
|
501
526
|
this._tokens[chainId],
|
|
502
|
-
|
|
527
|
+
versions,
|
|
503
528
|
lightningApi,
|
|
504
529
|
this.messenger,
|
|
505
530
|
{
|
|
@@ -521,22 +546,22 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
521
546
|
|
|
522
547
|
return {
|
|
523
548
|
chainEvents,
|
|
524
|
-
spvVaultContract,
|
|
525
|
-
swapContract,
|
|
526
549
|
chainInterface,
|
|
527
|
-
btcRelay,
|
|
528
|
-
synchronizer,
|
|
529
550
|
|
|
530
551
|
wrappers,
|
|
531
552
|
|
|
532
553
|
unifiedChainEvents,
|
|
533
554
|
unifiedSwapStorage,
|
|
534
555
|
|
|
535
|
-
|
|
556
|
+
defaultVersion,
|
|
557
|
+
|
|
558
|
+
reviver,
|
|
559
|
+
|
|
560
|
+
versionedContracts
|
|
536
561
|
}
|
|
537
562
|
});
|
|
538
563
|
|
|
539
|
-
const contracts = objectMap(chainsData, (data) => data.swapContract);
|
|
564
|
+
const contracts = objectMap(chainsData, (data) => data.versions ?? {[data.defaultVersion ?? "v1"]: {swapContract: data.swapContract, spvVaultContract: data.spvVaultContract}});
|
|
540
565
|
if(options.intermediaryUrl!=null) {
|
|
541
566
|
this.intermediaryDiscovery = new IntermediaryDiscovery(contracts, options.registryUrl, Array.isArray(options.intermediaryUrl) ? options.intermediaryUrl : [options.intermediaryUrl], options.getRequestTimeout);
|
|
542
567
|
} else {
|
|
@@ -553,7 +578,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
553
578
|
}
|
|
554
579
|
|
|
555
580
|
private async _init(): Promise<void> {
|
|
556
|
-
this.logger.debug("init(): Initializing swapper
|
|
581
|
+
this.logger.debug("init(): Initializing swapper...");
|
|
557
582
|
|
|
558
583
|
const abortController = new AbortController();
|
|
559
584
|
|
|
@@ -594,14 +619,23 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
594
619
|
for(let chainIdentifier in this._chains) {
|
|
595
620
|
chainPromises.push((async() => {
|
|
596
621
|
const {
|
|
597
|
-
|
|
622
|
+
chainInterface,
|
|
623
|
+
versionedContracts,
|
|
598
624
|
unifiedChainEvents,
|
|
599
625
|
unifiedSwapStorage,
|
|
600
626
|
wrappers,
|
|
601
627
|
reviver
|
|
602
628
|
} = this._chains[chainIdentifier];
|
|
603
|
-
|
|
604
|
-
|
|
629
|
+
|
|
630
|
+
const _chainInterface: any = chainInterface;
|
|
631
|
+
if(_chainInterface.verifyNetwork!=null) {
|
|
632
|
+
await _chainInterface.verifyNetwork(this.bitcoinNetwork);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
for(let contractVersion in versionedContracts) {
|
|
636
|
+
await versionedContracts[contractVersion].swapContract.start();
|
|
637
|
+
this.logger.debug("init(): Intialized swap contract: "+chainIdentifier+` version: ${contractVersion}`);
|
|
638
|
+
}
|
|
605
639
|
|
|
606
640
|
await unifiedSwapStorage.init();
|
|
607
641
|
if(unifiedSwapStorage.storage instanceof IndexedDBUnifiedStorage) {
|
|
@@ -1865,18 +1899,56 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1865
1899
|
* initiated after this blockheight
|
|
1866
1900
|
*/
|
|
1867
1901
|
async recoverSwaps<C extends ChainIds<T>>(chainId: C, signer: string, startBlockheight?: number): Promise<ISwap<T[C]>[]> {
|
|
1868
|
-
|
|
1902
|
+
//TODO: Recover swaps from all the known contract versions
|
|
1903
|
+
const {versionedContracts, unifiedSwapStorage, reviver, wrappers} = this._chains[chainId];
|
|
1869
1904
|
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1905
|
+
const recoveredSwaps: ISwap<T[C]>[] = [];
|
|
1906
|
+
let someVersionSupportsRecovery = false;
|
|
1907
|
+
const recoveredEscrowStates: {
|
|
1908
|
+
[p: string]: {
|
|
1909
|
+
init?: {
|
|
1910
|
+
data: SwapData
|
|
1911
|
+
getInitTxId: () => Promise<string>
|
|
1912
|
+
getTxBlock: () => Promise<{
|
|
1913
|
+
blockTime: number
|
|
1914
|
+
blockHeight: number
|
|
1915
|
+
}>
|
|
1916
|
+
},
|
|
1917
|
+
state: SwapCommitState
|
|
1918
|
+
contractVersion: string
|
|
1919
|
+
}
|
|
1920
|
+
} = {};
|
|
1921
|
+
const recoveredSpvStates: {
|
|
1922
|
+
[contractVersion: string]: {
|
|
1923
|
+
[escrowHash: string]: SpvWithdrawalClaimedState | SpvWithdrawalFrontedState
|
|
1924
|
+
}
|
|
1925
|
+
} = {};
|
|
1926
|
+
|
|
1927
|
+
for(let contractVersion in versionedContracts) {
|
|
1928
|
+
const {swapContract, spvVaultContract} = versionedContracts[contractVersion];
|
|
1929
|
+
|
|
1930
|
+
if(
|
|
1931
|
+
swapContract.getHistoricalSwaps==null ||
|
|
1932
|
+
(spvVaultContract!=null && spvVaultContract.getHistoricalWithdrawalStates==null)
|
|
1933
|
+
) {
|
|
1934
|
+
this.logger.warn(`recoverSwaps(): Swap data recovery not supported on ${chainId}, with contract version ${contractVersion}`);
|
|
1935
|
+
continue;
|
|
1936
|
+
}
|
|
1874
1937
|
|
|
1875
|
-
|
|
1876
|
-
const spvVaultData = await spvVaultContract?.getHistoricalWithdrawalStates!(signer, startBlockheight);
|
|
1938
|
+
someVersionSupportsRecovery = true;
|
|
1877
1939
|
|
|
1878
|
-
|
|
1879
|
-
|
|
1940
|
+
const {swaps} = await swapContract.getHistoricalSwaps(signer, startBlockheight);
|
|
1941
|
+
const spvVaultData = wrappers[SwapType.SPV_VAULT_FROM_BTC]==null
|
|
1942
|
+
? undefined
|
|
1943
|
+
: await spvVaultContract?.getHistoricalWithdrawalStates!(signer, startBlockheight);
|
|
1944
|
+
|
|
1945
|
+
for(let key in swaps) recoveredEscrowStates[key] = {...swaps[key], contractVersion};
|
|
1946
|
+
if(spvVaultData!=null) for(let key in spvVaultData.withdrawals) (recoveredSpvStates[contractVersion] ??= {})[key] = spvVaultData.withdrawals[key];
|
|
1947
|
+
}
|
|
1948
|
+
if(!someVersionSupportsRecovery) throw new Error(`Historical swap recovery is not supported for ${chainId}`);
|
|
1949
|
+
|
|
1950
|
+
const escrowHashes = Object.keys(recoveredEscrowStates);
|
|
1951
|
+
for(let contractVersion in recoveredSpvStates) Object.keys(recoveredSpvStates[contractVersion]).forEach(btcTxId => escrowHashes.push(btcTxId));
|
|
1880
1952
|
this.logger.debug(`recoverSwaps(): Loaded on-chain data for ${escrowHashes.length} swaps`);
|
|
1881
1953
|
this.logger.debug(`recoverSwaps(): Fetching if swap escrowHashes are known: ${escrowHashes.join(", ")}`);
|
|
1882
1954
|
const knownSwapsArray = await unifiedSwapStorage.query([[{key: "escrowHash", value: escrowHashes}]], reviver);
|
|
@@ -1887,11 +1959,10 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1887
1959
|
});
|
|
1888
1960
|
this.logger.debug(`recoverSwaps(): Fetched known swaps escrowHashes: ${Object.keys(knownSwaps).join(", ")}`);
|
|
1889
1961
|
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
for(let escrowHash in swaps) {
|
|
1893
|
-
const {init, state} = swaps[escrowHash];
|
|
1962
|
+
for(let escrowHash in recoveredEscrowStates) {
|
|
1963
|
+
const {init, state, contractVersion} = recoveredEscrowStates[escrowHash];
|
|
1894
1964
|
const knownSwap = knownSwaps[escrowHash];
|
|
1965
|
+
const { swapContract } = versionedContracts[contractVersion];
|
|
1895
1966
|
|
|
1896
1967
|
if(knownSwap==null) {
|
|
1897
1968
|
if(init==null) {
|
|
@@ -1900,6 +1971,10 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1900
1971
|
}
|
|
1901
1972
|
} else if(knownSwap instanceof IEscrowSwap) {
|
|
1902
1973
|
this.logger.debug(`recoverSwaps(escrow): Forcibly updating ${escrowHash} swap: swap already known and in local storage!`);
|
|
1974
|
+
if((knownSwap._contractVersion ?? "v1")!==contractVersion) {
|
|
1975
|
+
this.logger.debug(`recoverSwaps(escrow): Skipping ${escrowHash} swap: swap uses contract version ${knownSwap._contractVersion ?? "v1"}, but state comes from ${contractVersion}!`);
|
|
1976
|
+
continue;
|
|
1977
|
+
}
|
|
1903
1978
|
if(await knownSwap._forciblySetOnchainState(state)) {
|
|
1904
1979
|
await knownSwap._save();
|
|
1905
1980
|
}
|
|
@@ -1919,27 +1994,27 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1919
1994
|
//To BTCLN
|
|
1920
1995
|
typeIdentified = true;
|
|
1921
1996
|
const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
|
|
1922
|
-
swap = await wrappers[SwapType.TO_BTCLN].recoverFromSwapDataAndState(init, state, lp);
|
|
1997
|
+
swap = await wrappers[SwapType.TO_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
|
|
1923
1998
|
} else if(data.isClaimer(signer)) {
|
|
1924
1999
|
//From BTCLN
|
|
1925
2000
|
typeIdentified = true;
|
|
1926
2001
|
const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
|
|
1927
|
-
if(
|
|
1928
|
-
swap = await wrappers[SwapType.FROM_BTCLN_AUTO].recoverFromSwapDataAndState(init, state, lp);
|
|
2002
|
+
if(swapContract.supportsInitWithoutClaimer && wrappers[SwapType.FROM_BTCLN_AUTO]!=null) {
|
|
2003
|
+
swap = await wrappers[SwapType.FROM_BTCLN_AUTO].recoverFromSwapDataAndState(init, state, contractVersion, lp);
|
|
1929
2004
|
} else {
|
|
1930
|
-
swap = await wrappers[SwapType.FROM_BTCLN].recoverFromSwapDataAndState(init, state, lp);
|
|
2005
|
+
swap = await wrappers[SwapType.FROM_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
|
|
1931
2006
|
}
|
|
1932
2007
|
}
|
|
1933
2008
|
} else if(data.getType()===ChainSwapType.CHAIN_NONCED) {
|
|
1934
2009
|
//To BTC
|
|
1935
2010
|
typeIdentified = true;
|
|
1936
2011
|
const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
|
|
1937
|
-
swap = await wrappers[SwapType.TO_BTC].recoverFromSwapDataAndState(init, state, lp);
|
|
2012
|
+
swap = await wrappers[SwapType.TO_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
|
|
1938
2013
|
} else if(data.getType()===ChainSwapType.CHAIN) {
|
|
1939
2014
|
//From BTC
|
|
1940
2015
|
typeIdentified = true;
|
|
1941
2016
|
const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
|
|
1942
|
-
swap = await wrappers[SwapType.FROM_BTC].recoverFromSwapDataAndState(init, state, lp);
|
|
2017
|
+
swap = await wrappers[SwapType.FROM_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
|
|
1943
2018
|
}
|
|
1944
2019
|
|
|
1945
2020
|
if(swap!=null) {
|
|
@@ -1949,17 +2024,20 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1949
2024
|
}
|
|
1950
2025
|
}
|
|
1951
2026
|
|
|
1952
|
-
|
|
2027
|
+
for(let contractVersion in recoveredSpvStates) {
|
|
2028
|
+
const { spvVaultContract } = versionedContracts[contractVersion];
|
|
2029
|
+
const spvVaultData = recoveredSpvStates[contractVersion];
|
|
2030
|
+
|
|
1953
2031
|
const vaultsData = await spvVaultContract.getMultipleVaultData(
|
|
1954
|
-
Object.keys(spvVaultData
|
|
2032
|
+
Object.keys(spvVaultData)
|
|
1955
2033
|
.map(btcTxId => ({
|
|
1956
|
-
owner: spvVaultData
|
|
1957
|
-
vaultId: spvVaultData
|
|
2034
|
+
owner: spvVaultData[btcTxId].owner,
|
|
2035
|
+
vaultId: spvVaultData[btcTxId].vaultId
|
|
1958
2036
|
}))
|
|
1959
2037
|
);
|
|
1960
2038
|
|
|
1961
|
-
for(let btcTxId in spvVaultData
|
|
1962
|
-
const state = spvVaultData
|
|
2039
|
+
for(let btcTxId in spvVaultData) {
|
|
2040
|
+
const state = spvVaultData[btcTxId];
|
|
1963
2041
|
const knownSwap = knownSwaps[btcTxId];
|
|
1964
2042
|
|
|
1965
2043
|
if(knownSwap!=null) {
|
|
@@ -1981,6 +2059,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
|
|
|
1981
2059
|
);
|
|
1982
2060
|
const swap = await wrappers[SwapType.SPV_VAULT_FROM_BTC].recoverFromState(
|
|
1983
2061
|
state,
|
|
2062
|
+
contractVersion,
|
|
1984
2063
|
vaultsData[state.owner]?.[state.vaultId.toString(10)],
|
|
1985
2064
|
lp
|
|
1986
2065
|
);
|
|
@@ -404,7 +404,9 @@ export class SwapperUtils<T extends MultiChain> {
|
|
|
404
404
|
feeRate?: any
|
|
405
405
|
}): Promise<TokenAmount> {
|
|
406
406
|
if(this.root._chains[token.chainId]==null) throw new Error("Invalid chain identifier! Unknown chain: "+token.chainId);
|
|
407
|
-
const {
|
|
407
|
+
const {defaultVersion, versionedContracts, chainInterface} = this.root._chains[token.chainId];
|
|
408
|
+
|
|
409
|
+
const {swapContract} = versionedContracts[defaultVersion];
|
|
408
410
|
|
|
409
411
|
let signer: string;
|
|
410
412
|
if(typeof(wallet)==="string") {
|
package/src/swaps/ISwap.ts
CHANGED
|
@@ -25,7 +25,8 @@ export type ISwapInit = {
|
|
|
25
25
|
expiry: number,
|
|
26
26
|
swapFee: bigint,
|
|
27
27
|
swapFeeBtc: bigint,
|
|
28
|
-
exactIn: boolean
|
|
28
|
+
exactIn: boolean,
|
|
29
|
+
contractVersion: string
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -140,6 +141,10 @@ export abstract class ISwap<
|
|
|
140
141
|
* @internal
|
|
141
142
|
*/
|
|
142
143
|
_persisted: boolean = false;
|
|
144
|
+
/**
|
|
145
|
+
* @internal
|
|
146
|
+
*/
|
|
147
|
+
_contractVersion?: string;
|
|
143
148
|
|
|
144
149
|
|
|
145
150
|
/**
|
|
@@ -181,6 +186,7 @@ export abstract class ISwap<
|
|
|
181
186
|
this.version = this.currentVersion;
|
|
182
187
|
this.createdAt = Date.now();
|
|
183
188
|
this._randomNonce = randomBytes(16).toString("hex");
|
|
189
|
+
this._contractVersion = swapInitOrObj.contractVersion;
|
|
184
190
|
} else {
|
|
185
191
|
this.expiry = swapInitOrObj.expiry;
|
|
186
192
|
this.url = swapInitOrObj.url;
|
|
@@ -211,6 +217,7 @@ export abstract class ISwap<
|
|
|
211
217
|
this.createdAt = swapInitOrObj.createdAt ?? swapInitOrObj.expiry;
|
|
212
218
|
|
|
213
219
|
this._randomNonce = swapInitOrObj.randomNonce;
|
|
220
|
+
this._contractVersion = swapInitOrObj.contractVersion;
|
|
214
221
|
}
|
|
215
222
|
if(this.version!==this.currentVersion) {
|
|
216
223
|
this.upgradeVersion();
|
|
@@ -637,7 +644,8 @@ export abstract class ISwap<
|
|
|
637
644
|
initiated: this.initiated,
|
|
638
645
|
exactIn: this.exactIn,
|
|
639
646
|
createdAt: this.createdAt,
|
|
640
|
-
randomNonce: this._randomNonce
|
|
647
|
+
randomNonce: this._randomNonce,
|
|
648
|
+
contractVersion: this._contractVersion
|
|
641
649
|
}
|
|
642
650
|
}
|
|
643
651
|
|
|
@@ -89,7 +89,7 @@ export abstract class IEscrowSelfInitSwap<
|
|
|
89
89
|
while(!expired) {
|
|
90
90
|
await timeoutPromise(intervalSeconds*1000, abortSignal);
|
|
91
91
|
try {
|
|
92
|
-
expired = await this.
|
|
92
|
+
expired = await this._contract.isInitAuthorizationExpired(this._data, this.signatureData);
|
|
93
93
|
} catch (e) {
|
|
94
94
|
this.logger.error("watchdogWaitTillSignatureExpiry(): Error when checking signature expiry: ", e);
|
|
95
95
|
}
|
|
@@ -106,14 +106,14 @@ export abstract class IEscrowSelfInitSwap<
|
|
|
106
106
|
* @internal
|
|
107
107
|
*/
|
|
108
108
|
protected getCommitFee(): Promise<bigint> {
|
|
109
|
-
return this.
|
|
109
|
+
return this._contract.getCommitFee(this._getInitiator(), this.getSwapData(), this.feeRate);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* Returns the transaction fee paid on the smart chain side to initiate the escrow
|
|
114
114
|
*/
|
|
115
115
|
async getSmartChainNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>> {
|
|
116
|
-
const swapContract: T["Contract"] = this.
|
|
116
|
+
const swapContract: T["Contract"] = this._contract;
|
|
117
117
|
return toTokenAmount(
|
|
118
118
|
await (
|
|
119
119
|
swapContract.getRawCommitFee!=null ?
|
|
@@ -178,7 +178,7 @@ export abstract class IEscrowSelfInitSwap<
|
|
|
178
178
|
async _verifyQuoteDefinitelyExpired(): Promise<boolean> {
|
|
179
179
|
if(this._data==null || this.signatureData==null) throw new Error("data or signature data are null!");
|
|
180
180
|
|
|
181
|
-
return this.
|
|
181
|
+
return this._contract.isInitAuthorizationExpired(
|
|
182
182
|
this._data!, this.signatureData!
|
|
183
183
|
);
|
|
184
184
|
}
|
|
@@ -190,7 +190,7 @@ export abstract class IEscrowSelfInitSwap<
|
|
|
190
190
|
if(this._data==null || this.signatureData==null) throw new Error("data or signature data are null!");
|
|
191
191
|
|
|
192
192
|
try {
|
|
193
|
-
await this.
|
|
193
|
+
await this._contract.isValidInitAuthorization(
|
|
194
194
|
this._getInitiator(), this._data!, this.signatureData!, this.feeRate
|
|
195
195
|
);
|
|
196
196
|
return true;
|
|
@@ -50,6 +50,11 @@ export abstract class IEscrowSwap<
|
|
|
50
50
|
*/
|
|
51
51
|
_claimTxId?: string;
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
protected _contract: T["Contract"];
|
|
57
|
+
|
|
53
58
|
protected constructor(wrapper: D["Wrapper"], obj: any);
|
|
54
59
|
protected constructor(wrapper: D["Wrapper"], swapInit: IEscrowSwapInit<T["Data"]>);
|
|
55
60
|
protected constructor(
|
|
@@ -61,12 +66,14 @@ export abstract class IEscrowSwap<
|
|
|
61
66
|
if(isIEscrowSwapInit(swapInitOrObj)) {
|
|
62
67
|
this._data = swapInitOrObj.data;
|
|
63
68
|
} else {
|
|
64
|
-
if(swapInitOrObj.data!=null) this._data = new wrapper._swapDataDeserializer(swapInitOrObj.data);
|
|
69
|
+
if(swapInitOrObj.data!=null) this._data = new (wrapper._swapDataDeserializer(this._contractVersion))(swapInitOrObj.data);
|
|
65
70
|
|
|
66
71
|
this._commitTxId = swapInitOrObj.commitTxId;
|
|
67
72
|
this._claimTxId = swapInitOrObj.claimTxId;
|
|
68
73
|
this._refundTxId = swapInitOrObj.refundTxId;
|
|
69
74
|
}
|
|
75
|
+
|
|
76
|
+
this._contract = wrapper._contract(this._contractVersion);
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
/**
|
|
@@ -170,7 +177,7 @@ export abstract class IEscrowSwap<
|
|
|
170
177
|
while(status?.type===SwapCommitStateType.NOT_COMMITED) {
|
|
171
178
|
await timeoutPromise(intervalSeconds*1000, abortSignal);
|
|
172
179
|
try {
|
|
173
|
-
status = await this.
|
|
180
|
+
status = await this._contract.getCommitStatus(this._getInitiator(), this._data);
|
|
174
181
|
if(
|
|
175
182
|
status?.type===SwapCommitStateType.NOT_COMMITED &&
|
|
176
183
|
await this._verifyQuoteDefinitelyExpired()
|
|
@@ -200,7 +207,7 @@ export abstract class IEscrowSwap<
|
|
|
200
207
|
while(status?.type===SwapCommitStateType.COMMITED || status?.type===SwapCommitStateType.REFUNDABLE) {
|
|
201
208
|
await timeoutPromise(intervalSeconds*1000, abortSignal);
|
|
202
209
|
try {
|
|
203
|
-
status = await this.
|
|
210
|
+
status = await this._contract.getCommitStatus(this._getInitiator(), this._data);
|
|
204
211
|
} catch (e) {
|
|
205
212
|
this.logger.error("watchdogWaitTillResult(): Error when fetching commit status: ", e);
|
|
206
213
|
}
|