@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
@@ -34,46 +34,68 @@ export abstract class IEscrowSwapWrapper<
34
34
  /**
35
35
  * @internal
36
36
  */
37
- readonly _contract: T["Contract"];
37
+ readonly _contract: (version?: string) => T["Contract"] = (version?: string) => {
38
+ const _version = version ?? "v1";
39
+ const data = this._versionedContracts[_version];
40
+ if(data==null) throw new Error(`Invalid contract version ${_version} requested`);
41
+ return data.swapContract;
42
+ };
38
43
  /**
39
44
  * @internal
40
45
  */
41
- readonly _swapDataDeserializer: new (data: any) => T["Data"];
46
+ readonly _swapDataDeserializer: (version?: string) => new (data: any) => T["Data"] = (version?: string) => {
47
+ const _version = version ?? "v1";
48
+ const data = this._versionedContracts[_version];
49
+ if(data==null) throw new Error(`Invalid contract version ${_version} requested`);
50
+ return data.swapDataConstructor;
51
+ };
52
+
53
+ //TODO: Properly populate in constructor
54
+ readonly _versionedContracts: {
55
+ [version: string]: {
56
+ swapContract: T["Contract"],
57
+ swapDataConstructor: new (data: any) => T["Data"]
58
+ }
59
+ } = {};
42
60
 
43
61
  constructor(
44
62
  chainIdentifier: string,
45
63
  unifiedStorage: UnifiedSwapStorage<T>,
46
64
  unifiedChainEvents: UnifiedSwapEventListener<T>,
47
65
  chain: T["ChainInterface"],
48
- contract: T["Contract"],
49
66
  prices: ISwapPrice,
50
67
  tokens: WrapperCtorTokens,
51
- swapDataDeserializer: new (data: any) => T["Data"],
52
68
  options: O,
69
+ versionedContracts: {
70
+ [version: string]: {
71
+ swapContract: T["Contract"],
72
+ swapDataConstructor: new (data: any) => T["Data"]
73
+ }
74
+ },
53
75
  events?: EventEmitter<{swapState: [ISwap]}>
54
76
  ) {
55
77
  super(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, options, events);
56
- this._swapDataDeserializer = swapDataDeserializer;
57
- this._contract = contract;
78
+ this._versionedContracts = versionedContracts;
58
79
  }
59
80
 
60
81
  /**
61
82
  * Pre-fetches signature verification data from the server's pre-sent promise, doesn't throw, instead returns null
62
83
  *
63
84
  * @param signDataPrefetch Promise that resolves when we receive "signDataPrefetch" from the LP in streaming mode
85
+ * @param contractVersion
64
86
  * @returns Pre-fetched signature verification data or null if failed
65
87
  *
66
88
  * @internal
67
89
  */
68
- protected preFetchSignData(signDataPrefetch: Promise<any | null>): Promise<T["PreFetchVerification"] | undefined> {
69
- if(this._contract.preFetchForInitSignatureVerification==null) {
90
+ protected preFetchSignData(signDataPrefetch: Promise<any | null>, contractVersion: string): Promise<T["PreFetchVerification"] | undefined> {
91
+ if(this._contract(contractVersion).preFetchForInitSignatureVerification==null) {
70
92
  // Catch promise rejections, should they happen
71
93
  signDataPrefetch.catch(() => {});
72
94
  return Promise.resolve(undefined);
73
95
  }
74
96
  return signDataPrefetch.then(obj => {
75
97
  if(obj==null) return undefined;
76
- return this._contract.preFetchForInitSignatureVerification!(obj);
98
+ return this._contract(contractVersion).preFetchForInitSignatureVerification!(obj);
77
99
  }).catch(e => {
78
100
  this.logger.error("preFetchSignData(): Error: ", e);
79
101
  });
@@ -87,6 +109,7 @@ export abstract class IEscrowSwapWrapper<
87
109
  * @param signature Response of the intermediary
88
110
  * @param feeRatePromise Pre-fetched fee rate promise
89
111
  * @param preFetchSignatureVerificationData Pre-fetched signature verification data
112
+ * @param contractVersion
90
113
  * @param abortSignal
91
114
  * @returns Swap initialization signature expiry
92
115
  * @throws {SignatureVerificationError} when swap init signature is invalid
@@ -99,11 +122,12 @@ export abstract class IEscrowSwapWrapper<
99
122
  signature: SignatureData,
100
123
  feeRatePromise: Promise<any>,
101
124
  preFetchSignatureVerificationData: Promise<any>,
102
- abortSignal?: AbortSignal
125
+ contractVersion: string,
126
+ abortSignal?: AbortSignal,
103
127
  ): Promise<number> {
104
128
  const [feeRate, preFetchedSignatureData] = await Promise.all([feeRatePromise, preFetchSignatureVerificationData]);
105
- await this._contract.isValidInitAuthorization(initiator, data, signature, feeRate, preFetchedSignatureData);
106
- return await this._contract.getInitAuthorizationExpiry(data, signature, preFetchedSignatureData);
129
+ await this._contract(contractVersion).isValidInitAuthorization(initiator, data, signature, feeRate, preFetchedSignatureData);
130
+ return await this._contract(contractVersion).getInitAuthorizationExpiry(data, signature, preFetchedSignatureData);
107
131
  }
108
132
 
109
133
  /**
@@ -186,7 +210,7 @@ export abstract class IEscrowSwapWrapper<
186
210
 
187
211
  const swapExpiredStatus: {[id: string]: boolean} = {};
188
212
 
189
- const checkStatusSwaps: (D["Swap"] & {_data: T["Data"]})[] = [];
213
+ const checkStatusSwaps: {[contractVersion: string]: (D["Swap"] & {_data: T["Data"]})[]} = {};
190
214
 
191
215
  for(let pastSwap of pastSwaps) {
192
216
  if(pastSwap._shouldFetchExpiryStatus()) {
@@ -195,24 +219,37 @@ export abstract class IEscrowSwapWrapper<
195
219
  }
196
220
  if(pastSwap._shouldFetchOnchainState()) {
197
221
  //Add to swaps for which status should be checked
198
- if(pastSwap._data!=null) checkStatusSwaps.push(pastSwap as (D["Swap"] & {_data: T["Data"]}));
222
+ if(pastSwap._data!=null) (checkStatusSwaps[pastSwap._contractVersion ?? "v1"] ??= []).push(pastSwap as (D["Swap"] & {_data: T["Data"]}));
199
223
  }
200
224
  }
201
225
 
202
- const swapStatuses = await this._contract.getCommitStatuses(checkStatusSwaps.map(val => ({signer: val._getInitiator(), swapData: val._data})));
226
+ for(let version in checkStatusSwaps) {
227
+ if(this._versionedContracts[version]==null) {
228
+ this.logger.warn(`_checkPastSwaps(): No contract was found for ${this.chainIdentifier} version ${version}! Skipping these swaps!`);
229
+ continue;
230
+ }
203
231
 
204
- for(let pastSwap of checkStatusSwaps) {
205
- const escrowHash = pastSwap.getEscrowHash();
206
- const shouldSave = await pastSwap._sync(
207
- false,
208
- swapExpiredStatus[pastSwap.getId()],
209
- escrowHash==null ? undefined : swapStatuses[escrowHash]
232
+ const _checkStatusSwap = checkStatusSwaps[version];
233
+ const swapStatuses = await this._contract(version).getCommitStatuses(
234
+ _checkStatusSwap.map(val => ({
235
+ signer: val._getInitiator(),
236
+ swapData: val._data
237
+ }))
210
238
  );
211
- if(shouldSave) {
212
- if(pastSwap.isQuoteExpired()) {
213
- removeSwaps.push(pastSwap);
214
- } else {
215
- changedSwaps.push(pastSwap);
239
+
240
+ for(let pastSwap of _checkStatusSwap) {
241
+ const escrowHash = pastSwap.getEscrowHash();
242
+ const shouldSave = await pastSwap._sync(
243
+ false,
244
+ swapExpiredStatus[pastSwap.getId()],
245
+ escrowHash==null ? undefined : swapStatuses[escrowHash]
246
+ );
247
+ if(shouldSave) {
248
+ if(pastSwap.isQuoteExpired()) {
249
+ removeSwaps.push(pastSwap);
250
+ } else {
251
+ changedSwaps.push(pastSwap);
252
+ }
216
253
  }
217
254
  }
218
255
  }
@@ -239,6 +276,7 @@ export abstract class IEscrowSwapWrapper<
239
276
  getTxBlock: () => Promise<{blockTime: number, blockHeight: number}>
240
277
  },
241
278
  state: SwapCommitState,
279
+ contractVersion: string,
242
280
  lp?: Intermediary
243
281
  ): Promise<D["Swap"] | null>;
244
282
 
@@ -38,10 +38,9 @@ export abstract class IFromBTCLNWrapper<
38
38
  * @param unifiedStorage Storage interface for the current environment
39
39
  * @param unifiedChainEvents On-chain event listener
40
40
  * @param chain
41
- * @param contract Underlying contract handling the swaps
42
41
  * @param prices Swap pricing handler
43
42
  * @param tokens
44
- * @param swapDataDeserializer Deserializer for SwapData
43
+ * @param versionedContracts
45
44
  * @param lnApi
46
45
  * @param options
47
46
  * @param events Instance to use for emitting events
@@ -51,15 +50,19 @@ export abstract class IFromBTCLNWrapper<
51
50
  unifiedStorage: UnifiedSwapStorage<T>,
52
51
  unifiedChainEvents: UnifiedSwapEventListener<T>,
53
52
  chain: T["ChainInterface"],
54
- contract: T["Contract"],
55
53
  prices: ISwapPrice,
56
54
  tokens: WrapperCtorTokens,
57
- swapDataDeserializer: new (data: any) => T["Data"],
55
+ versionedContracts: {
56
+ [version: string]: {
57
+ swapContract: T["Contract"],
58
+ swapDataConstructor: new (data: any) => T["Data"]
59
+ }
60
+ },
58
61
  lnApi: LightningNetworkApi,
59
62
  options: O,
60
63
  events?: EventEmitter<{swapState: [IEscrowSwap]}>
61
64
  ) {
62
- super(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, swapDataDeserializer, options, events);
65
+ super(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, options, versionedContracts, events);
63
66
  this.lnApi = lnApi;
64
67
  }
65
68
 
@@ -196,7 +196,7 @@ export abstract class IFromBTCSelfInitSwap<
196
196
  required: TokenAmount<SCToken<T["ChainId"]>, true>
197
197
  }> {
198
198
  const [balance, commitFee] = await Promise.all([
199
- this.wrapper._contract.getBalance(this._getInitiator(), this.wrapper._chain.getNativeCurrencyAddress(), false),
199
+ this._contract.getBalance(this._getInitiator(), this.wrapper._chain.getNativeCurrencyAddress(), false),
200
200
  this.getCommitFee()
201
201
  ]);
202
202
  const totalFee = commitFee + this.getSwapData().getTotalDeposit();
@@ -247,7 +247,7 @@ export abstract class IFromBTCSelfInitSwap<
247
247
  await this._saveAndEmit();
248
248
  }
249
249
 
250
- return await this.wrapper._contract.txsInit(
250
+ return await this._contract.txsInit(
251
251
  this._getInitiator(), this._data, this.signatureData, skipChecks, this.feeRate
252
252
  ).catch(e => Promise.reject(e instanceof SignatureVerificationError ? new Error("Request timed out") : e));
253
253
  }
@@ -274,7 +274,7 @@ export abstract class IFromBTCSelfInitSwap<
274
274
  * smart chain
275
275
  */
276
276
  async getClaimNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>> {
277
- const swapContract: T["Contract"] = this.wrapper._contract;
277
+ const swapContract: T["Contract"] = this._contract;
278
278
  return toTokenAmount(
279
279
  await swapContract.getClaimFee(this._getInitiator(), this.getSwapData()),
280
280
  this.wrapper._getNativeToken(),
@@ -1,7 +1,7 @@
1
1
  import {ISwapWrapperOptions} from "../../ISwapWrapper";
2
2
  import {Intermediary} from "../../../intermediaries/Intermediary";
3
3
  import {IntermediaryError} from "../../../errors/IntermediaryError";
4
- import {randomBytes} from "../../../utils/Utils";
4
+ import {mapArrayToObject, randomBytes} from "../../../utils/Utils";
5
5
  import {BigIntBufferUtils, ChainType} from "@atomiqlabs/base";
6
6
  import {IEscrowSwapDefinition, IEscrowSwapWrapper} from "../IEscrowSwapWrapper";
7
7
  import {IEscrowSwap} from "../IEscrowSwap";
@@ -39,6 +39,7 @@ export abstract class IFromBTCWrapper<
39
39
  * @param claimHash optional claim hash of the swap or null
40
40
  * @param abortController
41
41
  *
42
+ * @param contractVersions
42
43
  * @returns Fee rate
43
44
  *
44
45
  * @internal
@@ -46,15 +47,18 @@ export abstract class IFromBTCWrapper<
46
47
  protected preFetchFeeRate(
47
48
  signer: string,
48
49
  amountData: AmountData,
49
- claimHash: string | undefined,
50
- abortController: AbortController
51
- ): Promise<string | undefined> {
52
- return this._contract.getInitFeeRate(this._chain.randomAddress(), signer, amountData.token, claimHash)
53
- .catch(e => {
54
- this.logger.warn("preFetchFeeRate(): Error: ", e);
55
- abortController.abort(e);
56
- return undefined;
57
- });
50
+ claimHash: {[contractVersion: string]: string} | undefined,
51
+ abortController: AbortController,
52
+ contractVersions: string[]
53
+ ): {[contractVersion: string]: Promise<string | undefined>} {
54
+ return mapArrayToObject(contractVersions, (contractVersion) => {
55
+ return this._contract(contractVersion).getInitFeeRate(this._chain.randomAddress(), signer, amountData.token, claimHash?.[contractVersion])
56
+ .catch(e => {
57
+ this.logger.warn("preFetchFeeRate(): Error: ", e);
58
+ abortController.abort(e);
59
+ return undefined;
60
+ });
61
+ });
58
62
  }
59
63
 
60
64
  /**
@@ -64,12 +68,18 @@ export abstract class IFromBTCWrapper<
64
68
  * @param lp Intermediary
65
69
  * @param abortController
66
70
  *
71
+ * @param contractVersion
67
72
  * @returns Intermediary's liquidity balance
68
73
  *
69
74
  * @internal
70
75
  */
71
- protected preFetchIntermediaryLiquidity(amountData: AmountData, lp: Intermediary, abortController: AbortController): Promise<bigint | undefined> {
72
- return lp.getLiquidity(this.chainIdentifier, this._contract, amountData.token.toString(), abortController.signal).catch(e => {
76
+ protected preFetchIntermediaryLiquidity(
77
+ amountData: AmountData,
78
+ lp: Intermediary,
79
+ abortController: AbortController,
80
+ contractVersion: string
81
+ ): Promise<bigint | undefined> {
82
+ return lp.getLiquidity(this.chainIdentifier, this._contract(contractVersion), amountData.token.toString(), abortController.signal).catch(e => {
73
83
  this.logger.warn("preFetchIntermediaryLiquidity(): Error: ", e);
74
84
  abortController.abort(e);
75
85
  return undefined;
@@ -474,16 +474,16 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
474
474
  required: TokenAmount<SCToken<T["ChainId"]>, true>
475
475
  }> {
476
476
  const [balance, feeRate] = await Promise.all([
477
- this.wrapper._contract.getBalance(this._getInitiator(), this.wrapper._chain.getNativeCurrencyAddress(), false),
478
- this.feeRate!=null ? Promise.resolve<string>(this.feeRate) : this.wrapper._contract.getInitFeeRate(
477
+ this._contract.getBalance(this._getInitiator(), this.wrapper._chain.getNativeCurrencyAddress(), false),
478
+ this.feeRate!=null ? Promise.resolve<string>(this.feeRate) : this._contract.getInitFeeRate(
479
479
  this.getSwapData().getOfferer(),
480
480
  this.getSwapData().getClaimer(),
481
481
  this.getSwapData().getToken(),
482
482
  this.getSwapData().getClaimHash()
483
483
  )
484
484
  ]);
485
- const commitFee = await this.wrapper._contract.getCommitFee(this._getInitiator(), this.getSwapData(), feeRate);
486
- const claimFee = await this.wrapper._contract.getClaimFee(this._getInitiator(), this.getSwapData(), feeRate);
485
+ const commitFee = await this._contract.getCommitFee(this._getInitiator(), this.getSwapData(), feeRate);
486
+ const claimFee = await this._contract.getClaimFee(this._getInitiator(), this.getSwapData(), feeRate);
487
487
  const totalFee = commitFee + claimFee + this.getSwapData().getTotalDeposit();
488
488
  return {
489
489
  enoughBalance: balance >= totalFee,
@@ -494,7 +494,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
494
494
 
495
495
  private isValidSecretPreimage(secret: string) {
496
496
  const paymentHash = Buffer.from(sha256(Buffer.from(secret, "hex")));
497
- const claimHash = this.wrapper._contract.getHashForHtlc(paymentHash).toString("hex");
497
+ const claimHash = this._contract.getHashForHtlc(paymentHash).toString("hex");
498
498
  return this.getSwapData().getClaimHash()===claimHash;
499
499
  }
500
500
 
@@ -716,10 +716,10 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
716
716
  const resp = await IntermediaryAPI.getPaymentAuthorization(this.url, paymentHash.toString("hex"));
717
717
  switch(resp.code) {
718
718
  case PaymentAuthorizationResponseCodes.AUTH_DATA:
719
- const data = new this.wrapper._swapDataDeserializer(resp.data.data);
719
+ const data = new (this.wrapper._swapDataDeserializer(this._contractVersion))(resp.data.data);
720
720
  try {
721
721
  await this.checkIntermediaryReturnedAuthData(this._getInitiator(), data, resp.data);
722
- this.expiry = await this.wrapper._contract.getInitAuthorizationExpiry(
722
+ this.expiry = await this._contract.getInitAuthorizationExpiry(
723
723
  data,
724
724
  resp.data
725
725
  );
@@ -773,8 +773,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
773
773
  if (data.hasSuccessAction()) throw new IntermediaryError("Invalid has success action");
774
774
 
775
775
  await Promise.all([
776
- this.wrapper._contract.isValidInitAuthorization(this._getInitiator(), data, signature, this.feeRate),
777
- this.wrapper._contract.getCommitStatus(data.getClaimer(), data)
776
+ this._contract.isValidInitAuthorization(this._getInitiator(), data, signature, this.feeRate),
777
+ this._contract.getCommitStatus(data.getClaimer(), data)
778
778
  .then(status => {
779
779
  if (status?.type !== SwapCommitStateType.NOT_COMMITED)
780
780
  throw new Error("Swap already committed on-chain!");
@@ -846,9 +846,9 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
846
846
 
847
847
  if(resp.code===PaymentAuthorizationResponseCodes.AUTH_DATA) {
848
848
  const sigData = resp.data;
849
- const swapData = new this.wrapper._swapDataDeserializer(resp.data.data);
849
+ const swapData = new (this.wrapper._swapDataDeserializer(this._contractVersion))(resp.data.data);
850
850
  await this.checkIntermediaryReturnedAuthData(this._getInitiator(), swapData, sigData);
851
- this.expiry = await this.wrapper._contract.getInitAuthorizationExpiry(
851
+ this.expiry = await this._contract.getInitAuthorizationExpiry(
852
852
  swapData,
853
853
  sigData
854
854
  );
@@ -972,7 +972,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
972
972
  if(!this.isValidSecretPreimage(useSecret))
973
973
  throw new Error("Invalid swap secret pre-image provided!");
974
974
 
975
- return this.wrapper._contract.txsClaimWithSecret(
975
+ return this._contract.txsClaimWithSecret(
976
976
  address ?? this._getInitiator(),
977
977
  this._data, useSecret, true, true
978
978
  );
@@ -1092,7 +1092,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1092
1092
  * to settle the swap on the smart chain destination side.
1093
1093
  */
1094
1094
  async getCommitAndClaimNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>> {
1095
- const swapContract: T["Contract"] = this.wrapper._contract;
1095
+ const swapContract: T["Contract"] = this._contract;
1096
1096
  const feeRate = this.feeRate ?? await swapContract.getInitFeeRate(
1097
1097
  this.getSwapData().getOfferer(),
1098
1098
  this.getSwapData().getClaimer(),
@@ -1123,7 +1123,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1123
1123
  * call {@link commit} first and then {@link claim}.
1124
1124
  */
1125
1125
  canCommitAndClaimInOneShot(): boolean {
1126
- return this.wrapper._contract.initAndClaimWithSecret!=null;
1126
+ return this._contract.initAndClaimWithSecret!=null;
1127
1127
  }
1128
1128
 
1129
1129
  /**
@@ -1154,7 +1154,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1154
1154
  throw new Error("Invalid swap secret pre-image provided!");
1155
1155
 
1156
1156
  const initTxs = await this.txsCommit(skipChecks);
1157
- const claimTxs = await this.wrapper._contract.txsClaimWithSecret(
1157
+ const claimTxs = await this._contract.txsClaimWithSecret(
1158
1158
  this._getInitiator(), this._data, useSecret,
1159
1159
  true, true, undefined,
1160
1160
  true
@@ -1311,7 +1311,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1311
1311
  }
1312
1312
 
1313
1313
  //Check if it's already successfully paid
1314
- commitStatus ??= await this.wrapper._contract.getCommitStatus(this._getInitiator(), this._data!);
1314
+ commitStatus ??= await this._contract.getCommitStatus(this._getInitiator(), this._data!);
1315
1315
  if(commitStatus!=null && await this._forciblySetOnchainState(commitStatus)) return true;
1316
1316
 
1317
1317
  //Set the state on expiry here
@@ -1382,7 +1382,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1382
1382
  if(await this.syncStateFromChain(quoteDefinitelyExpired, commitStatus)) changed = true;
1383
1383
 
1384
1384
  if(this._state===FromBTCLNSwapState.CLAIM_COMMITED) {
1385
- const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data!);
1385
+ const expired = await this._contract.isExpired(this._getInitiator(), this._data!);
1386
1386
  if(expired) {
1387
1387
  this._state = FromBTCLNSwapState.EXPIRED;
1388
1388
  changed = true;
@@ -1447,7 +1447,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1447
1447
  }
1448
1448
  break;
1449
1449
  case FromBTCLNSwapState.CLAIM_COMMITED:
1450
- const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data!);
1450
+ const expired = await this._contract.isExpired(this._getInitiator(), this._data!);
1451
1451
  if(expired) {
1452
1452
  this._state = FromBTCLNSwapState.EXPIRED;
1453
1453
  if(save) await this._saveAndEmit();
@@ -13,7 +13,7 @@ import {UserError} from "../../../../errors/UserError";
13
13
  import {IntermediaryError} from "../../../../errors/IntermediaryError";
14
14
  import {SwapType} from "../../../../enums/SwapType";
15
15
  import {
16
- extendAbortController, parseHashValueExact32Bytes,
16
+ extendAbortController, mapArrayToObject, parseHashValueExact32Bytes,
17
17
  throwIfUndefined
18
18
  } from "../../../../utils/Utils";
19
19
  import {FromBTCLNResponseType, IntermediaryAPI} from "../../../../intermediaries/apis/IntermediaryAPI";
@@ -113,10 +113,9 @@ export class FromBTCLNWrapper<
113
113
  * @param unifiedStorage Storage interface for the current environment
114
114
  * @param unifiedChainEvents On-chain event listener
115
115
  * @param chain
116
- * @param contract Underlying contract handling the swaps
117
116
  * @param prices Swap pricing handler
118
117
  * @param tokens
119
- * @param swapDataDeserializer Deserializer for SwapData
118
+ * @param versionedContracts
120
119
  * @param lnApi
121
120
  * @param options
122
121
  * @param events Instance to use for emitting events
@@ -126,16 +125,20 @@ export class FromBTCLNWrapper<
126
125
  unifiedStorage: UnifiedSwapStorage<T>,
127
126
  unifiedChainEvents: UnifiedSwapEventListener<T>,
128
127
  chain: T["ChainInterface"],
129
- contract: T["Contract"],
130
128
  prices: ISwapPrice,
131
129
  tokens: WrapperCtorTokens,
132
- swapDataDeserializer: new (data: any) => T["Data"],
130
+ versionedContracts: {
131
+ [version: string]: {
132
+ swapContract: T["Contract"],
133
+ swapDataConstructor: new (data: any) => T["Data"]
134
+ }
135
+ },
133
136
  lnApi: LightningNetworkApi,
134
137
  options?: AllOptional<FromBTCLNWrapperOptions>,
135
138
  events?: EventEmitter<{swapState: [ISwap]}>
136
139
  ) {
137
140
  super(
138
- chainIdentifier, unifiedStorage, unifiedChainEvents, chain, contract, prices, tokens, swapDataDeserializer, lnApi,
141
+ chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, versionedContracts, lnApi,
139
142
  {
140
143
  ...options,
141
144
  safetyFactor: options?.safetyFactor ?? 2,
@@ -254,8 +257,8 @@ export class FromBTCLNWrapper<
254
257
  abortSignal?: AbortSignal,
255
258
  preFetches?: {
256
259
  usdPricePrefetchPromise: Promise<number | undefined>,
257
- pricePrefetchPromise?: Promise<bigint | undefined>,
258
- feeRatePromise?: Promise<string | undefined>
260
+ pricePrefetchPromise: Promise<bigint | undefined>,
261
+ feeRatePromise: {[contractVersion: string]: Promise<string | undefined>},
259
262
  }
260
263
  ): {
261
264
  quote: Promise<FromBTCLNSwap<T>>,
@@ -273,6 +276,8 @@ export class FromBTCLNWrapper<
273
276
  if(_options.description!=null && Buffer.byteLength(_options.description, "utf8") > 500)
274
277
  throw new UserError("Invalid description length");
275
278
 
279
+ const lpVersions = Intermediary.getContractVersionsForLps(this.chainIdentifier, lps);
280
+
276
281
  let secret: Buffer | undefined;
277
282
  let paymentHash: Buffer;
278
283
  if(_options.paymentHash!=null) {
@@ -280,15 +285,17 @@ export class FromBTCLNWrapper<
280
285
  } else {
281
286
  ({secret, paymentHash} = this.getSecretAndHash());
282
287
  }
283
- const claimHash = this._contract.getHashForHtlc(paymentHash);
288
+ const _hash = mapArrayToObject(lpVersions, (contractVersion: string) => {
289
+ return this._contract(contractVersion).getHashForHtlc(paymentHash).toString("hex");
290
+ });
284
291
 
285
292
  const nativeTokenAddress = this._chain.getNativeCurrencyAddress();
286
293
 
287
294
  const _abortController = extendAbortController(abortSignal);
288
- const _preFetches = {
289
- pricePrefetchPromise: preFetches?.pricePrefetchPromise ?? this.preFetchPrice(amountData, _abortController.signal),
290
- feeRatePromise: preFetches?.feeRatePromise ?? this.preFetchFeeRate(recipient, amountData, claimHash.toString("hex"), _abortController),
291
- usdPricePrefetchPromise: preFetches?.usdPricePrefetchPromise ?? this.preFetchUsdPrice(_abortController.signal),
295
+ const _preFetches = preFetches ?? {
296
+ pricePrefetchPromise: this.preFetchPrice(amountData, _abortController.signal),
297
+ feeRatePromise: this.preFetchFeeRate(recipient, amountData, _hash, _abortController, lpVersions),
298
+ usdPricePrefetchPromise: this.preFetchUsdPrice(_abortController.signal),
292
299
  }
293
300
 
294
301
  return lps.map(lp => {
@@ -296,10 +303,11 @@ export class FromBTCLNWrapper<
296
303
  intermediary: lp,
297
304
  quote: (async () => {
298
305
  if(lp.services[SwapType.FROM_BTCLN]==null) throw new Error("LP service for processing from btcln swaps not found!");
306
+ const version = lp.getContractVersion(this.chainIdentifier);
299
307
 
300
308
  const abortController = extendAbortController(_abortController.signal);
301
309
 
302
- const liquidityPromise: Promise<bigint | undefined> = this.preFetchIntermediaryLiquidity(amountData, lp, abortController);
310
+ const liquidityPromise: Promise<bigint | undefined> = this.preFetchIntermediaryLiquidity(amountData, lp, abortController, version);
303
311
 
304
312
  const {lnCapacityPromise, resp} = await tryWithRetries(async(retryCount: number) => {
305
313
  const {lnPublicKey, response} = IntermediaryAPI.initFromBTCLN(
@@ -312,7 +320,7 @@ export class FromBTCLNWrapper<
312
320
  description: _options.description,
313
321
  descriptionHash: _options.descriptionHash,
314
322
  exactOut: !amountData.exactIn,
315
- feeRate: throwIfUndefined(_preFetches.feeRatePromise),
323
+ feeRate: throwIfUndefined(_preFetches.feeRatePromise[version]),
316
324
  additionalParams
317
325
  },
318
326
  this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined
@@ -351,16 +359,17 @@ export class FromBTCLNWrapper<
351
359
  expiry: decodedPr.timeExpireDate*1000,
352
360
  swapFee: resp.swapFee,
353
361
  swapFeeBtc: resp.swapFee * amountIn / (resp.total - resp.swapFee),
354
- feeRate: (await _preFetches.feeRatePromise)!,
355
- initialSwapData: await this._contract.createSwapData(
362
+ feeRate: (await _preFetches.feeRatePromise[version])!,
363
+ initialSwapData: await this._contract(version).createSwapData(
356
364
  ChainSwapType.HTLC, lp.getAddress(this.chainIdentifier), recipient, amountData.token,
357
- resp.total, claimHash.toString("hex"),
365
+ resp.total, _hash[version],
358
366
  this.getRandomSequence(), BigInt(Math.floor(Date.now()/1000)), false, true,
359
367
  resp.securityDeposit, 0n, nativeTokenAddress
360
368
  ),
361
369
  pr: resp.pr,
362
370
  secret: secret?.toString("hex"),
363
- exactIn: amountData.exactIn ?? true
371
+ exactIn: amountData.exactIn ?? true,
372
+ contractVersion: version
364
373
  } as FromBTCLNSwapInit<T["Data"]>);
365
374
  return quote;
366
375
  } catch (e) {
@@ -408,11 +417,13 @@ export class FromBTCLNWrapper<
408
417
  unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? this._options.unsafeSkipLnNodeCheck
409
418
  };
410
419
 
420
+ const lpVersions = Intermediary.getContractVersionsForLps(this.chainIdentifier, lps);
421
+
411
422
  const abortController = extendAbortController(abortSignal);
412
423
  const preFetches = {
413
424
  pricePrefetchPromise: this.preFetchPrice(amountData, abortController.signal),
414
425
  usdPricePrefetchPromise: this.preFetchUsdPrice(abortController.signal),
415
- feeRatePromise: this.preFetchFeeRate(recipient, amountData, undefined, abortController)
426
+ feeRatePromise: this.preFetchFeeRate(recipient, amountData, undefined, abortController, lpVersions)
416
427
  };
417
428
 
418
429
  try {
@@ -474,7 +485,7 @@ export class FromBTCLNWrapper<
474
485
  const changedSwapSet: Set<FromBTCLNSwap<T>> = new Set();
475
486
 
476
487
  const swapExpiredStatus: {[id: string]: boolean} = {};
477
- const checkStatusSwaps: (FromBTCLNSwap<T> & {_data: T["Data"]})[] = [];
488
+ const checkStatusSwaps: {[contractVersion: string]: (FromBTCLNSwap<T> & {_data: T["Data"]})[]} = {};
478
489
 
479
490
  await Promise.all(pastSwaps.map(async (pastSwap) => {
480
491
  if(pastSwap._shouldCheckIntermediary()) {
@@ -493,19 +504,27 @@ export class FromBTCLNWrapper<
493
504
  }
494
505
  if(pastSwap._shouldFetchOnchainState()) {
495
506
  //Add to swaps for which status should be checked
496
- if(pastSwap._data!=null) checkStatusSwaps.push(pastSwap as (FromBTCLNSwap<T> & {_data: T["Data"]}));
507
+ if(pastSwap._data!=null) (checkStatusSwaps[pastSwap._contractVersion ?? "v1"] ??= []).push(pastSwap as (FromBTCLNSwap<T> & {_data: T["Data"]}));
497
508
  }
498
509
  }));
499
510
 
500
- const swapStatuses = await this._contract.getCommitStatuses(checkStatusSwaps.map(val => ({signer: val._getInitiator(), swapData: val._data})));
511
+ for(let version in checkStatusSwaps) {
512
+ if(this._versionedContracts[version]==null) {
513
+ this.logger.warn(`_checkPastSwaps(): No contract was found for ${this.chainIdentifier} version ${version}! Skipping these swaps!`);
514
+ continue;
515
+ }
516
+
517
+ const _checkStatusSwap = checkStatusSwaps[version];
518
+ const swapStatuses = await this._contract(version).getCommitStatuses(_checkStatusSwap.map(val => ({signer: val._getInitiator(), swapData: val._data})));
501
519
 
502
- for(let pastSwap of checkStatusSwaps) {
503
- const shouldSave = await pastSwap._sync(
504
- false, swapExpiredStatus[pastSwap.getId()],
505
- swapStatuses[pastSwap.getEscrowHash()!], true
506
- );
507
- if(shouldSave) {
508
- changedSwapSet.add(pastSwap);
520
+ for(let pastSwap of _checkStatusSwap) {
521
+ const shouldSave = await pastSwap._sync(
522
+ false, swapExpiredStatus[pastSwap.getId()],
523
+ swapStatuses[pastSwap.getEscrowHash()!], true
524
+ );
525
+ if(shouldSave) {
526
+ changedSwapSet.add(pastSwap);
527
+ }
509
528
  }
510
529
  }
511
530
 
@@ -532,6 +551,7 @@ export class FromBTCLNWrapper<
532
551
  async recoverFromSwapDataAndState(
533
552
  init: {data: T["Data"], getInitTxId: () => Promise<string>, getTxBlock: () => Promise<{blockTime: number, blockHeight: number}>},
534
553
  state: SwapCommitState,
554
+ contractVersion: string,
535
555
  lp?: Intermediary
536
556
  ): Promise<FromBTCLNSwap<T> | null> {
537
557
  const data = init.data;
@@ -562,7 +582,8 @@ export class FromBTCLNWrapper<
562
582
  data,
563
583
  pr: paymentHash ?? undefined,
564
584
  secret,
565
- exactIn: false
585
+ exactIn: false,
586
+ contractVersion
566
587
  }
567
588
  const swap = new FromBTCLNSwap(this, swapInit);
568
589
  swap._commitTxId = await init.getInitTxId();