@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
@@ -6,6 +6,7 @@ const base_1 = require("@atomiqlabs/base");
6
6
  const SpvFromBTCSwap_1 = require("./SpvFromBTCSwap");
7
7
  const utils_1 = require("@scure/btc-signer/utils");
8
8
  const SwapType_1 = require("../../enums/SwapType");
9
+ const Intermediary_1 = require("../../intermediaries/Intermediary");
9
10
  const Utils_1 = require("../../utils/Utils");
10
11
  const BitcoinUtils_1 = require("../../utils/BitcoinUtils");
11
12
  const IntermediaryAPI_1 = require("../../intermediaries/apis/IntermediaryAPI");
@@ -27,17 +28,15 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
27
28
  * @param unifiedStorage Storage interface for the current environment
28
29
  * @param unifiedChainEvents On-chain event listener
29
30
  * @param chain
30
- * @param contract Underlying contract handling the swaps
31
31
  * @param prices Pricing to use
32
32
  * @param tokens
33
- * @param spvWithdrawalDataDeserializer Deserializer for SpvVaultWithdrawalData
34
- * @param btcRelay
35
- * @param synchronizer Btc relay synchronizer
33
+ * @param versionedContracts
34
+ * @param versionedSynchronizer
36
35
  * @param btcRpc Bitcoin RPC which also supports getting transactions by txoHash
37
36
  * @param options
38
37
  * @param events Instance to use for emitting events
39
38
  */
40
- constructor(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, spvWithdrawalDataDeserializer, btcRelay, synchronizer, btcRpc, options, events) {
39
+ constructor(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, versionedContracts, versionedSynchronizer, btcRpc, options, events) {
41
40
  super(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, {
42
41
  ...options,
43
42
  bitcoinNetwork: options?.bitcoinNetwork ?? utils_1.TEST_NETWORK,
@@ -57,6 +56,16 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
57
56
  * @internal
58
57
  */
59
58
  this._swapDeserializer = SpvFromBTCSwap_1.SpvFromBTCSwap;
59
+ /**
60
+ * @internal
61
+ */
62
+ this.btcRelay = (version) => {
63
+ const _version = version ?? "v1";
64
+ const data = this.versionedContracts[_version];
65
+ if (data == null)
66
+ throw new Error(`Invalid contract version ${_version} requested`);
67
+ return data.btcRelay;
68
+ };
60
69
  /**
61
70
  * @internal
62
71
  */
@@ -67,6 +76,36 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
67
76
  SpvFromBTCSwap_1.SpvFromBTCSwapState.POSTED,
68
77
  SpvFromBTCSwap_1.SpvFromBTCSwapState.BROADCASTED
69
78
  ];
79
+ /**
80
+ * @internal
81
+ */
82
+ this._synchronizer = (version) => {
83
+ const _version = version ?? "v1";
84
+ const data = this.versionedSynchronizer[_version];
85
+ if (data == null)
86
+ throw new Error(`Invalid contract version ${_version} requested`);
87
+ return data.synchronizer;
88
+ };
89
+ /**
90
+ * @internal
91
+ */
92
+ this._contract = (version) => {
93
+ const _version = version ?? "v1";
94
+ const data = this.versionedContracts[_version];
95
+ if (data == null)
96
+ throw new Error(`Invalid contract version ${_version} requested`);
97
+ return data.spvVaultContract;
98
+ };
99
+ /**
100
+ * @internal
101
+ */
102
+ this._spvWithdrawalDataDeserializer = (version) => {
103
+ const _version = version ?? "v1";
104
+ const data = this.versionedContracts[_version];
105
+ if (data == null)
106
+ throw new Error(`Invalid contract version ${_version} requested`);
107
+ return data.spvVaultWithdrawalDataConstructor;
108
+ };
70
109
  /**
71
110
  * @internal
72
111
  */
@@ -79,10 +118,10 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
79
118
  SpvFromBTCSwap_1.SpvFromBTCSwapState.DECLINED,
80
119
  SpvFromBTCSwap_1.SpvFromBTCSwapState.BTC_TX_CONFIRMED
81
120
  ];
82
- this._spvWithdrawalDataDeserializer = spvWithdrawalDataDeserializer;
83
- this._contract = contract;
84
- this.btcRelay = btcRelay;
85
- this._synchronizer = synchronizer;
121
+ this.versionedContracts = {};
122
+ this.versionedSynchronizer = {};
123
+ this.versionedContracts = versionedContracts;
124
+ this.versionedSynchronizer = versionedSynchronizer;
86
125
  this._btcRpc = btcRpc;
87
126
  }
88
127
  async processEventFront(event, swap) {
@@ -173,19 +212,20 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
173
212
  * @param pricePrefetch
174
213
  * @param nativeTokenPricePrefetch
175
214
  * @param abortController
215
+ * @param contractVersion
176
216
  * @private
177
217
  */
178
- async preFetchCallerFeeShare(amountData, options, pricePrefetch, nativeTokenPricePrefetch, abortController) {
218
+ async preFetchCallerFeeShare(amountData, options, pricePrefetch, nativeTokenPricePrefetch, abortController, contractVersion) {
179
219
  if (options.unsafeZeroWatchtowerFee)
180
220
  return 0n;
181
221
  if (amountData.amount === 0n)
182
222
  return 0n;
183
223
  try {
184
224
  const [feePerBlock, btcRelayData, currentBtcBlock, claimFeeRate, nativeTokenPrice] = await Promise.all([
185
- this.btcRelay.getFeePerBlock(),
186
- this.btcRelay.getTipData(),
225
+ this.btcRelay(contractVersion).getFeePerBlock(),
226
+ this.btcRelay(contractVersion).getTipData(),
187
227
  this._btcRpc.getTipHeight(),
188
- this._contract.getClaimFee(this._chain.randomAddress()),
228
+ this._contract(contractVersion).getClaimFee(this._chain.randomAddress()),
189
229
  nativeTokenPricePrefetch ?? (amountData.token === this._chain.getNativeCurrencyAddress() ?
190
230
  pricePrefetch :
191
231
  this._prices.preFetchPrice(this.chainIdentifier, this._chain.getNativeCurrencyAddress(), abortController.signal))
@@ -243,6 +283,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
243
283
  abortSignal.throwIfAborted();
244
284
  if (btcFeeRate != null && resp.btcFeeRate > btcFeeRate)
245
285
  throw new IntermediaryError_1.IntermediaryError(`Required bitcoin fee rate returned from the LP is too high! Maximum accepted: ${btcFeeRate} sats/vB, required by LP: ${resp.btcFeeRate} sats/vB`);
286
+ const lpVersion = lp.getContractVersion(this.chainIdentifier);
246
287
  //Vault related
247
288
  let vaultScript;
248
289
  let vaultAddressType;
@@ -288,7 +329,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
288
329
  //Fetch vault data
289
330
  let vault;
290
331
  try {
291
- vault = await this._contract.getVaultData(resp.address, resp.vaultId);
332
+ vault = await this._contract(lpVersion).getVaultData(resp.address, resp.vaultId);
292
333
  }
293
334
  catch (e) {
294
335
  this.logger.error("Error getting spv vault (owner: " + resp.address + " vaultId: " + resp.vaultId.toString(10) + "): ", e);
@@ -367,7 +408,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
367
408
  throw new IntermediaryError_1.IntermediaryError("Invalid ancestor transaction (not found)");
368
409
  btcTx = _btcTx;
369
410
  }
370
- const withdrawalData = await this._contract.getWithdrawalData(btcTx);
411
+ const withdrawalData = await this._contract(lpVersion).getWithdrawalData(btcTx);
371
412
  abortSignal.throwIfAborted();
372
413
  pendingWithdrawals.unshift(withdrawalData);
373
414
  utxo = pendingWithdrawals[0].getSpentVaultUtxo();
@@ -393,7 +434,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
393
434
  //Also verify that all the withdrawal txns are valid, this is an extra sanity check
394
435
  try {
395
436
  for (let withdrawal of pendingWithdrawals) {
396
- await this._contract.checkWithdrawalTx(withdrawal);
437
+ await this._contract(lpVersion).checkWithdrawalTx(withdrawal);
397
438
  }
398
439
  }
399
440
  catch (e) {
@@ -427,6 +468,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
427
468
  };
428
469
  if (amountData.token === this._chain.getNativeCurrencyAddress() && _options.gasAmount !== 0n)
429
470
  throw new UserError_1.UserError("Cannot specify `gasAmount` for swaps to a native token!");
471
+ const lpVersions = Intermediary_1.Intermediary.getContractVersionsForLps(this.chainIdentifier, lps);
430
472
  const _abortController = (0, Utils_1.extendAbortController)(abortSignal);
431
473
  const pricePrefetchPromise = this.preFetchPrice(amountData, _abortController.signal);
432
474
  const usdPricePrefetchPromise = this.preFetchUsdPrice(_abortController.signal);
@@ -435,7 +477,9 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
435
477
  const gasTokenPricePrefetchPromise = _options.gasAmount === 0n ?
436
478
  undefined :
437
479
  this.preFetchPrice({ token: nativeTokenAddress }, _abortController.signal);
438
- const callerFeePrefetchPromise = this.preFetchCallerFeeShare(amountData, _options, pricePrefetchPromise, gasTokenPricePrefetchPromise, _abortController);
480
+ const callerFeePrefetchPromise = (0, Utils_1.mapArrayToObject)(lpVersions, (contractVersion) => {
481
+ return this.preFetchCallerFeeShare(amountData, _options, pricePrefetchPromise, gasTokenPricePrefetchPromise, _abortController, contractVersion);
482
+ });
439
483
  const bitcoinFeeRatePromise = _options.maxAllowedBitcoinFeeRate != Infinity ?
440
484
  Promise.resolve(_options.maxAllowedBitcoinFeeRate) :
441
485
  this._btcRpc.getFeeRate().then(x => this._options.maxBtcFeeOffset + (x * this._options.maxBtcFeeMultiplier)).catch(e => {
@@ -448,6 +492,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
448
492
  quote: (0, RetryUtils_1.tryWithRetries)(async () => {
449
493
  if (lp.services[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] == null)
450
494
  throw new Error("LP service for processing spv vault swaps not found!");
495
+ const version = lp.getContractVersion(this.chainIdentifier);
451
496
  const abortController = (0, Utils_1.extendAbortController)(_abortController.signal);
452
497
  try {
453
498
  const resp = await (0, RetryUtils_1.tryWithRetries)(async (retryCount) => {
@@ -458,13 +503,13 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
458
503
  exactOut: !amountData.exactIn,
459
504
  gasToken: nativeTokenAddress,
460
505
  gasAmount: _options.gasAmount,
461
- callerFeeRate: (0, Utils_1.throwIfUndefined)(callerFeePrefetchPromise, "Caller fee prefetch failed!"),
506
+ callerFeeRate: (0, Utils_1.throwIfUndefined)(callerFeePrefetchPromise[version], "Caller fee prefetch failed!"),
462
507
  frontingFeeRate: 0n,
463
508
  additionalParams
464
509
  }, this._options.postRequestTimeout, abortController.signal, retryCount > 0 ? false : undefined);
465
510
  }, undefined, e => e instanceof RequestError_1.RequestError, abortController.signal);
466
511
  this.logger.debug("create(" + lp.url + "): LP response: ", resp);
467
- const callerFeeShare = (await callerFeePrefetchPromise);
512
+ const callerFeeShare = (await callerFeePrefetchPromise[version]);
468
513
  const [pricingInfo, gasPricingInfo, { vault, vaultUtxoValue }] = await Promise.all([
469
514
  this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], false, resp.btcAmountSwap, resp.total * (100000n + callerFeeShare) / 100000n, amountData.token, {}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal),
470
515
  _options.gasAmount === 0n ? Promise.resolve(undefined) : this.verifyReturnedPrice({ ...lp.services[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], swapBaseFee: 0 }, //Base fee should be charged only on the amount, not on gas
@@ -502,7 +547,8 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
502
547
  callerFeeShare: resp.callerFeeShare,
503
548
  frontingFeeShare: resp.frontingFeeShare,
504
549
  executionFeeShare: resp.executionFeeShare,
505
- genesisSmartChainBlockHeight: await (0, Utils_1.throwIfUndefined)(finalizedBlockHeightPrefetchPromise, "Finalize block height promise failed!")
550
+ genesisSmartChainBlockHeight: await (0, Utils_1.throwIfUndefined)(finalizedBlockHeightPrefetchPromise, "Finalize block height promise failed!"),
551
+ contractVersion: version
506
552
  };
507
553
  const quote = new SpvFromBTCSwap_1.SpvFromBTCSwap(this, swapInit);
508
554
  return quote;
@@ -522,9 +568,9 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
522
568
  * @param vault SPV vault processing the swap
523
569
  * @param lp Intermediary (LP) used as a counterparty for the swap
524
570
  */
525
- async recoverFromState(state, vault, lp) {
571
+ async recoverFromState(state, contractVersion, vault, lp) {
526
572
  //Get the vault
527
- vault ??= await this._contract.getVaultData(state.owner, state.vaultId);
573
+ vault ??= await this._contract(contractVersion).getVaultData(state.owner, state.vaultId);
528
574
  if (vault == null)
529
575
  return null;
530
576
  if (state.btcTxId == null)
@@ -532,7 +578,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
532
578
  const btcTx = await this._btcRpc.getTransaction(state.btcTxId);
533
579
  if (btcTx == null)
534
580
  return null;
535
- const withdrawalData = await this._contract.getWithdrawalData(btcTx)
581
+ const withdrawalData = await this._contract(contractVersion).getWithdrawalData(btcTx)
536
582
  .catch(e => {
537
583
  this.logger.warn(`Error parsing withdrawal data for tx ${btcTx.txid}: `, e);
538
584
  return null;
@@ -590,7 +636,8 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
590
636
  callerFeeShare: withdrawalData.callerFeeRate,
591
637
  frontingFeeShare: withdrawalData.frontingFeeRate,
592
638
  executionFeeShare: withdrawalData.executionFeeRate,
593
- genesisSmartChainBlockHeight: txBlock?.blockHeight ?? 0
639
+ genesisSmartChainBlockHeight: txBlock?.blockHeight ?? 0,
640
+ contractVersion
594
641
  };
595
642
  const quote = new SpvFromBTCSwap_1.SpvFromBTCSwap(this, swapInit);
596
643
  quote._data = withdrawalData;
@@ -644,11 +691,20 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
644
691
  script: randomVaultOutScript,
645
692
  amount: 600n
646
693
  });
647
- const opReturnData = this._contract.toOpReturnData(this._chain.randomAddress(), includeGasToken ? [0xffffffffffffffffn, 0xffffffffffffffffn] : [0xffffffffffffffffn]);
694
+ let longestOpReturnData = undefined;
695
+ for (let contractVersion in this.versionedContracts) {
696
+ if (this.versionedContracts[contractVersion].spvVaultContract == null)
697
+ continue;
698
+ const opReturnData = this._contract(contractVersion).toOpReturnData(this._chain.randomAddress(), includeGasToken ? [0xffffffffffffffffn, 0xffffffffffffffffn] : [0xffffffffffffffffn]);
699
+ if (longestOpReturnData == null || longestOpReturnData.length < opReturnData.length)
700
+ longestOpReturnData = opReturnData;
701
+ }
702
+ if (longestOpReturnData == null)
703
+ throw new Error(`No contract version supporting the Spv Vault BTC -> ${this.chainIdentifier} swaps found!`);
648
704
  psbt.addOutput({
649
705
  script: Buffer.concat([
650
- opReturnData.length <= 75 ? Buffer.from([0x6a, opReturnData.length]) : Buffer.from([0x6a, 0x4c, opReturnData.length]),
651
- opReturnData
706
+ longestOpReturnData.length <= 75 ? Buffer.from([0x6a, longestOpReturnData.length]) : Buffer.from([0x6a, 0x4c, longestOpReturnData.length]),
707
+ longestOpReturnData
652
708
  ]),
653
709
  amount: 0n
654
710
  });
@@ -661,7 +717,7 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
661
717
  async _checkPastSwaps(pastSwaps) {
662
718
  const changedSwaps = new Set();
663
719
  const removeSwaps = [];
664
- const broadcastedOrConfirmedSwaps = [];
720
+ const broadcastedOrConfirmedSwaps = {};
665
721
  for (let pastSwap of pastSwaps) {
666
722
  let changed = false;
667
723
  if (pastSwap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.SIGNED ||
@@ -695,56 +751,63 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
695
751
  changedSwaps.add(pastSwap);
696
752
  if (pastSwap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.BROADCASTED || pastSwap._state === SpvFromBTCSwap_1.SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
697
753
  if (pastSwap._data != null)
698
- broadcastedOrConfirmedSwaps.push(pastSwap);
754
+ (broadcastedOrConfirmedSwaps[pastSwap._contractVersion ?? "v1"] ??= []).push(pastSwap);
699
755
  }
700
756
  }
701
- const checkWithdrawalStateSwaps = [];
702
- const _fronts = await this._contract.getFronterAddresses(broadcastedOrConfirmedSwaps.map(val => ({
703
- ...val.getSpvVaultData(),
704
- withdrawal: val._data
705
- })));
706
- const _vaultUtxos = await this._contract.getVaultLatestUtxos(broadcastedOrConfirmedSwaps.map(val => val.getSpvVaultData()));
707
- for (const pastSwap of broadcastedOrConfirmedSwaps) {
708
- const fronterAddress = _fronts[pastSwap._data.getTxId()];
709
- const vault = pastSwap.getSpvVaultData();
710
- const latestVaultUtxo = _vaultUtxos[vault.owner]?.[vault.vaultId.toString(10)];
711
- if (fronterAddress === undefined)
712
- this.logger.warn(`_checkPastSwaps(): No fronter address returned for ${pastSwap._data.getTxId()}`);
713
- if (latestVaultUtxo === undefined)
714
- this.logger.warn(`_checkPastSwaps(): No last vault utxo returned for ${pastSwap._data.getTxId()}`);
715
- if (await pastSwap._shouldCheckWithdrawalState(fronterAddress, latestVaultUtxo))
716
- checkWithdrawalStateSwaps.push(pastSwap);
717
- }
718
- const withdrawalStates = await this._contract.getWithdrawalStates(checkWithdrawalStateSwaps.map(val => ({
719
- withdrawal: val._data,
720
- scStartBlockheight: val._genesisSmartChainBlockHeight
721
- })));
722
- for (const pastSwap of checkWithdrawalStateSwaps) {
723
- const status = withdrawalStates[pastSwap._data.getTxId()];
724
- if (status == null) {
725
- this.logger.warn(`_checkPastSwaps(): No withdrawal state returned for ${pastSwap._data.getTxId()}`);
757
+ for (let contractVersion in broadcastedOrConfirmedSwaps) {
758
+ if (this.versionedContracts[contractVersion] == null) {
759
+ this.logger.warn(`_checkPastSwaps(): No contract was found for ${this.chainIdentifier} version ${contractVersion}! Skipping these swaps!`);
726
760
  continue;
727
761
  }
728
- this.logger.debug("syncStateFromChain(): status of " + pastSwap._data.btcTx.txid, status?.type);
729
- let changed = false;
730
- switch (status.type) {
731
- case base_1.SpvWithdrawalStateType.FRONTED:
732
- pastSwap._frontTxId = status.txId;
733
- pastSwap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.FRONTED;
734
- changed ||= true;
735
- break;
736
- case base_1.SpvWithdrawalStateType.CLAIMED:
737
- pastSwap._claimTxId = status.txId;
738
- pastSwap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.CLAIMED;
739
- changed ||= true;
740
- break;
741
- case base_1.SpvWithdrawalStateType.CLOSED:
742
- pastSwap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.CLOSED;
743
- changed ||= true;
744
- break;
762
+ const _broadcastedOrConfirmedSwaps = broadcastedOrConfirmedSwaps[contractVersion];
763
+ const checkWithdrawalStateSwaps = [];
764
+ const _fronts = await this._contract(contractVersion).getFronterAddresses(_broadcastedOrConfirmedSwaps.map(val => ({
765
+ ...val.getSpvVaultData(),
766
+ withdrawal: val._data
767
+ })));
768
+ const _vaultUtxos = await this._contract(contractVersion).getVaultLatestUtxos(_broadcastedOrConfirmedSwaps.map(val => val.getSpvVaultData()));
769
+ for (const pastSwap of _broadcastedOrConfirmedSwaps) {
770
+ const fronterAddress = _fronts[pastSwap._data.getTxId()];
771
+ const vault = pastSwap.getSpvVaultData();
772
+ const latestVaultUtxo = _vaultUtxos[vault.owner]?.[vault.vaultId.toString(10)];
773
+ if (fronterAddress === undefined)
774
+ this.logger.warn(`_checkPastSwaps(): No fronter address returned for ${pastSwap._data.getTxId()}`);
775
+ if (latestVaultUtxo === undefined)
776
+ this.logger.warn(`_checkPastSwaps(): No last vault utxo returned for ${pastSwap._data.getTxId()}`);
777
+ if (await pastSwap._shouldCheckWithdrawalState(fronterAddress, latestVaultUtxo))
778
+ checkWithdrawalStateSwaps.push(pastSwap);
779
+ }
780
+ const withdrawalStates = await this._contract(contractVersion).getWithdrawalStates(checkWithdrawalStateSwaps.map(val => ({
781
+ withdrawal: val._data,
782
+ scStartBlockheight: val._genesisSmartChainBlockHeight
783
+ })));
784
+ for (const pastSwap of checkWithdrawalStateSwaps) {
785
+ const status = withdrawalStates[pastSwap._data.getTxId()];
786
+ if (status == null) {
787
+ this.logger.warn(`_checkPastSwaps(): No withdrawal state returned for ${pastSwap._data.getTxId()}`);
788
+ continue;
789
+ }
790
+ this.logger.debug("syncStateFromChain(): status of " + pastSwap._data.btcTx.txid, status?.type);
791
+ let changed = false;
792
+ switch (status.type) {
793
+ case base_1.SpvWithdrawalStateType.FRONTED:
794
+ pastSwap._frontTxId = status.txId;
795
+ pastSwap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.FRONTED;
796
+ changed ||= true;
797
+ break;
798
+ case base_1.SpvWithdrawalStateType.CLAIMED:
799
+ pastSwap._claimTxId = status.txId;
800
+ pastSwap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.CLAIMED;
801
+ changed ||= true;
802
+ break;
803
+ case base_1.SpvWithdrawalStateType.CLOSED:
804
+ pastSwap._state = SpvFromBTCSwap_1.SpvFromBTCSwapState.CLOSED;
805
+ changed ||= true;
806
+ break;
807
+ }
808
+ if (changed)
809
+ changedSwaps.add(pastSwap);
745
810
  }
746
- if (changed)
747
- changedSwaps.add(pastSwap);
748
811
  }
749
812
  return {
750
813
  changedSwaps: Array.from(changedSwaps),
@@ -73,7 +73,8 @@ class LnForGasWrapper extends ISwapWrapper_1.ISwapWrapper {
73
73
  swapFee: resp.swapFee,
74
74
  swapFeeBtc: resp.swapFeeSats,
75
75
  token,
76
- exactIn: false
76
+ exactIn: false,
77
+ contractVersion: "v1"
77
78
  };
78
79
  const quote = new LnForGasSwap_1.LnForGasSwap(this, quoteInit);
79
80
  return quote;
@@ -84,7 +84,8 @@ class OnchainForGasWrapper extends ISwapWrapper_1.ISwapWrapper {
84
84
  swapFee: resp.swapFee,
85
85
  swapFeeBtc: resp.swapFeeSats,
86
86
  exactIn: false,
87
- token
87
+ token,
88
+ contractVersion: "v1"
88
89
  });
89
90
  return quote;
90
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"));
@@ -17,6 +17,15 @@ export declare function throwIfUndefined<T>(promise: Promise<T | undefined>, msg
17
17
  * @category Utilities
18
18
  */
19
19
  export declare function promiseAny<T>(promises: Promise<T>[]): Promise<T>;
20
+ /**
21
+ * Maps an array to object properties using the translation function
22
+ *
23
+ * @param array
24
+ * @param translator
25
+ */
26
+ export declare function mapArrayToObject<T extends string[], O>(array: T, translator: (key: T[number]) => O): {
27
+ [key in T[number]]: O;
28
+ };
20
29
  /**
21
30
  * Maps a JS object to another JS object based on the translation function, the translation function is called for every
22
31
  * property (value/key) of the old object and returns the new value of for this property
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseHashValueExact32Bytes = exports.toDecimal = exports.fromDecimal = exports.getTxoHash = exports.randomBytes = exports.toBigInt = exports.bigIntCompare = exports.bigIntMax = exports.bigIntMin = exports.extendAbortController = exports.mapToArray = exports.objectMap = exports.promiseAny = exports.throwIfUndefined = void 0;
3
+ exports.parseHashValueExact32Bytes = exports.toDecimal = exports.fromDecimal = exports.getTxoHash = exports.randomBytes = exports.toBigInt = exports.bigIntCompare = exports.bigIntMax = exports.bigIntMin = exports.extendAbortController = exports.mapToArray = exports.objectMap = exports.mapArrayToObject = exports.promiseAny = exports.throwIfUndefined = void 0;
4
4
  const buffer_1 = require("buffer");
5
5
  const utils_1 = require("@noble/hashes/utils");
6
6
  const sha2_1 = require("@noble/hashes/sha2");
@@ -48,6 +48,20 @@ function promiseAny(promises) {
48
48
  });
49
49
  }
50
50
  exports.promiseAny = promiseAny;
51
+ /**
52
+ * Maps an array to object properties using the translation function
53
+ *
54
+ * @param array
55
+ * @param translator
56
+ */
57
+ function mapArrayToObject(array, translator) {
58
+ const obj = {};
59
+ array.forEach((item) => {
60
+ obj[item] = translator(item);
61
+ });
62
+ return obj;
63
+ }
64
+ exports.mapArrayToObject = mapArrayToObject;
51
65
  /**
52
66
  * Maps a JS object to another JS object based on the translation function, the translation function is called for every
53
67
  * property (value/key) of the old object and returns the new value of for this property
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/sdk",
3
- "version": "8.6.2",
3
+ "version": "8.7.1",
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",
@@ -23,7 +23,7 @@
23
23
  "author": "adambor",
24
24
  "license": "ISC",
25
25
  "dependencies": {
26
- "@atomiqlabs/base": "^13.1.9",
26
+ "@atomiqlabs/base": "^13.5.0",
27
27
  "@atomiqlabs/bolt11": "1.6.1",
28
28
  "@atomiqlabs/btc-mempool": "^1.0.4",
29
29
  "@atomiqlabs/messenger-nostr": "^2.0.0",
@@ -82,9 +82,10 @@ export class UnifiedSwapEventListener<
82
82
 
83
83
  for(let event of events) {
84
84
  const escrowHash = chainEventToEscrowHash(event);
85
+ const eventVersion = event.contractVersion ?? "v1";
85
86
  if(escrowHash!=null) {
86
87
  const swap = swapsByEscrowHash[escrowHash];
87
- if(swap!=null) {
88
+ if(swap!=null && (swap._contractVersion ?? "v1")===eventVersion) {
88
89
  const obj = this.listeners[swap.getType()];
89
90
  if(obj==null) continue;
90
91
  await obj.listener(event, swap);
@@ -124,8 +125,9 @@ export class UnifiedSwapEventListener<
124
125
 
125
126
  for(let claimData in htlcCheckInitializeEvents) {
126
127
  const event = htlcCheckInitializeEvents[claimData];
128
+ const eventVersion = event.contractVersion ?? "v1";
127
129
  const swap = swapsByClaimDataHash[claimData];
128
- if(swap!=null) {
130
+ if(swap!=null && (swap._contractVersion ?? "v1")===eventVersion) {
129
131
  const obj = this.listeners[swap.getType()];
130
132
  if(obj==null) continue;
131
133
  await obj.listener(event, swap);
@@ -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,
@@ -55,6 +55,10 @@ export class Intermediary {
55
55
  * Addresses of the intermediary on smart chains, used for checking the provided signatures
56
56
  */
57
57
  readonly addresses: {[chainIdentifier: string]: string};
58
+ /**
59
+ * Contract versions of the intermediary on smart chains
60
+ */
61
+ readonly contractVersions: {[chainIdentifier: string]: string};
58
62
  /**
59
63
  * Swap protocol services offered by the intermediary
60
64
  */
@@ -99,12 +103,14 @@ export class Intermediary {
99
103
  url: string,
100
104
  addresses: {[chainIdentifier: string]: string},
101
105
  services: ServicesType,
102
- reputation: { [chainIdentifier: string]: SingleChainReputationType } = {}
106
+ reputation: { [chainIdentifier: string]: SingleChainReputationType } = {},
107
+ contractVersions: {[chainIdentifier: string]: string} = {},
103
108
  ) {
104
109
  this.url = url;
105
110
  this.addresses = addresses;
106
111
  this.services = services;
107
112
  this.reputation = reputation;
113
+ this.contractVersions = contractVersions;
108
114
 
109
115
  this.swapBounds = {};
110
116
  for(let _swapType in this.services) {
@@ -247,4 +253,28 @@ export class Intermediary {
247
253
  return this.addresses[chainIdentifier];
248
254
  }
249
255
 
256
+ /**
257
+ * Returns the contract version used by the intermediary for a given chain
258
+ *
259
+ * @param chainIdentifier
260
+ */
261
+ getContractVersion(chainIdentifier: string): string {
262
+ return this.contractVersions[chainIdentifier] ?? "v1";
263
+ }
264
+
265
+ /**
266
+ * Returns the range of contract versions used by the LPs
267
+ *
268
+ * @param chainIdentifier
269
+ * @param lps
270
+ */
271
+ static getContractVersionsForLps(chainIdentifier: string, lps: Intermediary[]): string[] {
272
+ const versions: string[] = [];
273
+ lps.forEach((lp) => {
274
+ const lpVersion = lp.getContractVersion(chainIdentifier);
275
+ if(!versions.includes(lpVersion)) versions.push(lpVersion);
276
+ });
277
+ return versions;
278
+ }
279
+
250
280
  }