@atomiqlabs/sdk 8.6.3 → 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 (78) hide show
  1. package/dist/events/UnifiedSwapEventListener.js +4 -2
  2. package/dist/intermediaries/Intermediary.d.ts +21 -0
  3. package/dist/intermediaries/Intermediary.js +25 -1
  4. package/dist/intermediaries/IntermediaryDiscovery.d.ts +15 -3
  5. package/dist/intermediaries/IntermediaryDiscovery.js +21 -3
  6. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +1 -0
  7. package/dist/swapper/Swapper.d.ts +9 -4
  8. package/dist/swapper/Swapper.js +89 -41
  9. package/dist/swapper/SwapperUtils.js +2 -1
  10. package/dist/swaps/ISwap.d.ts +5 -0
  11. package/dist/swaps/ISwap.js +4 -1
  12. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +5 -5
  13. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +4 -0
  14. package/dist/swaps/escrow_swaps/IEscrowSwap.js +4 -3
  15. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +19 -6
  16. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +54 -21
  17. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +7 -3
  18. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +3 -4
  19. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +3 -3
  20. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +8 -2
  21. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +12 -8
  22. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +18 -18
  23. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +12 -6
  24. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +38 -24
  25. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +9 -9
  26. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +14 -7
  27. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +54 -38
  28. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +5 -5
  29. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +18 -7
  30. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +61 -33
  31. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +12 -12
  32. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +8 -2
  33. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +13 -8
  34. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +1 -1
  35. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +13 -4
  36. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +44 -28
  37. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +2 -2
  38. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +8 -4
  39. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +29 -21
  40. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +1 -0
  41. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +13 -12
  42. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +21 -10
  43. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +136 -73
  44. package/dist/swaps/trusted/ln/LnForGasWrapper.js +2 -1
  45. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +2 -1
  46. package/dist/utils/Utils.d.ts +9 -0
  47. package/dist/utils/Utils.js +15 -1
  48. package/package.json +2 -2
  49. package/src/events/UnifiedSwapEventListener.ts +4 -2
  50. package/src/intermediaries/Intermediary.ts +31 -1
  51. package/src/intermediaries/IntermediaryDiscovery.ts +27 -8
  52. package/src/intermediaries/apis/IntermediaryAPI.ts +2 -1
  53. package/src/swapper/Swapper.ts +133 -61
  54. package/src/swapper/SwapperUtils.ts +3 -1
  55. package/src/swaps/ISwap.ts +10 -2
  56. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +5 -5
  57. package/src/swaps/escrow_swaps/IEscrowSwap.ts +10 -3
  58. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +64 -26
  59. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +8 -5
  60. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +3 -3
  61. package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +22 -12
  62. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +18 -18
  63. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +52 -31
  64. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +9 -9
  65. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +76 -52
  66. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +5 -5
  67. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +82 -38
  68. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +12 -12
  69. package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +21 -9
  70. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +1 -1
  71. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +56 -33
  72. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +2 -2
  73. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +40 -22
  74. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +17 -13
  75. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +149 -83
  76. package/src/swaps/trusted/ln/LnForGasWrapper.ts +2 -1
  77. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +2 -1
  78. package/src/utils/Utils.ts +14 -0
@@ -47,9 +47,10 @@ class UnifiedSwapEventListener {
47
47
  const htlcCheckInitializeEvents = {};
48
48
  for (let event of events) {
49
49
  const escrowHash = chainEventToEscrowHash(event);
50
+ const eventVersion = event.contractVersion ?? "v1";
50
51
  if (escrowHash != null) {
51
52
  const swap = swapsByEscrowHash[escrowHash];
52
- if (swap != null) {
53
+ if (swap != null && (swap._contractVersion ?? "v1") === eventVersion) {
53
54
  const obj = this.listeners[swap.getType()];
54
55
  if (obj == null)
55
56
  continue;
@@ -85,8 +86,9 @@ class UnifiedSwapEventListener {
85
86
  logger.debug("processEvents(): Additional HTLC swaps founds: ", swapsByClaimDataHash);
86
87
  for (let claimData in htlcCheckInitializeEvents) {
87
88
  const event = htlcCheckInitializeEvents[claimData];
89
+ const eventVersion = event.contractVersion ?? "v1";
88
90
  const swap = swapsByClaimDataHash[claimData];
89
- if (swap != null) {
91
+ if (swap != null && (swap._contractVersion ?? "v1") === eventVersion) {
90
92
  const obj = this.listeners[swap.getType()];
91
93
  if (obj == null)
92
94
  continue;
@@ -50,6 +50,12 @@ export declare class Intermediary {
50
50
  readonly addresses: {
51
51
  [chainIdentifier: string]: string;
52
52
  };
53
+ /**
54
+ * Contract versions of the intermediary on smart chains
55
+ */
56
+ readonly contractVersions: {
57
+ [chainIdentifier: string]: string;
58
+ };
53
59
  /**
54
60
  * Swap protocol services offered by the intermediary
55
61
  */
@@ -97,6 +103,8 @@ export declare class Intermediary {
97
103
  [chainIdentifier: string]: string;
98
104
  }, services: ServicesType, reputation?: {
99
105
  [chainIdentifier: string]: SingleChainReputationType;
106
+ }, contractVersions?: {
107
+ [chainIdentifier: string]: string;
100
108
  });
101
109
  /**
102
110
  * Returns the input/output swap limit for given swap type, chain and token
@@ -154,4 +162,17 @@ export declare class Intermediary {
154
162
  * @param chainIdentifier Chain identifier of the smart chain
155
163
  */
156
164
  getAddress(chainIdentifier: string): string;
165
+ /**
166
+ * Returns the contract version used by the intermediary for a given chain
167
+ *
168
+ * @param chainIdentifier
169
+ */
170
+ getContractVersion(chainIdentifier: string): string;
171
+ /**
172
+ * Returns the range of contract versions used by the LPs
173
+ *
174
+ * @param chainIdentifier
175
+ * @param lps
176
+ */
177
+ static getContractVersionsForLps(chainIdentifier: string, lps: Intermediary[]): string[];
157
178
  }
@@ -9,7 +9,7 @@ const RetryUtils_1 = require("../utils/RetryUtils");
9
9
  * @category LPs
10
10
  */
11
11
  class Intermediary {
12
- constructor(url, addresses, services, reputation = {}) {
12
+ constructor(url, addresses, services, reputation = {}, contractVersions = {}) {
13
13
  /**
14
14
  * Reputation of the intermediary on different smart chains, this is only fetched
15
15
  * on-demand when creating a swap where reputation is checked
@@ -24,6 +24,7 @@ class Intermediary {
24
24
  this.addresses = addresses;
25
25
  this.services = services;
26
26
  this.reputation = reputation;
27
+ this.contractVersions = contractVersions;
27
28
  this.swapBounds = {};
28
29
  for (let _swapType in this.services) {
29
30
  const swapType = parseInt(_swapType);
@@ -138,5 +139,28 @@ class Intermediary {
138
139
  getAddress(chainIdentifier) {
139
140
  return this.addresses[chainIdentifier];
140
141
  }
142
+ /**
143
+ * Returns the contract version used by the intermediary for a given chain
144
+ *
145
+ * @param chainIdentifier
146
+ */
147
+ getContractVersion(chainIdentifier) {
148
+ return this.contractVersions[chainIdentifier] ?? "v1";
149
+ }
150
+ /**
151
+ * Returns the range of contract versions used by the LPs
152
+ *
153
+ * @param chainIdentifier
154
+ * @param lps
155
+ */
156
+ static getContractVersionsForLps(chainIdentifier, lps) {
157
+ const versions = [];
158
+ lps.forEach((lp) => {
159
+ const lpVersion = lp.getContractVersion(chainIdentifier);
160
+ if (!versions.includes(lpVersion))
161
+ versions.push(lpVersion);
162
+ });
163
+ return versions;
164
+ }
141
165
  }
142
166
  exports.Intermediary = Intermediary;
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { Intermediary } from "./Intermediary";
3
3
  import { SwapType } from "../enums/SwapType";
4
- import { SwapContract } from "@atomiqlabs/base";
4
+ import { SpvVaultContract, SwapContract } from "@atomiqlabs/base";
5
5
  import { EventEmitter } from "events";
6
6
  /**
7
7
  * Swap handler type mapping for intermediary communication
@@ -83,7 +83,12 @@ export declare class IntermediaryDiscovery extends EventEmitter {
83
83
  * Swap contracts for checking intermediary signatures
84
84
  */
85
85
  swapContracts: {
86
- [key: string]: SwapContract;
86
+ [chainIdentifier: string]: {
87
+ [contractVersion: string]: {
88
+ swapContract: SwapContract;
89
+ spvVaultContract: SpvVaultContract;
90
+ };
91
+ };
87
92
  };
88
93
  /**
89
94
  * Registry URL used as a source for the list of intermediaries, this should be a link to a
@@ -105,7 +110,12 @@ export declare class IntermediaryDiscovery extends EventEmitter {
105
110
  */
106
111
  private overrideNodeUrls?;
107
112
  constructor(swapContracts: {
108
- [key: string]: SwapContract;
113
+ [chainIdentifier: string]: {
114
+ [contractVersion: string]: {
115
+ swapContract: SwapContract;
116
+ spvVaultContract: SpvVaultContract;
117
+ };
118
+ };
109
119
  }, registryUrl?: string, nodeUrls?: string[], httpRequestTimeout?: number, maxWaitForOthersTimeout?: number);
110
120
  /**
111
121
  * Fetches the URLs of swap intermediaries from registry or from a pre-defined array of node urls
@@ -183,6 +193,8 @@ export declare class IntermediaryDiscovery extends EventEmitter {
183
193
  /**
184
194
  * Returns swap candidates for a specific swap type & token address
185
195
  *
196
+ * @remark Also filters the LPs based on supported swap versions
197
+ *
186
198
  * @param chainIdentifier Chain identifier of the smart chain
187
199
  * @param swapType Swap protocol type
188
200
  * @param tokenAddress Token address
@@ -133,13 +133,21 @@ class IntermediaryDiscovery extends events_1.EventEmitter {
133
133
  abortSignal?.throwIfAborted();
134
134
  const promises = [];
135
135
  const addresses = {};
136
+ const contractVersions = {};
136
137
  for (let chain in response.chains) {
137
138
  if (this.swapContracts[chain] != null) {
139
+ const { signature, address, contractVersion } = response.chains[chain];
140
+ const _contractVersion = contractVersion ?? "v1";
141
+ const contract = this.swapContracts[chain][_contractVersion];
142
+ if (contract == null) {
143
+ logger.warn("getNodeInfo(): Unknown chain contract version " + _contractVersion + " for " + chain + " reported by intermediary: " + url);
144
+ continue;
145
+ }
138
146
  promises.push((async () => {
139
- const { signature, address } = response.chains[chain];
140
147
  try {
141
- await this.swapContracts[chain].isValidDataSignature(buffer_1.Buffer.from(response.envelope), signature, address);
148
+ await contract.swapContract.isValidDataSignature(buffer_1.Buffer.from(response.envelope), signature, address);
142
149
  addresses[chain] = address;
150
+ contractVersions[chain] = _contractVersion;
143
151
  }
144
152
  catch (e) {
145
153
  logger.warn("getNodeInfo(): Failed to verify " + chain + " signature for intermediary: " + url);
@@ -171,6 +179,7 @@ class IntermediaryDiscovery extends events_1.EventEmitter {
171
179
  }
172
180
  return {
173
181
  addresses,
182
+ contractVersions,
174
183
  info
175
184
  };
176
185
  }
@@ -188,7 +197,7 @@ class IntermediaryDiscovery extends events_1.EventEmitter {
188
197
  for (let key in nodeInfo.info.services) {
189
198
  services[swapHandlerTypeToSwapType(key)] = nodeInfo.info.services[key];
190
199
  }
191
- return new Intermediary_1.Intermediary(url, nodeInfo.addresses, services);
200
+ return new Intermediary_1.Intermediary(url, nodeInfo.addresses, services, undefined, nodeInfo.contractVersions);
192
201
  }
193
202
  catch (e) {
194
203
  logger.warn("fetchIntermediaries(): Intermediary " + url + ` is unreachable due to ${e.name ?? e.message} error, skipping...`);
@@ -356,6 +365,8 @@ class IntermediaryDiscovery extends events_1.EventEmitter {
356
365
  /**
357
366
  * Returns swap candidates for a specific swap type & token address
358
367
  *
368
+ * @remark Also filters the LPs based on supported swap versions
369
+ *
359
370
  * @param chainIdentifier Chain identifier of the smart chain
360
371
  * @param swapType Swap protocol type
361
372
  * @param tokenAddress Token address
@@ -377,6 +388,13 @@ class IntermediaryDiscovery extends events_1.EventEmitter {
377
388
  return false;
378
389
  if (!swapService.chainTokens[chainIdentifier].includes(tokenAddress.toString()))
379
390
  return false;
391
+ const contracts = this.swapContracts[chainIdentifier][e.getContractVersion(chainIdentifier) ?? "v1"];
392
+ if (contracts == null)
393
+ return false;
394
+ if (swapType === SwapType_1.SwapType.FROM_BTCLN_AUTO && !contracts.swapContract?.supportsInitWithoutClaimer)
395
+ return false;
396
+ if (swapType === SwapType_1.SwapType.SPV_VAULT_FROM_BTC && contracts.spvVaultContract == null)
397
+ return false;
380
398
  return true;
381
399
  });
382
400
  candidates.sort(getIntermediaryComparator(swapType, tokenAddress, amount));
@@ -7,6 +7,7 @@ export type InfoHandlerResponse = {
7
7
  [chainIdentifier: string]: {
8
8
  address: string;
9
9
  signature: string;
10
+ contractVersion?: string;
10
11
  };
11
12
  };
12
13
  };
@@ -159,14 +159,19 @@ type ChainSpecificData<T extends ChainType> = {
159
159
  [SwapType.FROM_BTCLN_AUTO]: FromBTCLNAutoWrapper<T>;
160
160
  };
161
161
  chainEvents: T["Events"];
162
- swapContract: T["Contract"];
163
- spvVaultContract: T["SpvVaultContract"];
164
162
  chainInterface: T["ChainInterface"];
165
- btcRelay: BtcRelay<any, T["TX"], BtcBlock, T["Signer"]>;
166
- synchronizer: RelaySynchronizer<any, T["TX"], BtcBlock>;
167
163
  unifiedChainEvents: UnifiedSwapEventListener<T>;
168
164
  unifiedSwapStorage: UnifiedSwapStorage<T>;
169
165
  reviver: (val: any) => ISwap<T>;
166
+ defaultVersion: string;
167
+ versionedContracts: {
168
+ [contractVersion: string]: {
169
+ swapContract: T["Contract"];
170
+ spvVaultContract: T["SpvVaultContract"];
171
+ btcRelay: BtcRelay<any, T["TX"], BtcBlock, T["Signer"]>;
172
+ synchronizer: RelaySynchronizer<any, T["TX"], BtcBlock>;
173
+ };
174
+ };
170
175
  };
171
176
  type MultiChainData<T extends MultiChain> = {
172
177
  [chainIdentifier in keyof T]: ChainSpecificData<T[chainIdentifier]>;
@@ -91,30 +91,50 @@ class Swapper extends events_1.EventEmitter {
91
91
  this.emit("swapState", swap);
92
92
  };
93
93
  this._chains = (0, Utils_1.objectMap)(chainsData, (chainData, key) => {
94
- const { swapContract, chainEvents, btcRelay, chainInterface, spvVaultContract, spvVaultWithdrawalDataConstructor, chainId } = chainData;
95
- const synchronizer = bitcoinSynchronizer(btcRelay);
94
+ let { chainInterface, chainEvents, chainId, btcRelay, swapContract, swapDataConstructor, spvVaultContract, spvVaultWithdrawalDataConstructor, spvVaultDataConstructor, defaultVersion, versions } = chainData;
95
+ defaultVersion ??= "v1";
96
+ if (versions == null) {
97
+ versions = {
98
+ [defaultVersion]: {
99
+ btcRelay,
100
+ swapContract,
101
+ swapDataConstructor,
102
+ spvVaultContract,
103
+ spvVaultDataConstructor,
104
+ spvVaultWithdrawalDataConstructor
105
+ }
106
+ };
107
+ }
108
+ const versionedContracts = (0, Utils_1.objectMap)(versions, (value, key) => {
109
+ return {
110
+ swapContract: value.swapContract,
111
+ spvVaultContract: value.spvVaultContract,
112
+ btcRelay: value.btcRelay,
113
+ synchronizer: bitcoinSynchronizer(value.btcRelay)
114
+ };
115
+ });
96
116
  const storageHandler = swapStorage(storagePrefix + chainId);
97
117
  const unifiedSwapStorage = new UnifiedSwapStorage_1.UnifiedSwapStorage(storageHandler, this.options.noSwapCache);
98
118
  const unifiedChainEvents = new UnifiedSwapEventListener_1.UnifiedSwapEventListener(unifiedSwapStorage, chainEvents);
99
119
  const wrappers = {};
100
- wrappers[SwapType_1.SwapType.TO_BTCLN] = new ToBTCLNWrapper_1.ToBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, swapContract, pricing, this._tokens[chainId], chainData.swapDataConstructor, {
120
+ wrappers[SwapType_1.SwapType.TO_BTCLN] = new ToBTCLNWrapper_1.ToBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, {
101
121
  getRequestTimeout: this.options.getRequestTimeout,
102
122
  postRequestTimeout: this.options.postRequestTimeout,
103
123
  saveUninitializedSwaps: this.options.saveUninitializedSwaps,
104
124
  });
105
- wrappers[SwapType_1.SwapType.TO_BTC] = new ToBTCWrapper_1.ToBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, swapContract, pricing, this._tokens[chainId], chainData.swapDataConstructor, this._bitcoinRpc, {
125
+ wrappers[SwapType_1.SwapType.TO_BTC] = new ToBTCWrapper_1.ToBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, this._bitcoinRpc, {
106
126
  getRequestTimeout: this.options.getRequestTimeout,
107
127
  postRequestTimeout: this.options.postRequestTimeout,
108
128
  saveUninitializedSwaps: this.options.saveUninitializedSwaps,
109
129
  bitcoinNetwork: this._btcNetwork
110
130
  });
111
- wrappers[SwapType_1.SwapType.FROM_BTCLN] = new FromBTCLNWrapper_1.FromBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, swapContract, pricing, this._tokens[chainId], chainData.swapDataConstructor, lightningApi, {
131
+ wrappers[SwapType_1.SwapType.FROM_BTCLN] = new FromBTCLNWrapper_1.FromBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, lightningApi, {
112
132
  getRequestTimeout: this.options.getRequestTimeout,
113
133
  postRequestTimeout: this.options.postRequestTimeout,
114
134
  saveUninitializedSwaps: this.options.saveUninitializedSwaps,
115
135
  unsafeSkipLnNodeCheck: this.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET4 || this.bitcoinNetwork === base_1.BitcoinNetwork.REGTEST
116
136
  });
117
- wrappers[SwapType_1.SwapType.FROM_BTC] = new FromBTCWrapper_1.FromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, swapContract, pricing, this._tokens[chainId], chainData.swapDataConstructor, btcRelay, synchronizer, this._bitcoinRpc, {
137
+ wrappers[SwapType_1.SwapType.FROM_BTC] = new FromBTCWrapper_1.FromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, versionedContracts, this._bitcoinRpc, {
118
138
  getRequestTimeout: this.options.getRequestTimeout,
119
139
  postRequestTimeout: this.options.postRequestTimeout,
120
140
  saveUninitializedSwaps: this.options.saveUninitializedSwaps,
@@ -131,16 +151,18 @@ class Swapper extends events_1.EventEmitter {
131
151
  saveUninitializedSwaps: this.options.saveUninitializedSwaps,
132
152
  bitcoinNetwork: this._btcNetwork
133
153
  });
154
+ // This is gated on the default version of the contracts
134
155
  if (spvVaultContract != null) {
135
- wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] = new SpvFromBTCWrapper_1.SpvFromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, spvVaultContract, pricing, this._tokens[chainId], spvVaultWithdrawalDataConstructor, btcRelay, synchronizer, bitcoinRpc, {
156
+ wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] = new SpvFromBTCWrapper_1.SpvFromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, versionedContracts, bitcoinRpc, {
136
157
  getRequestTimeout: this.options.getRequestTimeout,
137
158
  postRequestTimeout: this.options.postRequestTimeout,
138
159
  saveUninitializedSwaps: this.options.saveUninitializedSwaps,
139
160
  bitcoinNetwork: this._btcNetwork
140
161
  });
141
162
  }
163
+ // This is gated on the default version of the contracts
142
164
  if (swapContract.supportsInitWithoutClaimer) {
143
- wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] = new FromBTCLNAutoWrapper_1.FromBTCLNAutoWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, swapContract, pricing, this._tokens[chainId], chainData.swapDataConstructor, lightningApi, this.messenger, {
165
+ wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] = new FromBTCLNAutoWrapper_1.FromBTCLNAutoWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, lightningApi, this.messenger, {
144
166
  getRequestTimeout: this.options.getRequestTimeout,
145
167
  postRequestTimeout: this.options.postRequestTimeout,
146
168
  saveUninitializedSwaps: this.options.saveUninitializedSwaps,
@@ -156,18 +178,16 @@ class Swapper extends events_1.EventEmitter {
156
178
  };
157
179
  return {
158
180
  chainEvents,
159
- spvVaultContract,
160
- swapContract,
161
181
  chainInterface,
162
- btcRelay,
163
- synchronizer,
164
182
  wrappers,
165
183
  unifiedChainEvents,
166
184
  unifiedSwapStorage,
167
- reviver
185
+ defaultVersion,
186
+ reviver,
187
+ versionedContracts
168
188
  };
169
189
  });
170
- const contracts = (0, Utils_1.objectMap)(chainsData, (data) => data.swapContract);
190
+ const contracts = (0, Utils_1.objectMap)(chainsData, (data) => data.versions ?? { [data.defaultVersion ?? "v1"]: { swapContract: data.swapContract, spvVaultContract: data.spvVaultContract } });
171
191
  if (options.intermediaryUrl != null) {
172
192
  this.intermediaryDiscovery = new IntermediaryDiscovery_1.IntermediaryDiscovery(contracts, options.registryUrl, Array.isArray(options.intermediaryUrl) ? options.intermediaryUrl : [options.intermediaryUrl], options.getRequestTimeout);
173
193
  }
@@ -218,13 +238,15 @@ class Swapper extends events_1.EventEmitter {
218
238
  const chainPromises = [];
219
239
  for (let chainIdentifier in this._chains) {
220
240
  chainPromises.push((async () => {
221
- const { chainInterface, swapContract, unifiedChainEvents, unifiedSwapStorage, wrappers, reviver } = this._chains[chainIdentifier];
241
+ const { chainInterface, versionedContracts, unifiedChainEvents, unifiedSwapStorage, wrappers, reviver } = this._chains[chainIdentifier];
222
242
  const _chainInterface = chainInterface;
223
243
  if (_chainInterface.verifyNetwork != null) {
224
244
  await _chainInterface.verifyNetwork(this.bitcoinNetwork);
225
245
  }
226
- await swapContract.start();
227
- this.logger.debug("init(): Intialized swap contract: " + chainIdentifier);
246
+ for (let contractVersion in versionedContracts) {
247
+ await versionedContracts[contractVersion].swapContract.start();
248
+ this.logger.debug("init(): Intialized swap contract: " + chainIdentifier + ` version: ${contractVersion}`);
249
+ }
228
250
  await unifiedSwapStorage.init();
229
251
  if (unifiedSwapStorage.storage instanceof IndexedDBUnifiedStorage_1.IndexedDBUnifiedStorage) {
230
252
  //Try to migrate the data here
@@ -1173,15 +1195,35 @@ class Swapper extends events_1.EventEmitter {
1173
1195
  * initiated after this blockheight
1174
1196
  */
1175
1197
  async recoverSwaps(chainId, signer, startBlockheight) {
1176
- const { spvVaultContract, swapContract, unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1177
- if (swapContract.getHistoricalSwaps == null ||
1178
- (spvVaultContract != null && spvVaultContract.getHistoricalWithdrawalStates == null))
1198
+ //TODO: Recover swaps from all the known contract versions
1199
+ const { versionedContracts, unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1200
+ const recoveredSwaps = [];
1201
+ let someVersionSupportsRecovery = false;
1202
+ const recoveredEscrowStates = {};
1203
+ const recoveredSpvStates = {};
1204
+ for (let contractVersion in versionedContracts) {
1205
+ const { swapContract, spvVaultContract } = versionedContracts[contractVersion];
1206
+ if (swapContract.getHistoricalSwaps == null ||
1207
+ (spvVaultContract != null && spvVaultContract.getHistoricalWithdrawalStates == null)) {
1208
+ this.logger.warn(`recoverSwaps(): Swap data recovery not supported on ${chainId}, with contract version ${contractVersion}`);
1209
+ continue;
1210
+ }
1211
+ someVersionSupportsRecovery = true;
1212
+ const { swaps } = await swapContract.getHistoricalSwaps(signer, startBlockheight);
1213
+ const spvVaultData = wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] == null
1214
+ ? undefined
1215
+ : await spvVaultContract?.getHistoricalWithdrawalStates(signer, startBlockheight);
1216
+ for (let key in swaps)
1217
+ recoveredEscrowStates[key] = { ...swaps[key], contractVersion };
1218
+ if (spvVaultData != null)
1219
+ for (let key in spvVaultData.withdrawals)
1220
+ (recoveredSpvStates[contractVersion] ??= {})[key] = spvVaultData.withdrawals[key];
1221
+ }
1222
+ if (!someVersionSupportsRecovery)
1179
1223
  throw new Error(`Historical swap recovery is not supported for ${chainId}`);
1180
- const { swaps } = await swapContract.getHistoricalSwaps(signer, startBlockheight);
1181
- const spvVaultData = await spvVaultContract?.getHistoricalWithdrawalStates(signer, startBlockheight);
1182
- const escrowHashes = Object.keys(swaps);
1183
- if (spvVaultData != null)
1184
- Object.keys(spvVaultData.withdrawals).forEach(btcTxId => escrowHashes.push(btcTxId));
1224
+ const escrowHashes = Object.keys(recoveredEscrowStates);
1225
+ for (let contractVersion in recoveredSpvStates)
1226
+ Object.keys(recoveredSpvStates[contractVersion]).forEach(btcTxId => escrowHashes.push(btcTxId));
1185
1227
  this.logger.debug(`recoverSwaps(): Loaded on-chain data for ${escrowHashes.length} swaps`);
1186
1228
  this.logger.debug(`recoverSwaps(): Fetching if swap escrowHashes are known: ${escrowHashes.join(", ")}`);
1187
1229
  const knownSwapsArray = await unifiedSwapStorage.query([[{ key: "escrowHash", value: escrowHashes }]], reviver);
@@ -1192,10 +1234,10 @@ class Swapper extends events_1.EventEmitter {
1192
1234
  knownSwaps[escrowHash] = val;
1193
1235
  });
1194
1236
  this.logger.debug(`recoverSwaps(): Fetched known swaps escrowHashes: ${Object.keys(knownSwaps).join(", ")}`);
1195
- const recoveredSwaps = [];
1196
- for (let escrowHash in swaps) {
1197
- const { init, state } = swaps[escrowHash];
1237
+ for (let escrowHash in recoveredEscrowStates) {
1238
+ const { init, state, contractVersion } = recoveredEscrowStates[escrowHash];
1198
1239
  const knownSwap = knownSwaps[escrowHash];
1240
+ const { swapContract } = versionedContracts[contractVersion];
1199
1241
  if (knownSwap == null) {
1200
1242
  if (init == null) {
1201
1243
  this.logger.warn(`recoverSwaps(escrow): Fetched ${escrowHash} swap state, but swap not found locally!`);
@@ -1204,6 +1246,10 @@ class Swapper extends events_1.EventEmitter {
1204
1246
  }
1205
1247
  else if (knownSwap instanceof IEscrowSwap_1.IEscrowSwap) {
1206
1248
  this.logger.debug(`recoverSwaps(escrow): Forcibly updating ${escrowHash} swap: swap already known and in local storage!`);
1249
+ if ((knownSwap._contractVersion ?? "v1") !== contractVersion) {
1250
+ this.logger.debug(`recoverSwaps(escrow): Skipping ${escrowHash} swap: swap uses contract version ${knownSwap._contractVersion ?? "v1"}, but state comes from ${contractVersion}!`);
1251
+ continue;
1252
+ }
1207
1253
  if (await knownSwap._forciblySetOnchainState(state)) {
1208
1254
  await knownSwap._save();
1209
1255
  }
@@ -1222,17 +1268,17 @@ class Swapper extends events_1.EventEmitter {
1222
1268
  //To BTCLN
1223
1269
  typeIdentified = true;
1224
1270
  const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1225
- swap = await wrappers[SwapType_1.SwapType.TO_BTCLN].recoverFromSwapDataAndState(init, state, lp);
1271
+ swap = await wrappers[SwapType_1.SwapType.TO_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1226
1272
  }
1227
1273
  else if (data.isClaimer(signer)) {
1228
1274
  //From BTCLN
1229
1275
  typeIdentified = true;
1230
1276
  const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1231
- if (this.supportsSwapType(chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO)) {
1232
- swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].recoverFromSwapDataAndState(init, state, lp);
1277
+ if (swapContract.supportsInitWithoutClaimer && wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] != null) {
1278
+ swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1233
1279
  }
1234
1280
  else {
1235
- swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN].recoverFromSwapDataAndState(init, state, lp);
1281
+ swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1236
1282
  }
1237
1283
  }
1238
1284
  }
@@ -1240,13 +1286,13 @@ class Swapper extends events_1.EventEmitter {
1240
1286
  //To BTC
1241
1287
  typeIdentified = true;
1242
1288
  const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1243
- swap = await wrappers[SwapType_1.SwapType.TO_BTC].recoverFromSwapDataAndState(init, state, lp);
1289
+ swap = await wrappers[SwapType_1.SwapType.TO_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1244
1290
  }
1245
1291
  else if (data.getType() === base_1.ChainSwapType.CHAIN) {
1246
1292
  //From BTC
1247
1293
  typeIdentified = true;
1248
1294
  const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1249
- swap = await wrappers[SwapType_1.SwapType.FROM_BTC].recoverFromSwapDataAndState(init, state, lp);
1295
+ swap = await wrappers[SwapType_1.SwapType.FROM_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1250
1296
  }
1251
1297
  if (swap != null) {
1252
1298
  recoveredSwaps.push(swap);
@@ -1256,14 +1302,16 @@ class Swapper extends events_1.EventEmitter {
1256
1302
  this.logger.debug(`recoverSwaps(escrow): Swap data type correctly identified but swap returned is null for swap ${escrowHash}`);
1257
1303
  }
1258
1304
  }
1259
- if (spvVaultContract != null && spvVaultData != null) {
1260
- const vaultsData = await spvVaultContract.getMultipleVaultData(Object.keys(spvVaultData.withdrawals)
1305
+ for (let contractVersion in recoveredSpvStates) {
1306
+ const { spvVaultContract } = versionedContracts[contractVersion];
1307
+ const spvVaultData = recoveredSpvStates[contractVersion];
1308
+ const vaultsData = await spvVaultContract.getMultipleVaultData(Object.keys(spvVaultData)
1261
1309
  .map(btcTxId => ({
1262
- owner: spvVaultData.withdrawals[btcTxId].owner,
1263
- vaultId: spvVaultData.withdrawals[btcTxId].vaultId
1310
+ owner: spvVaultData[btcTxId].owner,
1311
+ vaultId: spvVaultData[btcTxId].vaultId
1264
1312
  })));
1265
- for (let btcTxId in spvVaultData.withdrawals) {
1266
- const state = spvVaultData.withdrawals[btcTxId];
1313
+ for (let btcTxId in spvVaultData) {
1314
+ const state = spvVaultData[btcTxId];
1267
1315
  const knownSwap = knownSwaps[btcTxId];
1268
1316
  if (knownSwap != null) {
1269
1317
  if (knownSwap instanceof SpvFromBTCSwap_1.SpvFromBTCSwap) {
@@ -1280,7 +1328,7 @@ class Swapper extends events_1.EventEmitter {
1280
1328
  }
1281
1329
  }
1282
1330
  const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && state.owner.toLowerCase() === val.getAddress(chainId).toLowerCase());
1283
- const swap = await wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC].recoverFromState(state, vaultsData[state.owner]?.[state.vaultId.toString(10)], lp);
1331
+ const swap = await wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC].recoverFromState(state, contractVersion, vaultsData[state.owner]?.[state.vaultId.toString(10)], lp);
1284
1332
  if (swap != null) {
1285
1333
  recoveredSwaps.push(swap);
1286
1334
  }
@@ -337,7 +337,8 @@ class SwapperUtils {
337
337
  async getSpendableBalance(wallet, token, options) {
338
338
  if (this.root._chains[token.chainId] == null)
339
339
  throw new Error("Invalid chain identifier! Unknown chain: " + token.chainId);
340
- const { swapContract, chainInterface } = this.root._chains[token.chainId];
340
+ const { defaultVersion, versionedContracts, chainInterface } = this.root._chains[token.chainId];
341
+ const { swapContract } = versionedContracts[defaultVersion];
341
342
  let signer;
342
343
  if (typeof (wallet) === "string") {
343
344
  signer = wallet;
@@ -25,6 +25,7 @@ export type ISwapInit = {
25
25
  swapFee: bigint;
26
26
  swapFeeBtc: bigint;
27
27
  exactIn: boolean;
28
+ contractVersion: string;
28
29
  };
29
30
  /**
30
31
  * Type guard to check if an object is an ISwapInit
@@ -119,6 +120,10 @@ export declare abstract class ISwap<T extends ChainType = ChainType, D extends S
119
120
  * @internal
120
121
  */
121
122
  _persisted: boolean;
123
+ /**
124
+ * @internal
125
+ */
126
+ _contractVersion?: string;
122
127
  /**
123
128
  * Event emitter emitting `"swapState"` event when swap's state changes
124
129
  */
@@ -73,6 +73,7 @@ class ISwap {
73
73
  this.version = this.currentVersion;
74
74
  this.createdAt = Date.now();
75
75
  this._randomNonce = (0, Utils_1.randomBytes)(16).toString("hex");
76
+ this._contractVersion = swapInitOrObj.contractVersion;
76
77
  }
77
78
  else {
78
79
  this.expiry = swapInitOrObj.expiry;
@@ -97,6 +98,7 @@ class ISwap {
97
98
  this.exactIn = swapInitOrObj.exactIn;
98
99
  this.createdAt = swapInitOrObj.createdAt ?? swapInitOrObj.expiry;
99
100
  this._randomNonce = swapInitOrObj.randomNonce;
101
+ this._contractVersion = swapInitOrObj.contractVersion;
100
102
  }
101
103
  if (this.version !== this.currentVersion) {
102
104
  this.upgradeVersion();
@@ -323,7 +325,8 @@ class ISwap {
323
325
  initiated: this.initiated,
324
326
  exactIn: this.exactIn,
325
327
  createdAt: this.createdAt,
326
- randomNonce: this._randomNonce
328
+ randomNonce: this._randomNonce,
329
+ contractVersion: this._contractVersion
327
330
  };
328
331
  }
329
332
  //////////////////////////////
@@ -55,7 +55,7 @@ class IEscrowSelfInitSwap extends IEscrowSwap_1.IEscrowSwap {
55
55
  while (!expired) {
56
56
  await (0, TimeoutUtils_1.timeoutPromise)(intervalSeconds * 1000, abortSignal);
57
57
  try {
58
- expired = await this.wrapper._contract.isInitAuthorizationExpired(this._data, this.signatureData);
58
+ expired = await this._contract.isInitAuthorizationExpired(this._data, this.signatureData);
59
59
  }
60
60
  catch (e) {
61
61
  this.logger.error("watchdogWaitTillSignatureExpiry(): Error when checking signature expiry: ", e);
@@ -71,13 +71,13 @@ class IEscrowSelfInitSwap extends IEscrowSwap_1.IEscrowSwap {
71
71
  * @internal
72
72
  */
73
73
  getCommitFee() {
74
- return this.wrapper._contract.getCommitFee(this._getInitiator(), this.getSwapData(), this.feeRate);
74
+ return this._contract.getCommitFee(this._getInitiator(), this.getSwapData(), this.feeRate);
75
75
  }
76
76
  /**
77
77
  * Returns the transaction fee paid on the smart chain side to initiate the escrow
78
78
  */
79
79
  async getSmartChainNetworkFee() {
80
- const swapContract = this.wrapper._contract;
80
+ const swapContract = this._contract;
81
81
  return (0, TokenAmount_1.toTokenAmount)(await (swapContract.getRawCommitFee != null ?
82
82
  swapContract.getRawCommitFee(this._getInitiator(), this.getSwapData(), this.feeRate) :
83
83
  swapContract.getCommitFee(this._getInitiator(), this.getSwapData(), this.feeRate)), this.wrapper._getNativeToken(), this.wrapper._prices);
@@ -90,7 +90,7 @@ class IEscrowSelfInitSwap extends IEscrowSwap_1.IEscrowSwap {
90
90
  async _verifyQuoteDefinitelyExpired() {
91
91
  if (this._data == null || this.signatureData == null)
92
92
  throw new Error("data or signature data are null!");
93
- return this.wrapper._contract.isInitAuthorizationExpired(this._data, this.signatureData);
93
+ return this._contract.isInitAuthorizationExpired(this._data, this.signatureData);
94
94
  }
95
95
  /**
96
96
  * Checks if the swap's quote is still valid
@@ -99,7 +99,7 @@ class IEscrowSelfInitSwap extends IEscrowSwap_1.IEscrowSwap {
99
99
  if (this._data == null || this.signatureData == null)
100
100
  throw new Error("data or signature data are null!");
101
101
  try {
102
- await this.wrapper._contract.isValidInitAuthorization(this._getInitiator(), this._data, this.signatureData, this.feeRate);
102
+ await this._contract.isValidInitAuthorization(this._getInitiator(), this._data, this.signatureData, this.feeRate);
103
103
  return true;
104
104
  }
105
105
  catch (e) {
@@ -31,6 +31,10 @@ export declare abstract class IEscrowSwap<T extends ChainType = ChainType, D ext
31
31
  * @internal
32
32
  */
33
33
  _claimTxId?: string;
34
+ /**
35
+ * @internal
36
+ */
37
+ protected _contract: T["Contract"];
34
38
  protected constructor(wrapper: D["Wrapper"], obj: any);
35
39
  protected constructor(wrapper: D["Wrapper"], swapInit: IEscrowSwapInit<T["Data"]>);
36
40
  /**