@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.
Files changed (85) hide show
  1. package/dist/events/UnifiedSwapEventListener.js +4 -2
  2. package/dist/http/paramcoders/ParamDecoder.js +9 -4
  3. package/dist/http/paramcoders/ParamEncoder.js +6 -1
  4. package/dist/intermediaries/Intermediary.d.ts +21 -0
  5. package/dist/intermediaries/Intermediary.js +25 -1
  6. package/dist/intermediaries/IntermediaryDiscovery.d.ts +15 -3
  7. package/dist/intermediaries/IntermediaryDiscovery.js +25 -6
  8. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +1 -0
  9. package/dist/swapper/Swapper.d.ts +9 -4
  10. package/dist/swapper/Swapper.js +94 -42
  11. package/dist/swapper/SwapperUtils.js +2 -1
  12. package/dist/swaps/ISwap.d.ts +5 -0
  13. package/dist/swaps/ISwap.js +4 -1
  14. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +5 -5
  15. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +4 -0
  16. package/dist/swaps/escrow_swaps/IEscrowSwap.js +4 -3
  17. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +19 -6
  18. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +54 -21
  19. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +7 -3
  20. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +3 -4
  21. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +3 -3
  22. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +8 -2
  23. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +12 -8
  24. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +18 -18
  25. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +12 -6
  26. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +38 -24
  27. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +9 -9
  28. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +14 -7
  29. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +54 -38
  30. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +5 -5
  31. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +18 -7
  32. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +61 -33
  33. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +12 -12
  34. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +8 -2
  35. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +13 -8
  36. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +1 -1
  37. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +13 -4
  38. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +44 -28
  39. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +2 -2
  40. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +8 -4
  41. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +29 -21
  42. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +1 -0
  43. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +13 -12
  44. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +21 -10
  45. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +136 -73
  46. package/dist/swaps/trusted/ln/LnForGasWrapper.js +2 -1
  47. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +2 -1
  48. package/dist/utils/RetryUtils.d.ts +2 -1
  49. package/dist/utils/RetryUtils.js +3 -2
  50. package/dist/utils/Utils.d.ts +9 -0
  51. package/dist/utils/Utils.js +15 -1
  52. package/package.json +2 -2
  53. package/src/events/UnifiedSwapEventListener.ts +4 -2
  54. package/src/http/paramcoders/ParamDecoder.ts +8 -4
  55. package/src/http/paramcoders/ParamEncoder.ts +5 -1
  56. package/src/intermediaries/Intermediary.ts +31 -1
  57. package/src/intermediaries/IntermediaryDiscovery.ts +33 -12
  58. package/src/intermediaries/apis/IntermediaryAPI.ts +2 -1
  59. package/src/swapper/Swapper.ts +141 -62
  60. package/src/swapper/SwapperUtils.ts +3 -1
  61. package/src/swaps/ISwap.ts +10 -2
  62. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +5 -5
  63. package/src/swaps/escrow_swaps/IEscrowSwap.ts +10 -3
  64. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +64 -26
  65. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +8 -5
  66. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +3 -3
  67. package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +22 -12
  68. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +18 -18
  69. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +52 -31
  70. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +9 -9
  71. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +76 -52
  72. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +5 -5
  73. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +82 -38
  74. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +12 -12
  75. package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +21 -9
  76. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +1 -1
  77. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +56 -33
  78. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +2 -2
  79. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +40 -22
  80. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +17 -13
  81. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +149 -83
  82. package/src/swaps/trusted/ln/LnForGasWrapper.ts +2 -1
  83. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +2 -1
  84. package/src/utils/RetryUtils.ts +11 -4
  85. package/src/utils/Utils.ts +14 -0
@@ -21,7 +21,7 @@ import {UnifiedSwapEventListener} from "../../events/UnifiedSwapEventListener";
21
21
  import {ISwapPrice} from "../../prices/abstract/ISwapPrice";
22
22
  import {EventEmitter} from "events";
23
23
  import {Intermediary} from "../../intermediaries/Intermediary";
24
- import {extendAbortController, randomBytes, throwIfUndefined} from "../../utils/Utils";
24
+ import {extendAbortController, mapArrayToObject, randomBytes, throwIfUndefined} from "../../utils/Utils";
25
25
  import {fromOutputScript, toCoinselectAddressType, toOutputScript} from "../../utils/BitcoinUtils";
26
26
  import {IntermediaryAPI, SpvFromBTCPrepareResponseType} from "../../intermediaries/apis/IntermediaryAPI";
27
27
  import {RequestError} from "../../errors/RequestError";
@@ -111,7 +111,12 @@ export class SpvFromBTCWrapper<
111
111
  /**
112
112
  * @internal
113
113
  */
114
- protected readonly btcRelay: T["BtcRelay"];
114
+ protected readonly btcRelay: (version?: string) => BtcRelay<any, T["TX"], any> = (version?: string) => {
115
+ const _version = version ?? "v1";
116
+ const data = this.versionedContracts[_version];
117
+ if(data==null) throw new Error(`Invalid contract version ${_version} requested`);
118
+ return data.btcRelay;
119
+ };
115
120
  /**
116
121
  * @internal
117
122
  */
@@ -127,11 +132,21 @@ export class SpvFromBTCWrapper<
127
132
  /**
128
133
  * @internal
129
134
  */
130
- readonly _synchronizer: RelaySynchronizer<any, T["TX"], any>;
135
+ readonly _synchronizer: (version?: string) => RelaySynchronizer<any, T["TX"], any> = (version?: string) => {
136
+ const _version = version ?? "v1";
137
+ const data = this.versionedSynchronizer[_version];
138
+ if(data==null) throw new Error(`Invalid contract version ${_version} requested`);
139
+ return data.synchronizer;
140
+ };
131
141
  /**
132
142
  * @internal
133
143
  */
134
- readonly _contract: T["SpvVaultContract"];
144
+ readonly _contract: (version?: string) => T["SpvVaultContract"] = (version?: string) => {
145
+ const _version = version ?? "v1";
146
+ const data = this.versionedContracts[_version];
147
+ if(data==null) throw new Error(`Invalid contract version ${_version} requested`);
148
+ return data.spvVaultContract;
149
+ };
135
150
  /**
136
151
  * @internal
137
152
  */
@@ -139,7 +154,13 @@ export class SpvFromBTCWrapper<
139
154
  /**
140
155
  * @internal
141
156
  */
142
- readonly _spvWithdrawalDataDeserializer: new (data: any) => T["SpvVaultWithdrawalData"];
157
+ readonly _spvWithdrawalDataDeserializer: (version?: string) => (new (data: any) => T["SpvVaultWithdrawalData"]) = (version?: string) => {
158
+ const _version = version ?? "v1";
159
+ const data = this.versionedContracts[_version];
160
+ if(data==null) throw new Error(`Invalid contract version ${_version} requested`);
161
+ return data.spvVaultWithdrawalDataConstructor;
162
+ };
163
+
143
164
  /**
144
165
  * @internal
145
166
  */
@@ -153,17 +174,29 @@ export class SpvFromBTCWrapper<
153
174
  SpvFromBTCSwapState.BTC_TX_CONFIRMED
154
175
  ];
155
176
 
177
+ private readonly versionedContracts: {
178
+ [version: string]: {
179
+ btcRelay: BtcRelay<any, T["TX"], any>,
180
+ spvVaultContract: T["SpvVaultContract"],
181
+ spvVaultWithdrawalDataConstructor: new (data: any) => T["SpvVaultWithdrawalData"]
182
+ }
183
+ } = {};
184
+
185
+ private readonly versionedSynchronizer: {
186
+ [version: string]: {
187
+ synchronizer: RelaySynchronizer<any, T["TX"], any>
188
+ }
189
+ } = {};
190
+
156
191
  /**
157
192
  * @param chainIdentifier
158
193
  * @param unifiedStorage Storage interface for the current environment
159
194
  * @param unifiedChainEvents On-chain event listener
160
195
  * @param chain
161
- * @param contract Underlying contract handling the swaps
162
196
  * @param prices Pricing to use
163
197
  * @param tokens
164
- * @param spvWithdrawalDataDeserializer Deserializer for SpvVaultWithdrawalData
165
- * @param btcRelay
166
- * @param synchronizer Btc relay synchronizer
198
+ * @param versionedContracts
199
+ * @param versionedSynchronizer
167
200
  * @param btcRpc Bitcoin RPC which also supports getting transactions by txoHash
168
201
  * @param options
169
202
  * @param events Instance to use for emitting events
@@ -173,12 +206,20 @@ export class SpvFromBTCWrapper<
173
206
  unifiedStorage: UnifiedSwapStorage<T>,
174
207
  unifiedChainEvents: UnifiedSwapEventListener<T>,
175
208
  chain: T["ChainInterface"],
176
- contract: T["SpvVaultContract"],
177
209
  prices: ISwapPrice,
178
210
  tokens: WrapperCtorTokens,
179
- spvWithdrawalDataDeserializer: new (data: any) => T["SpvVaultWithdrawalData"],
180
- btcRelay: BtcRelay<any, T["TX"], any>,
181
- synchronizer: RelaySynchronizer<any, T["TX"], any>,
211
+ versionedContracts: {
212
+ [version: string]: {
213
+ btcRelay: BtcRelay<any, T["TX"], any>,
214
+ spvVaultContract: T["SpvVaultContract"],
215
+ spvVaultWithdrawalDataConstructor: new (data: any) => T["SpvVaultWithdrawalData"]
216
+ }
217
+ },
218
+ versionedSynchronizer: {
219
+ [version: string]: {
220
+ synchronizer: RelaySynchronizer<any, T["TX"], any>
221
+ }
222
+ },
182
223
  btcRpc: BitcoinRpcWithAddressIndex<any>,
183
224
  options?: AllOptional<SpvFromBTCWrapperOptions>,
184
225
  events?: EventEmitter<{swapState: [ISwap]}>
@@ -197,10 +238,8 @@ export class SpvFromBTCWrapper<
197
238
  },
198
239
  events
199
240
  );
200
- this._spvWithdrawalDataDeserializer = spvWithdrawalDataDeserializer;
201
- this._contract = contract;
202
- this.btcRelay = btcRelay;
203
- this._synchronizer = synchronizer;
241
+ this.versionedContracts = versionedContracts;
242
+ this.versionedSynchronizer = versionedSynchronizer;
204
243
  this._btcRpc = btcRpc;
205
244
  }
206
245
 
@@ -304,6 +343,7 @@ export class SpvFromBTCWrapper<
304
343
  * @param pricePrefetch
305
344
  * @param nativeTokenPricePrefetch
306
345
  * @param abortController
346
+ * @param contractVersion
307
347
  * @private
308
348
  */
309
349
  private async preFetchCallerFeeShare(
@@ -314,7 +354,8 @@ export class SpvFromBTCWrapper<
314
354
  },
315
355
  pricePrefetch: Promise<bigint | undefined>,
316
356
  nativeTokenPricePrefetch: Promise<bigint | undefined> | undefined,
317
- abortController: AbortController
357
+ abortController: AbortController,
358
+ contractVersion: string
318
359
  ): Promise<bigint | undefined> {
319
360
  if(options.unsafeZeroWatchtowerFee) return 0n;
320
361
  if(amountData.amount===0n) return 0n;
@@ -327,10 +368,10 @@ export class SpvFromBTCWrapper<
327
368
  claimFeeRate,
328
369
  nativeTokenPrice
329
370
  ] = await Promise.all([
330
- this.btcRelay.getFeePerBlock(),
331
- this.btcRelay.getTipData(),
371
+ this.btcRelay(contractVersion).getFeePerBlock(),
372
+ this.btcRelay(contractVersion).getTipData(),
332
373
  this._btcRpc.getTipHeight(),
333
- this._contract.getClaimFee(this._chain.randomAddress()),
374
+ this._contract(contractVersion).getClaimFee(this._chain.randomAddress()),
334
375
  nativeTokenPricePrefetch ?? (amountData.token===this._chain.getNativeCurrencyAddress() ?
335
376
  pricePrefetch :
336
377
  this._prices.preFetchPrice(this.chainIdentifier, this._chain.getNativeCurrencyAddress(), abortController.signal))
@@ -405,6 +446,8 @@ export class SpvFromBTCWrapper<
405
446
  abortSignal.throwIfAborted();
406
447
  if(btcFeeRate!=null && resp.btcFeeRate > btcFeeRate) throw new IntermediaryError(`Required bitcoin fee rate returned from the LP is too high! Maximum accepted: ${btcFeeRate} sats/vB, required by LP: ${resp.btcFeeRate} sats/vB`);
407
448
 
449
+ const lpVersion = lp.getContractVersion(this.chainIdentifier);
450
+
408
451
  //Vault related
409
452
  let vaultScript: Uint8Array;
410
453
  let vaultAddressType: CoinselectAddressTypes;
@@ -452,7 +495,7 @@ export class SpvFromBTCWrapper<
452
495
  //Fetch vault data
453
496
  let vault: T["SpvVaultData"] | null;
454
497
  try {
455
- vault = await this._contract.getVaultData(resp.address, resp.vaultId);
498
+ vault = await this._contract(lpVersion).getVaultData(resp.address, resp.vaultId);
456
499
  } catch (e) {
457
500
  this.logger.error("Error getting spv vault (owner: "+resp.address+" vaultId: "+resp.vaultId.toString(10)+"): ", e);
458
501
  throw new IntermediaryError("Spv swap vault not found", e);
@@ -522,7 +565,7 @@ export class SpvFromBTCWrapper<
522
565
  if(_btcTx==null) throw new IntermediaryError("Invalid ancestor transaction (not found)");
523
566
  btcTx = _btcTx;
524
567
  }
525
- const withdrawalData = await this._contract.getWithdrawalData(btcTx);
568
+ const withdrawalData = await this._contract(lpVersion).getWithdrawalData(btcTx);
526
569
  abortSignal.throwIfAborted();
527
570
  pendingWithdrawals.unshift(withdrawalData);
528
571
  utxo = pendingWithdrawals[0].getSpentVaultUtxo();
@@ -549,7 +592,7 @@ export class SpvFromBTCWrapper<
549
592
  //Also verify that all the withdrawal txns are valid, this is an extra sanity check
550
593
  try {
551
594
  for(let withdrawal of pendingWithdrawals) {
552
- await this._contract.checkWithdrawalTx(withdrawal);
595
+ await this._contract(lpVersion).checkWithdrawalTx(withdrawal);
553
596
  }
554
597
  } catch (e) {
555
598
  this.logger.error("Error calculating spv vault balance (owner: "+resp.address+" vaultId: "+resp.vaultId.toString(10)+"): ", e);
@@ -596,6 +639,8 @@ export class SpvFromBTCWrapper<
596
639
  if(amountData.token===this._chain.getNativeCurrencyAddress() && _options.gasAmount!==0n)
597
640
  throw new UserError("Cannot specify `gasAmount` for swaps to a native token!");
598
641
 
642
+ const lpVersions = Intermediary.getContractVersionsForLps(this.chainIdentifier, lps);
643
+
599
644
  const _abortController = extendAbortController(abortSignal);
600
645
  const pricePrefetchPromise: Promise<bigint | undefined> = this.preFetchPrice(amountData, _abortController.signal);
601
646
  const usdPricePrefetchPromise: Promise<number | undefined> = this.preFetchUsdPrice(_abortController.signal);
@@ -604,7 +649,9 @@ export class SpvFromBTCWrapper<
604
649
  const gasTokenPricePrefetchPromise: Promise<bigint | undefined> | undefined = _options.gasAmount===0n ?
605
650
  undefined :
606
651
  this.preFetchPrice({token: nativeTokenAddress}, _abortController.signal);
607
- const callerFeePrefetchPromise = this.preFetchCallerFeeShare(amountData, _options, pricePrefetchPromise, gasTokenPricePrefetchPromise, _abortController);
652
+ const callerFeePrefetchPromise = mapArrayToObject(lpVersions, (contractVersion: string) => {
653
+ return this.preFetchCallerFeeShare(amountData, _options, pricePrefetchPromise, gasTokenPricePrefetchPromise, _abortController, contractVersion);
654
+ });
608
655
  const bitcoinFeeRatePromise: Promise<number | undefined> = _options.maxAllowedBitcoinFeeRate!=Infinity ?
609
656
  Promise.resolve(_options.maxAllowedBitcoinFeeRate) :
610
657
  this._btcRpc.getFeeRate().then(x => this._options.maxBtcFeeOffset + (x*this._options.maxBtcFeeMultiplier)).catch(e => {
@@ -617,6 +664,7 @@ export class SpvFromBTCWrapper<
617
664
  intermediary: lp,
618
665
  quote: tryWithRetries(async () => {
619
666
  if(lp.services[SwapType.SPV_VAULT_FROM_BTC]==null) throw new Error("LP service for processing spv vault swaps not found!");
667
+ const version = lp.getContractVersion(this.chainIdentifier);
620
668
 
621
669
  const abortController = extendAbortController(_abortController.signal);
622
670
 
@@ -631,7 +679,7 @@ export class SpvFromBTCWrapper<
631
679
  exactOut: !amountData.exactIn,
632
680
  gasToken: nativeTokenAddress,
633
681
  gasAmount: _options.gasAmount,
634
- callerFeeRate: throwIfUndefined(callerFeePrefetchPromise, "Caller fee prefetch failed!"),
682
+ callerFeeRate: throwIfUndefined(callerFeePrefetchPromise[version], "Caller fee prefetch failed!"),
635
683
  frontingFeeRate: 0n,
636
684
  additionalParams
637
685
  },
@@ -641,7 +689,7 @@ export class SpvFromBTCWrapper<
641
689
 
642
690
  this.logger.debug("create("+lp.url+"): LP response: ", resp)
643
691
 
644
- const callerFeeShare = (await callerFeePrefetchPromise)!;
692
+ const callerFeeShare = (await callerFeePrefetchPromise[version])!;
645
693
 
646
694
  const [
647
695
  pricingInfo,
@@ -704,7 +752,8 @@ export class SpvFromBTCWrapper<
704
752
  genesisSmartChainBlockHeight: await throwIfUndefined(
705
753
  finalizedBlockHeightPrefetchPromise,
706
754
  "Finalize block height promise failed!"
707
- )
755
+ ),
756
+ contractVersion: version
708
757
  };
709
758
  const quote = new SpvFromBTCSwap<T>(this, swapInit);
710
759
  return quote;
@@ -724,14 +773,14 @@ export class SpvFromBTCWrapper<
724
773
  * @param vault SPV vault processing the swap
725
774
  * @param lp Intermediary (LP) used as a counterparty for the swap
726
775
  */
727
- public async recoverFromState(state: SpvWithdrawalClaimedState | SpvWithdrawalFrontedState, vault?: SpvVaultData | null, lp?: Intermediary): Promise<SpvFromBTCSwap<T> | null> {
776
+ public async recoverFromState(state: SpvWithdrawalClaimedState | SpvWithdrawalFrontedState, contractVersion: string, vault?: SpvVaultData | null, lp?: Intermediary): Promise<SpvFromBTCSwap<T> | null> {
728
777
  //Get the vault
729
- vault ??= await this._contract.getVaultData(state.owner, state.vaultId);
778
+ vault ??= await this._contract(contractVersion).getVaultData(state.owner, state.vaultId);
730
779
  if(vault==null) return null;
731
780
  if(state.btcTxId==null) return null;
732
781
  const btcTx = await this._btcRpc.getTransaction(state.btcTxId);
733
782
  if(btcTx==null) return null;
734
- const withdrawalData = await this._contract.getWithdrawalData(btcTx)
783
+ const withdrawalData = await this._contract(contractVersion).getWithdrawalData(btcTx)
735
784
  .catch(e => {
736
785
  this.logger.warn(`Error parsing withdrawal data for tx ${btcTx.txid}: `, e);
737
786
  return null;
@@ -798,7 +847,9 @@ export class SpvFromBTCWrapper<
798
847
  frontingFeeShare: withdrawalData.frontingFeeRate,
799
848
  executionFeeShare: withdrawalData.executionFeeRate,
800
849
 
801
- genesisSmartChainBlockHeight: txBlock?.blockHeight ?? 0
850
+ genesisSmartChainBlockHeight: txBlock?.blockHeight ?? 0,
851
+
852
+ contractVersion
802
853
  };
803
854
  const quote = new SpvFromBTCSwap<T>(this, swapInit);
804
855
  quote._data = withdrawalData;
@@ -853,15 +904,21 @@ export class SpvFromBTCWrapper<
853
904
  amount: 600n
854
905
  });
855
906
 
856
- const opReturnData = this._contract.toOpReturnData(
857
- this._chain.randomAddress(),
858
- includeGasToken ? [0xFFFFFFFFFFFFFFFFn, 0xFFFFFFFFFFFFFFFFn] : [0xFFFFFFFFFFFFFFFFn]
859
- );
907
+ let longestOpReturnData: Buffer | undefined = undefined;
908
+ for(let contractVersion in this.versionedContracts) {
909
+ if(this.versionedContracts[contractVersion].spvVaultContract==null) continue;
910
+ const opReturnData = this._contract(contractVersion).toOpReturnData(
911
+ this._chain.randomAddress(),
912
+ includeGasToken ? [0xFFFFFFFFFFFFFFFFn, 0xFFFFFFFFFFFFFFFFn] : [0xFFFFFFFFFFFFFFFFn]
913
+ );
914
+ if(longestOpReturnData==null || longestOpReturnData.length < opReturnData.length) longestOpReturnData = opReturnData;
915
+ }
916
+ if(longestOpReturnData==null) throw new Error(`No contract version supporting the Spv Vault BTC -> ${this.chainIdentifier} swaps found!`);
860
917
 
861
918
  psbt.addOutput({
862
919
  script: Buffer.concat([
863
- opReturnData.length <= 75 ? Buffer.from([0x6a, opReturnData.length]) : Buffer.from([0x6a, 0x4c, opReturnData.length]),
864
- opReturnData
920
+ longestOpReturnData.length <= 75 ? Buffer.from([0x6a, longestOpReturnData.length]) : Buffer.from([0x6a, 0x4c, longestOpReturnData.length]),
921
+ longestOpReturnData
865
922
  ]),
866
923
  amount: 0n
867
924
  });
@@ -880,7 +937,7 @@ export class SpvFromBTCWrapper<
880
937
  const changedSwaps: Set<SpvFromBTCSwap<T>> = new Set();
881
938
  const removeSwaps: SpvFromBTCSwap<T>[] = [];
882
939
 
883
- const broadcastedOrConfirmedSwaps: (SpvFromBTCSwap<T> & {_data: T["SpvVaultWithdrawalData"]})[] = [];
940
+ const broadcastedOrConfirmedSwaps: {[version: string]: (SpvFromBTCSwap<T> & {_data: T["SpvVaultWithdrawalData"]})[]} = {};
884
941
 
885
942
  for(let pastSwap of pastSwaps) {
886
943
  let changed: boolean = false;
@@ -919,56 +976,65 @@ export class SpvFromBTCWrapper<
919
976
  if(changed) changedSwaps.add(pastSwap);
920
977
 
921
978
  if(pastSwap._state===SpvFromBTCSwapState.BROADCASTED || pastSwap._state===SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
922
- if(pastSwap._data!=null) broadcastedOrConfirmedSwaps.push(pastSwap as (SpvFromBTCSwap<T> & {_data: T["SpvVaultWithdrawalData"]}));
979
+ if(pastSwap._data!=null) (broadcastedOrConfirmedSwaps[pastSwap._contractVersion ?? "v1"] ??= []).push(pastSwap as (SpvFromBTCSwap<T> & {_data: T["SpvVaultWithdrawalData"]}));
923
980
  }
924
981
  }
925
982
 
926
- const checkWithdrawalStateSwaps: (SpvFromBTCSwap<T> & {_data: T["SpvVaultWithdrawalData"]})[] = [];
927
- const _fronts = await this._contract.getFronterAddresses(broadcastedOrConfirmedSwaps.map(val => ({
928
- ...val.getSpvVaultData(),
929
- withdrawal: val._data!
930
- })));
931
- const _vaultUtxos = await this._contract.getVaultLatestUtxos(broadcastedOrConfirmedSwaps.map(val => val.getSpvVaultData()));
932
- for(const pastSwap of broadcastedOrConfirmedSwaps) {
933
- const fronterAddress = _fronts[pastSwap._data.getTxId()];
934
- const vault = pastSwap.getSpvVaultData();
935
- const latestVaultUtxo = _vaultUtxos[vault.owner]?.[vault.vaultId.toString(10)];
936
- if(fronterAddress===undefined) this.logger.warn(`_checkPastSwaps(): No fronter address returned for ${pastSwap._data.getTxId()}`);
937
- if(latestVaultUtxo===undefined) this.logger.warn(`_checkPastSwaps(): No last vault utxo returned for ${pastSwap._data.getTxId()}`);
938
- if(await pastSwap._shouldCheckWithdrawalState(fronterAddress, latestVaultUtxo)) checkWithdrawalStateSwaps.push(pastSwap);
939
- }
940
-
941
- const withdrawalStates = await this._contract.getWithdrawalStates(
942
- checkWithdrawalStateSwaps.map(val => ({
943
- withdrawal: val._data,
944
- scStartBlockheight: val._genesisSmartChainBlockHeight
945
- }))
946
- );
947
- for(const pastSwap of checkWithdrawalStateSwaps) {
948
- const status = withdrawalStates[pastSwap._data.getTxId()];
949
- if(status==null) {
950
- this.logger.warn(`_checkPastSwaps(): No withdrawal state returned for ${pastSwap._data.getTxId()}`);
983
+ for(let contractVersion in broadcastedOrConfirmedSwaps) {
984
+ if(this.versionedContracts[contractVersion]==null) {
985
+ this.logger.warn(`_checkPastSwaps(): No contract was found for ${this.chainIdentifier} version ${contractVersion}! Skipping these swaps!`);
951
986
  continue;
952
987
  }
953
- this.logger.debug("syncStateFromChain(): status of "+pastSwap._data.btcTx.txid, status?.type);
954
- let changed = false;
955
- switch(status.type) {
956
- case SpvWithdrawalStateType.FRONTED:
957
- pastSwap._frontTxId = status.txId;
958
- pastSwap._state = SpvFromBTCSwapState.FRONTED;
959
- changed ||= true;
960
- break;
961
- case SpvWithdrawalStateType.CLAIMED:
962
- pastSwap._claimTxId = status.txId;
963
- pastSwap._state = SpvFromBTCSwapState.CLAIMED;
964
- changed ||= true;
965
- break;
966
- case SpvWithdrawalStateType.CLOSED:
967
- pastSwap._state = SpvFromBTCSwapState.CLOSED;
968
- changed ||= true;
969
- break;
988
+
989
+ const _broadcastedOrConfirmedSwaps = broadcastedOrConfirmedSwaps[contractVersion];
990
+
991
+ const checkWithdrawalStateSwaps: (SpvFromBTCSwap<T> & {_data: T["SpvVaultWithdrawalData"]})[] = [];
992
+ const _fronts = await this._contract(contractVersion).getFronterAddresses(_broadcastedOrConfirmedSwaps.map(val => ({
993
+ ...val.getSpvVaultData(),
994
+ withdrawal: val._data!
995
+ })));
996
+ const _vaultUtxos = await this._contract(contractVersion).getVaultLatestUtxos(_broadcastedOrConfirmedSwaps.map(val => val.getSpvVaultData()));
997
+ for(const pastSwap of _broadcastedOrConfirmedSwaps) {
998
+ const fronterAddress = _fronts[pastSwap._data.getTxId()];
999
+ const vault = pastSwap.getSpvVaultData();
1000
+ const latestVaultUtxo = _vaultUtxos[vault.owner]?.[vault.vaultId.toString(10)];
1001
+ if(fronterAddress===undefined) this.logger.warn(`_checkPastSwaps(): No fronter address returned for ${pastSwap._data.getTxId()}`);
1002
+ if(latestVaultUtxo===undefined) this.logger.warn(`_checkPastSwaps(): No last vault utxo returned for ${pastSwap._data.getTxId()}`);
1003
+ if(await pastSwap._shouldCheckWithdrawalState(fronterAddress, latestVaultUtxo)) checkWithdrawalStateSwaps.push(pastSwap);
1004
+ }
1005
+
1006
+ const withdrawalStates = await this._contract(contractVersion).getWithdrawalStates(
1007
+ checkWithdrawalStateSwaps.map(val => ({
1008
+ withdrawal: val._data,
1009
+ scStartBlockheight: val._genesisSmartChainBlockHeight
1010
+ }))
1011
+ );
1012
+ for(const pastSwap of checkWithdrawalStateSwaps) {
1013
+ const status = withdrawalStates[pastSwap._data.getTxId()];
1014
+ if(status==null) {
1015
+ this.logger.warn(`_checkPastSwaps(): No withdrawal state returned for ${pastSwap._data.getTxId()}`);
1016
+ continue;
1017
+ }
1018
+ this.logger.debug("syncStateFromChain(): status of "+pastSwap._data.btcTx.txid, status?.type);
1019
+ let changed = false;
1020
+ switch(status.type) {
1021
+ case SpvWithdrawalStateType.FRONTED:
1022
+ pastSwap._frontTxId = status.txId;
1023
+ pastSwap._state = SpvFromBTCSwapState.FRONTED;
1024
+ changed ||= true;
1025
+ break;
1026
+ case SpvWithdrawalStateType.CLAIMED:
1027
+ pastSwap._claimTxId = status.txId;
1028
+ pastSwap._state = SpvFromBTCSwapState.CLAIMED;
1029
+ changed ||= true;
1030
+ break;
1031
+ case SpvWithdrawalStateType.CLOSED:
1032
+ pastSwap._state = SpvFromBTCSwapState.CLOSED;
1033
+ changed ||= true;
1034
+ break;
1035
+ }
1036
+ if(changed) changedSwaps.add(pastSwap);
970
1037
  }
971
- if(changed) changedSwaps.add(pastSwap);
972
1038
  }
973
1039
 
974
1040
  return {
@@ -81,7 +81,8 @@ export class LnForGasWrapper<T extends ChainType> extends ISwapWrapper<T, LnForG
81
81
  swapFee: resp.swapFee,
82
82
  swapFeeBtc: resp.swapFeeSats,
83
83
  token,
84
- exactIn: false
84
+ exactIn: false,
85
+ contractVersion: "v1"
85
86
  };
86
87
  const quote = new LnForGasSwap(this, quoteInit);
87
88
  return quote;
@@ -122,7 +122,8 @@ export class OnchainForGasWrapper<T extends ChainType> extends ISwapWrapper<T, O
122
122
  swapFee: resp.swapFee,
123
123
  swapFeeBtc: resp.swapFeeSats,
124
124
  exactIn: false,
125
- token
125
+ token,
126
+ contractVersion: "v1"
126
127
  } as OnchainForGasSwapInit);
127
128
  return quote;
128
129
  }
@@ -40,12 +40,19 @@ function checkError(e: any, errorAllowed: ((e: any) => boolean) | Constructor<Er
40
40
  * @param retryPolicy.exponential Whether to use exponentially increasing delays
41
41
  * @param errorAllowed A callback for determining whether a given error is allowed, and we should therefore not retry
42
42
  * @param abortSignal
43
+ * @param failureLogLevel
43
44
  * @returns Result of the action executing callback
44
45
  * @category Utilities
45
46
  */
46
- export async function tryWithRetries<T>(func: (retryCount: number) => Promise<T>, retryPolicy?: {
47
- maxRetries?: number, delay?: number, exponential?: boolean
48
- }, errorAllowed?: ((e: any) => boolean) | Constructor<Error> | Constructor<Error>[], abortSignal?: AbortSignal): Promise<T> {
47
+ export async function tryWithRetries<T>(
48
+ func: (retryCount: number) => Promise<T>,
49
+ retryPolicy?: {
50
+ maxRetries?: number, delay?: number, exponential?: boolean
51
+ },
52
+ errorAllowed?: ((e: any) => boolean) | Constructor<Error> | Constructor<Error>[],
53
+ abortSignal?: AbortSignal,
54
+ failureLogLevel: "debug" | "info" | "warn" | "error" = "warn"
55
+ ): Promise<T> {
49
56
  retryPolicy = retryPolicy || {};
50
57
  retryPolicy.maxRetries = retryPolicy.maxRetries || 5;
51
58
  retryPolicy.delay = retryPolicy.delay || 500;
@@ -59,7 +66,7 @@ export async function tryWithRetries<T>(func: (retryCount: number) => Promise<T>
59
66
  } catch (e) {
60
67
  if (errorAllowed != null && checkError(e, errorAllowed)) throw e;
61
68
  err = e;
62
- logger.debug("tryWithRetries(): Error on try number: " + i, e);
69
+ logger[failureLogLevel]("tryWithRetries(): Error on try number: " + i, e);
63
70
  }
64
71
  if (abortSignal != null && abortSignal.aborted) throw (abortSignal.reason || new Error("Aborted"));
65
72
  if (i !== retryPolicy.maxRetries - 1) {
@@ -46,6 +46,20 @@ export function promiseAny<T>(promises: Promise<T>[]): Promise<T> {
46
46
  });
47
47
  }
48
48
 
49
+ /**
50
+ * Maps an array to object properties using the translation function
51
+ *
52
+ * @param array
53
+ * @param translator
54
+ */
55
+ export function mapArrayToObject<T extends string[], O>(array: T, translator: (key: T[number]) => O): {[key in T[number]]: O} {
56
+ const obj: any = {};
57
+ array.forEach((item) => {
58
+ obj[item] = translator(item);
59
+ });
60
+ return obj;
61
+ }
62
+
49
63
  /**
50
64
  * Maps a JS object to another JS object based on the translation function, the translation function is called for every
51
65
  * property (value/key) of the old object and returns the new value of for this property