@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.
Files changed (61) hide show
  1. package/dist/http/paramcoders/ParamDecoder.js +9 -4
  2. package/dist/http/paramcoders/ParamEncoder.js +6 -1
  3. package/dist/intermediaries/IntermediaryDiscovery.js +4 -3
  4. package/dist/storage/UnifiedSwapStorage.js +13 -8
  5. package/dist/swapper/Swapper.d.ts +1 -12
  6. package/dist/swapper/Swapper.js +31 -28
  7. package/dist/swapper/SwapperFactory.d.ts +1 -0
  8. package/dist/swapper/SwapperFactory.js +9 -4
  9. package/dist/swaps/ISwap.d.ts +8 -0
  10. package/dist/swaps/ISwap.js +8 -0
  11. package/dist/swaps/ISwapWrapper.d.ts +23 -1
  12. package/dist/swaps/ISwapWrapper.js +88 -28
  13. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +4 -1
  14. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +2 -2
  15. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +1 -1
  16. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +2 -2
  17. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +16 -6
  18. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +8 -2
  19. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +1 -1
  20. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +14 -4
  21. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +8 -6
  22. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +2 -1
  23. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +7 -5
  24. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +8 -2
  25. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +1 -1
  26. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +0 -6
  27. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +8 -3
  28. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +8 -2
  29. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +1 -0
  30. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +3 -2
  31. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +1 -3
  32. package/dist/swaps/trusted/ln/LnForGasWrapper.js +0 -1
  33. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +0 -1
  34. package/dist/utils/RetryUtils.d.ts +2 -1
  35. package/dist/utils/RetryUtils.js +3 -2
  36. package/package.json +1 -1
  37. package/src/http/paramcoders/ParamDecoder.ts +8 -4
  38. package/src/http/paramcoders/ParamEncoder.ts +5 -1
  39. package/src/intermediaries/IntermediaryDiscovery.ts +6 -4
  40. package/src/storage/UnifiedSwapStorage.ts +13 -8
  41. package/src/swapper/Swapper.ts +35 -28
  42. package/src/swapper/SwapperFactory.ts +12 -6
  43. package/src/swaps/ISwap.ts +8 -0
  44. package/src/swaps/ISwapWrapper.ts +104 -28
  45. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +5 -1
  46. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +3 -3
  47. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +17 -8
  48. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +8 -3
  49. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +13 -5
  50. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +8 -7
  51. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +9 -5
  52. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +7 -2
  53. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +1 -1
  54. package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +0 -3
  55. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +7 -3
  56. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +7 -2
  57. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +5 -2
  58. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +1 -3
  59. package/src/swaps/trusted/ln/LnForGasWrapper.ts +0 -1
  60. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +0 -1
  61. package/src/utils/RetryUtils.ts +11 -4
@@ -601,6 +601,7 @@ export declare class SpvFromBTCSwap<T extends ChainType> extends ISwap<T, SpvFro
601
601
  * @internal
602
602
  */
603
603
  _setBitcoinTxId(txId: string): Promise<void>;
604
+ private btcTxLastChecked?;
604
605
  /**
605
606
  * @internal
606
607
  */
@@ -227,7 +227,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
227
227
  */
228
228
  upgradeVersion() {
229
229
  if (this.version === 1) {
230
- this.posted = this.initiated;
230
+ this.posted = this.initiated && this._data != null;
231
231
  this.version = 2;
232
232
  }
233
233
  }
@@ -1244,6 +1244,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
1244
1244
  if (this._data?.btcTx == null)
1245
1245
  return false;
1246
1246
  //Check if bitcoin payment was confirmed
1247
+ this.btcTxLastChecked = Date.now();
1247
1248
  const res = await this.getBitcoinPayment();
1248
1249
  if (res == null) {
1249
1250
  //Check inputs double-spent
@@ -1379,7 +1380,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
1379
1380
  return true;
1380
1381
  }
1381
1382
  }
1382
- if (Math.floor(Date.now() / 1000) % 120 === 0) {
1383
+ if (this.btcTxLastChecked == null || Date.now() - this.btcTxLastChecked > 120000) {
1383
1384
  if (this._state === SpvFromBTCSwapState.POSTED ||
1384
1385
  this._state === SpvFromBTCSwapState.BROADCASTED) {
1385
1386
  try {
@@ -39,6 +39,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
39
39
  */
40
40
  constructor(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, spvWithdrawalDataDeserializer, btcRelay, synchronizer, btcRpc, options, events) {
41
41
  super(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, {
42
+ ...options,
42
43
  bitcoinNetwork: options?.bitcoinNetwork ?? utils_1.TEST_NETWORK,
43
44
  maxConfirmations: options?.maxConfirmations ?? 6,
44
45
  bitcoinBlocktime: options?.bitcoinBlocktime ?? 10 * 60,
@@ -89,7 +90,6 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
89
90
  swap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.BROADCASTED || swap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.DECLINED ||
90
91
  swap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED || swap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
91
92
  swap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.FRONTED;
92
- swap._frontTxId = event.meta?.txId;
93
93
  await swap._setBitcoinTxId(event.btcTxId).catch(e => {
94
94
  this.logger.warn("processEventFront(): Failed to set bitcoin txId: ", e);
95
95
  });
@@ -103,7 +103,6 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
103
103
  swap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED || swap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.FRONTED ||
104
104
  swap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
105
105
  swap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.CLAIMED;
106
- swap._claimTxId = event.meta?.txId;
107
106
  await swap._setBitcoinTxId(event.btcTxId).catch(e => {
108
107
  this.logger.warn("processEventClaim(): Failed to set bitcoin txId: ", e);
109
108
  });
@@ -506,7 +505,6 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
506
505
  genesisSmartChainBlockHeight: await (0, Utils_1.throwIfUndefined)(finalizedBlockHeightPrefetchPromise, "Finalize block height promise failed!")
507
506
  };
508
507
  const quote = new SpvFromBTCSwap_1.SpvFromBTCSwap(this, swapInit);
509
- await quote._save();
510
508
  return quote;
511
509
  }
512
510
  catch (e) {
@@ -76,7 +76,6 @@ class LnForGasWrapper extends ISwapWrapper_1.ISwapWrapper {
76
76
  exactIn: false
77
77
  };
78
78
  const quote = new LnForGasSwap_1.LnForGasSwap(this, quoteInit);
79
- await quote._save();
80
79
  return quote;
81
80
  }
82
81
  }
@@ -86,7 +86,6 @@ class OnchainForGasWrapper extends ISwapWrapper_1.ISwapWrapper {
86
86
  exactIn: false,
87
87
  token
88
88
  });
89
- await quote._save();
90
89
  return quote;
91
90
  }
92
91
  }
@@ -10,6 +10,7 @@ type Constructor<T = any> = new (...args: any[]) => T;
10
10
  * @param retryPolicy.exponential Whether to use exponentially increasing delays
11
11
  * @param errorAllowed A callback for determining whether a given error is allowed, and we should therefore not retry
12
12
  * @param abortSignal
13
+ * @param failureLogLevel
13
14
  * @returns Result of the action executing callback
14
15
  * @category Utilities
15
16
  */
@@ -17,5 +18,5 @@ export declare function tryWithRetries<T>(func: (retryCount: number) => Promise<
17
18
  maxRetries?: number;
18
19
  delay?: number;
19
20
  exponential?: boolean;
20
- }, errorAllowed?: ((e: any) => boolean) | Constructor<Error> | Constructor<Error>[], abortSignal?: AbortSignal): Promise<T>;
21
+ }, errorAllowed?: ((e: any) => boolean) | Constructor<Error> | Constructor<Error>[], abortSignal?: AbortSignal, failureLogLevel?: "debug" | "info" | "warn" | "error"): Promise<T>;
21
22
  export {};
@@ -36,10 +36,11 @@ function checkError(e, errorAllowed) {
36
36
  * @param retryPolicy.exponential Whether to use exponentially increasing delays
37
37
  * @param errorAllowed A callback for determining whether a given error is allowed, and we should therefore not retry
38
38
  * @param abortSignal
39
+ * @param failureLogLevel
39
40
  * @returns Result of the action executing callback
40
41
  * @category Utilities
41
42
  */
42
- async function tryWithRetries(func, retryPolicy, errorAllowed, abortSignal) {
43
+ async function tryWithRetries(func, retryPolicy, errorAllowed, abortSignal, failureLogLevel = "warn") {
43
44
  retryPolicy = retryPolicy || {};
44
45
  retryPolicy.maxRetries = retryPolicy.maxRetries || 5;
45
46
  retryPolicy.delay = retryPolicy.delay || 500;
@@ -53,7 +54,7 @@ async function tryWithRetries(func, retryPolicy, errorAllowed, abortSignal) {
53
54
  if (errorAllowed != null && checkError(e, errorAllowed))
54
55
  throw e;
55
56
  err = e;
56
- logger.debug("tryWithRetries(): Error on try number: " + i, e);
57
+ logger[failureLogLevel]("tryWithRetries(): Error on try number: " + i, e);
57
58
  }
58
59
  if (abortSignal != null && abortSignal.aborted)
59
60
  throw (abortSignal.reason || new Error("Aborted"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/sdk",
3
- "version": "8.6.0",
3
+ "version": "8.6.3",
4
4
  "description": "atomiq labs SDK for cross-chain swaps between smart chains and bitcoin",
5
5
  "main": "./dist/index.js",
6
6
  "types:": "./dist/index.d.ts",
@@ -1,6 +1,10 @@
1
1
  import {IParamReader} from "./IParamReader";
2
2
  import {Buffer} from "buffer";
3
3
 
4
+ function ensureBuffer(input: any): Buffer {
5
+ if(input instanceof Buffer) return input;
6
+ return Buffer.from(input);
7
+ }
4
8
 
5
9
  export class ParamDecoder implements IParamReader {
6
10
 
@@ -56,8 +60,8 @@ export class ParamDecoder implements IParamReader {
56
60
  this.frameHeader = leavesBuffer;
57
61
  leavesBuffer = null;
58
62
  } else {
59
- this.frameHeader = leavesBuffer.subarray(0, 4);
60
- leavesBuffer = leavesBuffer.subarray(4);
63
+ this.frameHeader = ensureBuffer(leavesBuffer.subarray(0, 4));
64
+ leavesBuffer = ensureBuffer(leavesBuffer.subarray(4));
61
65
  }
62
66
  } else if(this.frameHeader.length<4) {
63
67
  const requiredLen = 4-this.frameHeader.length;
@@ -66,13 +70,13 @@ export class ParamDecoder implements IParamReader {
66
70
  leavesBuffer = null;
67
71
  } else {
68
72
  this.frameHeader = Buffer.concat([this.frameHeader, leavesBuffer.subarray(0, requiredLen)]);
69
- leavesBuffer = leavesBuffer.subarray(requiredLen);
73
+ leavesBuffer = ensureBuffer(leavesBuffer.subarray(requiredLen));
70
74
  }
71
75
  }
72
76
  if(leavesBuffer==null) continue;
73
77
  if(this.frameHeader==null || this.frameHeader.length<4) continue;
74
78
 
75
- const frameLength = this.frameHeader.readUint32LE();
79
+ const frameLength = this.frameHeader.readUint32LE!=null ? this.frameHeader.readUint32LE() : this.frameHeader.readUInt32LE();
76
80
  const requiredLen = frameLength-this.frameDataLength;
77
81
 
78
82
  if(leavesBuffer.length<=requiredLen) {
@@ -19,7 +19,11 @@ export class ParamEncoder {
19
19
  const serialized: Buffer = Buffer.from(JSON.stringify(data));
20
20
 
21
21
  const frameLengthBuffer = Buffer.alloc(4);
22
- frameLengthBuffer.writeUint32LE(serialized.length);
22
+ if(frameLengthBuffer.writeUint32LE!=null) {
23
+ frameLengthBuffer.writeUint32LE(serialized.length);
24
+ } else {
25
+ frameLengthBuffer.writeUInt32LE(serialized.length);
26
+ }
23
27
 
24
28
  return this.writeFN(Buffer.concat([
25
29
  frameLengthBuffer,
@@ -241,7 +241,8 @@ export class IntermediaryDiscovery extends EventEmitter {
241
241
  () => IntermediaryAPI.getIntermediaryInfo(url, this.httpRequestTimeout, abortSignal),
242
242
  {maxRetries: 3, delay: 100, exponential: true},
243
243
  undefined,
244
- abortSignal
244
+ abortSignal,
245
+ "debug"
245
246
  );
246
247
  abortSignal?.throwIfAborted();
247
248
 
@@ -255,7 +256,7 @@ export class IntermediaryDiscovery extends EventEmitter {
255
256
  await this.swapContracts[chain].isValidDataSignature(Buffer.from(response.envelope), signature, address);
256
257
  addresses[chain] = address;
257
258
  } catch (e) {
258
- logger.warn("Failed to verify "+chain+" signature for intermediary: "+url);
259
+ logger.warn("getNodeInfo(): Failed to verify "+chain+" signature for intermediary: "+url);
259
260
  }
260
261
  })());
261
262
  }
@@ -303,8 +304,9 @@ export class IntermediaryDiscovery extends EventEmitter {
303
304
  services[swapHandlerTypeToSwapType(key as SwapHandlerType)] = nodeInfo.info.services[key as SwapHandlerType];
304
305
  }
305
306
  return new Intermediary(url, nodeInfo.addresses, services);
306
- } catch (e) {
307
- logger.warn("fetchIntermediaries(): Error contacting intermediary "+url+": ", e);
307
+ } catch (e: any) {
308
+ logger.warn("fetchIntermediaries(): Intermediary "+url+` is unreachable due to ${e.name ?? e.message} error, skipping...`);
309
+ logger.debug("fetchIntermediaries(): Error contacting intermediary "+url+": ", e);
308
310
  return null;
309
311
  }
310
312
  }
@@ -89,6 +89,7 @@ export class UnifiedSwapStorage<T extends ChainType> {
89
89
  }
90
90
  const value = reviver(rawObj);
91
91
  if(value==null) return;
92
+ value._persisted = true;
92
93
  if(!this.noWeakRefMap) this.weakRefCache.set(rawObj.id, new WeakRef<ISwap<T>>(value));
93
94
  result.push(value);
94
95
  });
@@ -101,36 +102,40 @@ export class UnifiedSwapStorage<T extends ChainType> {
101
102
  *
102
103
  * @param value Swap to save
103
104
  */
104
- save<S extends ISwap<T>>(value: S): Promise<void> {
105
+ async save<S extends ISwap<T>>(value: S): Promise<void> {
105
106
  if(!this.noWeakRefMap) this.weakRefCache.set(value.getId(), new WeakRef<ISwap<T>>(value));
106
- return this.storage.save(value.serialize());
107
+ await this.storage.save(value.serialize());
108
+ value._persisted = true;
107
109
  }
108
110
 
109
111
  /**
110
112
  * Saves multiple swaps to storage in a batch operation
111
113
  * @param values Array of swaps to save
112
114
  */
113
- saveAll<S extends ISwap<T>>(values: S[]): Promise<void> {
115
+ async saveAll<S extends ISwap<T>>(values: S[]): Promise<void> {
114
116
  if(!this.noWeakRefMap) values.forEach(value => this.weakRefCache.set(value.getId(), new WeakRef<ISwap<T>>(value)));
115
- return this.storage.saveAll(values.map(obj => obj.serialize()));
117
+ await this.storage.saveAll(values.map(obj => obj.serialize()));
118
+ values.forEach(value => value._persisted = true);
116
119
  }
117
120
 
118
121
  /**
119
122
  * Removes a swap from storage
120
123
  * @param value Swap to remove
121
124
  */
122
- remove<S extends ISwap<T>>(value: S): Promise<void> {
125
+ async remove<S extends ISwap<T>>(value: S): Promise<void> {
123
126
  if(!this.noWeakRefMap) this.weakRefCache.delete(value.getId());
124
- return this.storage.remove(value.serialize());
127
+ await this.storage.remove(value.serialize());
128
+ value._persisted = false;
125
129
  }
126
130
 
127
131
  /**
128
132
  * Removes multiple swaps from storage in a batch operation
129
133
  * @param values Array of swaps to remove
130
134
  */
131
- removeAll<S extends ISwap<T>>(values: S[]): Promise<void> {
135
+ async removeAll<S extends ISwap<T>>(values: S[]): Promise<void> {
132
136
  if(!this.noWeakRefMap) values.forEach(value => this.weakRefCache.delete(value.getId()));
133
- return this.storage.removeAll(values.map(obj => obj.serialize()));
137
+ await this.storage.removeAll(values.map(obj => obj.serialize()));
138
+ values.forEach(value => value._persisted = false);
134
139
  }
135
140
 
136
141
  }
@@ -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: SwapperCtorTokens<T>,
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
- for(let chainId in tokenData.chains) {
351
- const chainData = tokenData.chains[chainId]!;
352
- this._tokens[chainId] ??= {};
353
- this._tokensByTicker[chainId] ??= {};
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
  );
@@ -557,7 +553,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
557
553
  }
558
554
 
559
555
  private async _init(): Promise<void> {
560
- this.logger.debug("init(): Initializing swapper, sdk-lib version 16.1.3");
556
+ this.logger.debug("init(): Initializing swapper...");
561
557
 
562
558
  const abortController = new AbortController();
563
559
 
@@ -598,12 +594,19 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
598
594
  for(let chainIdentifier in this._chains) {
599
595
  chainPromises.push((async() => {
600
596
  const {
597
+ chainInterface,
601
598
  swapContract,
602
599
  unifiedChainEvents,
603
600
  unifiedSwapStorage,
604
601
  wrappers,
605
602
  reviver
606
603
  } = this._chains[chainIdentifier];
604
+
605
+ const _chainInterface: any = chainInterface;
606
+ if(_chainInterface.verifyNetwork!=null) {
607
+ await _chainInterface.verifyNetwork(this.bitcoinNetwork);
608
+ }
609
+
607
610
  await swapContract.start();
608
611
  this.logger.debug("init(): Intialized swap contract: "+chainIdentifier);
609
612
 
@@ -659,7 +662,10 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
659
662
  */
660
663
  async init(): Promise<void> {
661
664
  if(this.initialized) return;
662
- if(this.initPromise!=null) await this.initPromise;
665
+ if(this.initPromise!=null) {
666
+ await this.initPromise;
667
+ return;
668
+ }
663
669
 
664
670
  try {
665
671
  const promise = this._init();
@@ -856,10 +862,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
856
862
  if(swapLimitsChanged) this.emit("swapLimitsChanged");
857
863
 
858
864
  const quote = quotes[0].quote;
859
- if(this.options.saveUninitializedSwaps) {
860
- quote._setInitiated();
861
- await quote._save();
862
- }
865
+ await quote._save();
863
866
  return quote;
864
867
  } catch (e) {
865
868
  if(swapLimitsChanged) this.emit("swapLimitsChanged");
@@ -1334,13 +1337,15 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1334
1337
  * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
1335
1338
  * @throws {Error} If no trusted intermediary specified
1336
1339
  */
1337
- createTrustedLNForGasSwap<C extends ChainIds<T>>(chainIdentifier: C, recipient: string, amount: bigint, trustedIntermediaryOrUrl?: Intermediary | string): Promise<LnForGasSwap<T[C]>> {
1340
+ async createTrustedLNForGasSwap<C extends ChainIds<T>>(chainIdentifier: C, recipient: string, amount: bigint, trustedIntermediaryOrUrl?: Intermediary | string): Promise<LnForGasSwap<T[C]>> {
1338
1341
  if(this._chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
1339
1342
  if(!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true)) throw new Error("Invalid "+chainIdentifier+" address");
1340
1343
  recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
1341
1344
  const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
1342
1345
  if(useUrl==null) throw new Error("No trusted intermediary specified!");
1343
- return this._chains[chainIdentifier as C].wrappers[SwapType.TRUSTED_FROM_BTCLN].create(recipient, amount, useUrl);
1346
+ const swap = await this._chains[chainIdentifier as C].wrappers[SwapType.TRUSTED_FROM_BTCLN].create(recipient, amount, useUrl);
1347
+ await swap._save();
1348
+ return swap;
1344
1349
  }
1345
1350
 
1346
1351
  /**
@@ -1353,7 +1358,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1353
1358
  * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
1354
1359
  * @throws {Error} If no trusted intermediary specified
1355
1360
  */
1356
- createTrustedOnchainForGasSwap<C extends ChainIds<T>>(
1361
+ async createTrustedOnchainForGasSwap<C extends ChainIds<T>>(
1357
1362
  chainIdentifier: C, recipient: string,
1358
1363
  amount: bigint, refundAddress?: string,
1359
1364
  trustedIntermediaryOrUrl?: Intermediary | string
@@ -1363,7 +1368,9 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1363
1368
  recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
1364
1369
  const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
1365
1370
  if(useUrl==null) throw new Error("No trusted intermediary specified!");
1366
- return this._chains[chainIdentifier as C].wrappers[SwapType.TRUSTED_FROM_BTC].create(recipient, amount, useUrl, refundAddress);
1371
+ const swap = await this._chains[chainIdentifier as C].wrappers[SwapType.TRUSTED_FROM_BTC].create(recipient, amount, useUrl, refundAddress);
1372
+ await swap._save();
1373
+ return swap;
1367
1374
  }
1368
1375
 
1369
1376
  /**
@@ -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
- tokens[ticker] = addressMap[assetData.address] = {
205
+ const token: SCToken = {
204
206
  chain: "SC",
205
207
  chainId: initializer.chainId,
206
- address: assetData.address,
208
+ ticker,
207
209
  name: SmartChainAssets[ticker as SmartChainAssetTickers]?.name ?? ticker,
208
210
  decimals: assetData.decimals,
209
211
  displayDecimals: assetData.displayDecimals,
210
- ticker
211
- } as any;
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
- pricingAssets,
289
+ this.smartChainTokens,
284
290
  options.messenger,
285
291
  options
286
292
  );
@@ -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
  /**