@atomiqlabs/sdk 8.8.3 → 8.9.0

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 (130) hide show
  1. package/api/index.d.ts +1 -0
  2. package/api/index.js +3 -0
  3. package/dist/ApiList.d.ts +37 -0
  4. package/dist/ApiList.js +30 -0
  5. package/dist/api/ApiEndpoints.d.ts +393 -0
  6. package/dist/api/ApiEndpoints.js +2 -0
  7. package/dist/api/ApiParser.d.ts +10 -0
  8. package/dist/api/ApiParser.js +134 -0
  9. package/dist/api/ApiTypes.d.ts +157 -0
  10. package/dist/api/ApiTypes.js +75 -0
  11. package/dist/api/SerializedAction.d.ts +40 -0
  12. package/dist/api/SerializedAction.js +59 -0
  13. package/dist/api/SwapperApi.d.ts +50 -0
  14. package/dist/api/SwapperApi.js +431 -0
  15. package/dist/api/index.d.ts +5 -0
  16. package/dist/api/index.js +24 -0
  17. package/dist/events/UnifiedSwapEventListener.d.ts +4 -3
  18. package/dist/events/UnifiedSwapEventListener.js +8 -2
  19. package/dist/http/HttpUtils.d.ts +4 -2
  20. package/dist/http/HttpUtils.js +10 -4
  21. package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +2 -1
  22. package/dist/http/paramcoders/client/StreamingFetchPromise.js +3 -2
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +1 -0
  25. package/dist/intermediaries/IntermediaryDiscovery.d.ts +7 -2
  26. package/dist/intermediaries/IntermediaryDiscovery.js +4 -4
  27. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +171 -14
  28. package/dist/intermediaries/apis/IntermediaryAPI.js +174 -28
  29. package/dist/intermediaries/auth/SignedKeyBasedAuth.d.ts +14 -0
  30. package/dist/intermediaries/auth/SignedKeyBasedAuth.js +68 -0
  31. package/dist/storage/IUnifiedStorage.d.ts +45 -3
  32. package/dist/storage/UnifiedSwapStorage.d.ts +8 -2
  33. package/dist/storage/UnifiedSwapStorage.js +46 -8
  34. package/dist/swapper/Swapper.d.ts +36 -3
  35. package/dist/swapper/Swapper.js +54 -18
  36. package/dist/swapper/SwapperUtils.d.ts +18 -2
  37. package/dist/swapper/SwapperUtils.js +39 -1
  38. package/dist/swaps/ISwap.d.ts +70 -9
  39. package/dist/swaps/ISwap.js +28 -6
  40. package/dist/swaps/ISwapWrapper.d.ts +11 -1
  41. package/dist/swaps/ISwapWrapper.js +23 -3
  42. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +1 -1
  43. package/dist/swaps/escrow_swaps/IEscrowSwap.js +4 -2
  44. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +2 -1
  45. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +2 -2
  46. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +3 -1
  47. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +3 -2
  48. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +47 -31
  49. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +201 -67
  50. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +3 -1
  51. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +6 -6
  52. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +82 -15
  53. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +304 -98
  54. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +3 -1
  55. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +6 -6
  56. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +75 -42
  57. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +424 -87
  58. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +3 -1
  59. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +7 -7
  60. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +54 -11
  61. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +214 -41
  62. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +2 -1
  63. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +7 -8
  64. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +3 -1
  65. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +5 -5
  66. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +76 -19
  67. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +290 -51
  68. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +3 -1
  69. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +5 -5
  70. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +53 -12
  71. package/dist/swaps/trusted/ln/LnForGasSwap.js +163 -49
  72. package/dist/swaps/trusted/ln/LnForGasWrapper.js +1 -2
  73. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +14 -13
  74. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +30 -47
  75. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +3 -1
  76. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +4 -4
  77. package/dist/types/SwapExecutionAction.d.ts +141 -34
  78. package/dist/types/SwapExecutionAction.js +104 -0
  79. package/dist/types/SwapExecutionStep.d.ts +144 -0
  80. package/dist/types/SwapExecutionStep.js +87 -0
  81. package/dist/types/TokenAmount.d.ts +6 -0
  82. package/dist/types/TokenAmount.js +26 -1
  83. package/dist/utils/BitcoinUtils.d.ts +2 -0
  84. package/dist/utils/BitcoinUtils.js +34 -1
  85. package/dist/utils/Utils.d.ts +3 -1
  86. package/dist/utils/Utils.js +7 -1
  87. package/package.json +7 -4
  88. package/src/api/ApiEndpoints.ts +427 -0
  89. package/src/api/ApiParser.ts +138 -0
  90. package/src/api/ApiTypes.ts +229 -0
  91. package/src/api/SerializedAction.ts +97 -0
  92. package/src/api/SwapperApi.ts +545 -0
  93. package/src/api/index.ts +5 -0
  94. package/src/events/UnifiedSwapEventListener.ts +11 -3
  95. package/src/http/HttpUtils.ts +10 -4
  96. package/src/http/paramcoders/client/StreamingFetchPromise.ts +4 -2
  97. package/src/index.ts +1 -0
  98. package/src/intermediaries/IntermediaryDiscovery.ts +9 -2
  99. package/src/intermediaries/apis/IntermediaryAPI.ts +314 -30
  100. package/src/intermediaries/auth/SignedKeyBasedAuth.ts +69 -0
  101. package/src/storage/IUnifiedStorage.ts +45 -4
  102. package/src/storage/UnifiedSwapStorage.ts +42 -8
  103. package/src/swapper/Swapper.ts +87 -18
  104. package/src/swapper/SwapperUtils.ts +42 -2
  105. package/src/swaps/ISwap.ts +88 -16
  106. package/src/swaps/ISwapWrapper.ts +28 -3
  107. package/src/swaps/escrow_swaps/IEscrowSwap.ts +5 -3
  108. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +3 -1
  109. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +4 -1
  110. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +264 -67
  111. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +6 -4
  112. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +390 -89
  113. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +6 -4
  114. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +548 -94
  115. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +7 -5
  116. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +276 -45
  117. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +7 -6
  118. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +5 -3
  119. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +393 -57
  120. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +5 -3
  121. package/src/swaps/trusted/ln/LnForGasSwap.ts +211 -47
  122. package/src/swaps/trusted/ln/LnForGasWrapper.ts +1 -2
  123. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +32 -51
  124. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +5 -3
  125. package/src/types/SwapExecutionAction.ts +266 -43
  126. package/src/types/SwapExecutionStep.ts +224 -0
  127. package/src/types/TokenAmount.ts +36 -2
  128. package/src/utils/BitcoinUtils.ts +32 -0
  129. package/src/utils/Utils.ts +10 -1
  130. package/src/intermediaries/apis/TrustedIntermediaryAPI.ts +0 -258
@@ -16,11 +16,12 @@ export type QueryParams = {
16
16
  };
17
17
 
18
18
  /**
19
- * Base type for stored objects, every storage object MUST have an `id` field
19
+ * Base type for stored objects, every storage object MUST have an `id` field. The object might also specify a `_meta`
20
+ * field which gets carried to the delete/save operations (and can be used to implement optimistic concurrency)
20
21
  *
21
22
  * @category Storage
22
23
  */
23
- export type UnifiedStoredObject = {id: string} & any;
24
+ export type UnifiedStoredObject = {id: string, _meta?: any} & any;
24
25
 
25
26
  /**
26
27
  * Defines simple indexes (for queries that use a single key)
@@ -64,32 +65,72 @@ export interface IUnifiedStorage<I extends UnifiedStorageIndexes, C extends Unif
64
65
  * - [[condition1, condition2]] - returns all rows where condition1 AND condition2 is met
65
66
  * - [[condition1], [condition2]] - returns all rows where condition1 OR condition2 is met
66
67
  * - [[condition1, condition2], [condition3]] - returns all rows where (condition1 AND condition2) OR condition3 is met
68
+ *
69
+ * You can also add an optional `_meta` field in the returned unified storage object which gets attached to that
70
+ * returned object and will be present for subsequent saves and removal of this object, if you specify the `_meta`
71
+ * field here, you need to explicitly handle it in the all the saving and remove functions and not simply serialize
72
+ * it into the storage
73
+ *
67
74
  * @param params
68
75
  */
69
76
  query(params: Array<Array<QueryParams>>): Promise<Array<UnifiedStoredObject>>;
70
77
 
71
78
  /**
72
79
  * Saves an object to storage, updating indexes as needed
80
+ *
81
+ * If the object contains a `_meta` field, this will be also present in the to-be-saved value, to mutate the `_meta`
82
+ * field of the object that is saved, you can mutate the `_meta` field directly on the passed value, which then
83
+ * gets reflected automatically in the existing object. The mutated `_meta` field is copied even if the function
84
+ * throws, hence the implementations must be careful with setting the `_meta` field on the still in-flight requests
85
+ * that might fail.
86
+ *
73
87
  * @param value Object to save (must have an id property)
74
88
  */
75
89
  save(value: UnifiedStoredObject): Promise<void>;
76
90
 
77
91
  /**
78
92
  * Saves multiple objects to storage in a batch operation
93
+ *
94
+ * If the objects contain a `_meta` field, this will be also present in the to-be-saved values, to mutate the `_meta`
95
+ * field of the objects that are saved, you can mutate the `_meta` field directly on the passed values, which then
96
+ * gets reflected automatically in the existing objects. The mutated `_meta` field is copied even if the function
97
+ * throws, hence the implementations must be careful with setting the `_meta` field on the still in-flight requests
98
+ * that might fail.
99
+ *
79
100
  * @param value Array of objects to save
101
+ * @param lenient In lenient mode the persistency layer doesn't throw on individual swap failures due to
102
+ * optimistic concurrency, or other (implementation specific), this flag is to be used when the saving of the swap
103
+ * isn't mission-critical for executing next steps (e.g. in tick or sync loops)
80
104
  */
81
- saveAll(value: UnifiedStoredObject[]): Promise<void>;
105
+ saveAll(value: UnifiedStoredObject[], lenient?: boolean): Promise<void>;
82
106
 
83
107
  /**
84
108
  * Removes an object from storage
109
+ *
110
+ * If the object contains a `_meta` field, this will be also present in the to-be-removed value, to mutate the `_meta`
111
+ * field of the object that is saved, you can mutate the `_meta` field directly on the passed value, which then
112
+ * gets reflected automatically in the existing object. The mutated `_meta` field is copied even if the function
113
+ * throws, hence the implementations must be careful with setting the `_meta` field on the still in-flight requests
114
+ * that might fail.
115
+ *
85
116
  * @param value Object to remove (must have an id property)
86
117
  */
87
118
  remove(value: UnifiedStoredObject): Promise<void>;
88
119
 
89
120
  /**
90
121
  * Removes multiple objects from storage in a batch operation
122
+ *
123
+ * If the objects contain a `_meta` field, this will be also present in the to-be-removed values, to mutate the `_meta`
124
+ * field of the objects that are saved, you can mutate the `_meta` field directly on the passed values, which then
125
+ * gets reflected automatically in the existing objects. The mutated `_meta` field is copied even if the function
126
+ * throws, hence the implementations must be careful with setting the `_meta` field on the still in-flight requests
127
+ * that might fail.
128
+ *
91
129
  * @param value Array of objects to remove
130
+ * @param lenient In lenient mode the persistency layer doesn't throw on individual swap failures due to
131
+ * optimistic concurrency, or other (implementation specific), this flag is to be used when the saving of the swap
132
+ * isn't mission-critical for executing next steps (e.g. in tick or sync loops)
92
133
  */
93
- removeAll(value: UnifiedStoredObject[]): Promise<void>;
134
+ removeAll(value: UnifiedStoredObject[], lenient?: boolean): Promise<void>;
94
135
 
95
136
  }
@@ -104,18 +104,35 @@ export class UnifiedSwapStorage<T extends ChainType> {
104
104
  */
105
105
  async save<S extends ISwap<T>>(value: S): Promise<void> {
106
106
  if(!this.noWeakRefMap) this.weakRefCache.set(value.getId(), new WeakRef<ISwap<T>>(value));
107
- await this.storage.save(value.serialize());
107
+ const serialized = value.serialize();
108
+ try {
109
+ await this.storage.save(serialized);
110
+ } finally {
111
+ value._meta = serialized._meta;
112
+ }
108
113
  value._persisted = true;
109
114
  }
110
115
 
111
116
  /**
112
117
  * Saves multiple swaps to storage in a batch operation
113
118
  * @param values Array of swaps to save
119
+ * @param lenient In lenient mode the underlying persistent layer doesn't throw on individual swap failures due to
120
+ * optimistic concurrency, or other (implementation specific), this flag is to be used when the saving of the swap
121
+ * isn't mission-critical for executing next steps (e.g. in tick or sync loops)
114
122
  */
115
- async saveAll<S extends ISwap<T>>(values: S[]): Promise<void> {
123
+ async saveAll<S extends ISwap<T>>(values: S[], lenient?: boolean): Promise<void> {
116
124
  if(!this.noWeakRefMap) values.forEach(value => this.weakRefCache.set(value.getId(), new WeakRef<ISwap<T>>(value)));
117
- await this.storage.saveAll(values.map(obj => obj.serialize()));
118
- values.forEach(value => value._persisted = true);
125
+ const serialized = values.map(obj => obj.serialize());
126
+ try {
127
+ await this.storage.saveAll(serialized, lenient);
128
+ } finally {
129
+ values.forEach((value, index) => {
130
+ value._meta = serialized[index]._meta;
131
+ });
132
+ }
133
+ values.forEach((value) => {
134
+ value._persisted = true;
135
+ });
119
136
  }
120
137
 
121
138
  /**
@@ -124,18 +141,35 @@ export class UnifiedSwapStorage<T extends ChainType> {
124
141
  */
125
142
  async remove<S extends ISwap<T>>(value: S): Promise<void> {
126
143
  if(!this.noWeakRefMap) this.weakRefCache.delete(value.getId());
127
- await this.storage.remove(value.serialize());
144
+ const serialized = value.serialize();
145
+ try {
146
+ await this.storage.remove(serialized);
147
+ } finally {
148
+ value._meta = serialized._meta;
149
+ }
128
150
  value._persisted = false;
129
151
  }
130
152
 
131
153
  /**
132
154
  * Removes multiple swaps from storage in a batch operation
133
155
  * @param values Array of swaps to remove
156
+ * @param lenient In lenient mode the underlying persistent layer doesn't throw on individual swap failures due to
157
+ * optimistic concurrency, or other (implementation specific), this flag is to be used when the saving of the swap
158
+ * isn't mission-critical for executing next steps (e.g. in tick or sync loops)
134
159
  */
135
- async removeAll<S extends ISwap<T>>(values: S[]): Promise<void> {
160
+ async removeAll<S extends ISwap<T>>(values: S[], lenient?: boolean): Promise<void> {
136
161
  if(!this.noWeakRefMap) values.forEach(value => this.weakRefCache.delete(value.getId()));
137
- await this.storage.removeAll(values.map(obj => obj.serialize()));
138
- values.forEach(value => value._persisted = false);
162
+ const serialized = values.map(obj => obj.serialize());
163
+ try {
164
+ await this.storage.removeAll(serialized, lenient);
165
+ } finally {
166
+ values.forEach((value, index) => {
167
+ value._meta = serialized[index]._meta;
168
+ });
169
+ }
170
+ values.forEach((value) => {
171
+ value._persisted = false;
172
+ });
139
173
  }
140
174
 
141
175
  }
@@ -65,9 +65,11 @@ import {NotNever} from "../utils/TypeUtils";
65
65
  import {IEscrowSwap} from "../swaps/escrow_swaps/IEscrowSwap";
66
66
  import {LightningInvoiceCreateService, isLightningInvoiceCreateService} from "../types/wallets/LightningInvoiceCreateService";
67
67
  import {SwapSide} from "../enums/SwapSide";
68
+ import {IntermediaryAPI} from "../intermediaries/apis/IntermediaryAPI";
68
69
  import {BitcoinWalletUtxo, BitcoinWalletUtxoBase, IBitcoinWallet} from "../bitcoin/wallet/IBitcoinWallet";
69
70
  import {MinimalBitcoinWalletInterface} from "../types/wallets/MinimalBitcoinWalletInterface";
70
71
  import {toBitcoinWallet} from "../utils/BitcoinWalletUtils";
72
+ import {getSignedKeyBasedAuthHandler} from "../intermediaries/auth/SignedKeyBasedAuth";
71
73
 
72
74
  /**
73
75
  * Configuration options for the Swapper
@@ -129,8 +131,9 @@ export type SwapperOptions = {
129
131
  noTimers?: boolean,
130
132
  /**
131
133
  * By setting this flag, the swapper doesn't subscribe to on-chain events. To make sure the swap states are
132
- * properly updated you should call the {@link Swapper._syncSwaps} function periodically. This flag should be
133
- * set when you run an environment that doesn't support long-running timers and websocket connections - e.g.
134
+ * properly updated you should either call the {@link Swapper._syncSwaps} function periodically, or use the
135
+ * {@link Swapper._pollChainEvents} function to manually poll for on-chain events. This flag should be set
136
+ * when you run an environment that doesn't support long-running timers and websocket connections - e.g.
134
137
  * serverless environments like Azure Function Apps or AWS Lambda
135
138
  */
136
139
  noEvents?: boolean,
@@ -160,7 +163,7 @@ export type SwapperOptions = {
160
163
  * want to only create a swap, and then later on retrieve it with the `swapper.getSwapById()` function.
161
164
  *
162
165
  * Setting this to `false` means the SDK only saves and persists swaps that are considered initiated, i.e. when
163
- * `commit()`, `execute()` or `waitTillPayment` is called (or their respective txs... prefixed variations). This
166
+ * `commit()`, `execute()` or `waitTillPayment()` is called (or their respective txs... prefixed variations). This
164
167
  * might save calls to the persistent storage for swaps that are never initiated. This is useful in e.g.
165
168
  * frontend implementations where the frontend holds the swap object reference until it is initiated anyway, not
166
169
  * necessitating the saving of the swap data to the persistent storage until it is actually initiated.
@@ -170,7 +173,14 @@ export type SwapperOptions = {
170
173
  * Automatically checks system time on initialize, if the system time drifts too far from the actual time
171
174
  * (as checked from multiple server sources) it adjusts the `Date.now()` function to return proper actual time.
172
175
  */
173
- automaticClockDriftCorrection?: boolean
176
+ automaticClockDriftCorrection?: boolean,
177
+ /**
178
+ * Used in centralized API deployments to allow higher rate limits from LPs
179
+ */
180
+ signedKeyBasedAuth?: {
181
+ certificate: string,
182
+ privateKey: string
183
+ }
174
184
  };
175
185
 
176
186
  /**
@@ -307,6 +317,10 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
307
317
  * Pricing API used by the SDK
308
318
  */
309
319
  readonly prices: ISwapPrice<T>;
320
+ /**
321
+ * API for contacting LPs
322
+ */
323
+ readonly lpApi: IntermediaryAPI;
310
324
  /**
311
325
  * Intermediary discovery instance
312
326
  */
@@ -362,6 +376,13 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
362
376
  this._tokens[chainId][tokenData.address] = this._tokensByTicker[chainId][tokenData.ticker] = tokenData;
363
377
  }
364
378
 
379
+ const lpApi = new IntermediaryAPI(
380
+ this.options.signedKeyBasedAuth!=null
381
+ ? getSignedKeyBasedAuthHandler(this.options.signedKeyBasedAuth.certificate, this.options.signedKeyBasedAuth.privateKey)
382
+ : undefined
383
+ );
384
+ this.lpApi = lpApi;
385
+
365
386
  this.swapStateListener = (swap: ISwap) => {
366
387
  this.emit("swapState", swap);
367
388
  };
@@ -413,6 +434,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
413
434
  pricing,
414
435
  this._tokens[chainId],
415
436
  versions,
437
+ lpApi,
416
438
  {
417
439
  getRequestTimeout: this.options.getRequestTimeout,
418
440
  postRequestTimeout: this.options.postRequestTimeout,
@@ -428,6 +450,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
428
450
  this._tokens[chainId],
429
451
  versions,
430
452
  this._bitcoinRpc,
453
+ lpApi,
431
454
  {
432
455
  getRequestTimeout: this.options.getRequestTimeout,
433
456
  postRequestTimeout: this.options.postRequestTimeout,
@@ -444,6 +467,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
444
467
  this._tokens[chainId],
445
468
  versions,
446
469
  lightningApi,
470
+ lpApi,
447
471
  {
448
472
  getRequestTimeout: this.options.getRequestTimeout,
449
473
  postRequestTimeout: this.options.postRequestTimeout,
@@ -461,6 +485,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
461
485
  versions,
462
486
  versionedContracts,
463
487
  this._bitcoinRpc,
488
+ lpApi,
464
489
  {
465
490
  getRequestTimeout: this.options.getRequestTimeout,
466
491
  postRequestTimeout: this.options.postRequestTimeout,
@@ -475,6 +500,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
475
500
  chainInterface,
476
501
  pricing,
477
502
  this._tokens[chainId],
503
+ lpApi,
478
504
  {
479
505
  getRequestTimeout: this.options.getRequestTimeout,
480
506
  postRequestTimeout: this.options.postRequestTimeout,
@@ -489,6 +515,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
489
515
  pricing,
490
516
  this._tokens[chainId],
491
517
  bitcoinRpc,
518
+ lpApi,
492
519
  {
493
520
  getRequestTimeout: this.options.getRequestTimeout,
494
521
  postRequestTimeout: this.options.postRequestTimeout,
@@ -509,6 +536,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
509
536
  versions,
510
537
  versionedContracts,
511
538
  bitcoinRpc,
539
+ lpApi,
512
540
  {
513
541
  getRequestTimeout: this.options.getRequestTimeout,
514
542
  postRequestTimeout: this.options.postRequestTimeout,
@@ -530,6 +558,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
530
558
  versions,
531
559
  lightningApi,
532
560
  this.messenger,
561
+ lpApi,
533
562
  {
534
563
  getRequestTimeout: this.options.getRequestTimeout,
535
564
  postRequestTimeout: this.options.postRequestTimeout,
@@ -566,9 +595,9 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
566
595
 
567
596
  const contracts = objectMap(chainsData, (data) => data.versions ?? {[data.defaultVersion ?? "v1"]: {swapContract: data.swapContract, spvVaultContract: data.spvVaultContract}});
568
597
  if(options.intermediaryUrl!=null) {
569
- this.intermediaryDiscovery = new IntermediaryDiscovery(contracts, options.registryUrl, Array.isArray(options.intermediaryUrl) ? options.intermediaryUrl : [options.intermediaryUrl], options.getRequestTimeout);
598
+ this.intermediaryDiscovery = new IntermediaryDiscovery(contracts, lpApi, options.registryUrl, Array.isArray(options.intermediaryUrl) ? options.intermediaryUrl : [options.intermediaryUrl], options.getRequestTimeout);
570
599
  } else {
571
- this.intermediaryDiscovery = new IntermediaryDiscovery(contracts, options.registryUrl, undefined, options.getRequestTimeout);
600
+ this.intermediaryDiscovery = new IntermediaryDiscovery(contracts, lpApi, options.registryUrl, undefined, options.getRequestTimeout);
572
601
  }
573
602
 
574
603
  this.intermediaryDiscovery.on("removed", (intermediaries: Intermediary[]) => {
@@ -581,7 +610,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
581
610
  }
582
611
 
583
612
  private async _init(): Promise<void> {
584
- this.logger.debug("init(): Initializing swapper...");
613
+ this.logger.debug("init(): Initializing swapper");
585
614
 
586
615
  const abortController = new AbortController();
587
616
 
@@ -667,7 +696,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
667
696
  )
668
697
  }
669
698
 
670
- if(!this.options.noEvents) await unifiedChainEvents.start();
699
+ await unifiedChainEvents.start(this.options.noEvents);
671
700
  this.logger.debug("init(): Intialized events: "+chainIdentifier);
672
701
 
673
702
  for(let key in wrappers) {
@@ -709,6 +738,13 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
709
738
  }
710
739
  }
711
740
 
741
+ /**
742
+ * Whether the SDK is initialized (after {@link init} is called)
743
+ */
744
+ isInitialized(): boolean {
745
+ return this.initialized;
746
+ }
747
+
712
748
  /**
713
749
  * Stops listening for onchain events and closes this Swapper instance
714
750
  */
@@ -1521,6 +1557,9 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1521
1557
  dst: string | LNURLPay | LightningInvoiceCreateService,
1522
1558
  options?: FromBTCLNOptions | SpvFromBTCOptions | FromBTCOptions | ToBTCOptions | (ToBTCLNOptions & {comment?: string}) | FromBTCLNAutoOptions
1523
1559
  ): Promise<ISwap<T[C]>> {
1560
+ if(typeof(src)==="string") src = this.Utils.stripAddress(src);
1561
+ if(typeof(dst)==="string") dst = this.Utils.stripAddress(dst);
1562
+
1524
1563
  const srcToken = typeof(_srcToken)==="string" ? this.getToken(_srcToken) as Token<C> : _srcToken;
1525
1564
  const dstToken = typeof(_dstToken)==="string" ? this.getToken(_dstToken) as Token<C> : _dstToken;
1526
1565
  const amount = _amount==null ? null : (typeof(_amount)==="bigint" ? _amount : fromDecimal(_amount, exactIn ? srcToken.decimals : dstToken.decimals));
@@ -1634,7 +1673,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1634
1673
  const bitcoinFeeRatePromise = options?.bitcoinFeeRate ?? wallet.getFeeRate();
1635
1674
 
1636
1675
  const swap = await this.createFromBTCSwapNew(
1637
- dstToken.chainId, dstAddress, dstToken.address, null, false, undefined, {
1676
+ dstToken.chainId as C, dstAddress, dstToken.address, null, false, undefined, {
1638
1677
  ...options,
1639
1678
  sourceWalletUtxos: walletUtxosPromise,
1640
1679
  bitcoinFeeRate: bitcoinFeeRatePromise
@@ -1673,14 +1712,14 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1673
1712
  }
1674
1713
 
1675
1714
  /**
1676
- * Returns all swaps where an action is required (either claim or refund)
1715
+ * Returns all swaps which are pending (i.e. not in their final state yet)
1677
1716
  */
1678
- getActionableSwaps(): Promise<ISwap[]>;
1717
+ getPendingSwaps(): Promise<ISwap[]>;
1679
1718
  /**
1680
- * Returns swaps where an action is required (either claim or refund) for the specific chain, and optionally also for a specific signer's address
1719
+ * Returns swaps which are pending (i.e. not in their final state yet) for the specific chain, and optionally also for a specific signer's address
1681
1720
  */
1682
- getActionableSwaps<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<ISwap<T[C]>[]>;
1683
- async getActionableSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<ISwap[]> {
1721
+ getPendingSwaps<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<ISwap<T[C]>[]>;
1722
+ async getPendingSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<ISwap[]> {
1684
1723
  if(chainId==null) {
1685
1724
  const res: ISwap[][] = await Promise.all(Object.keys(this._chains).map((chainId) => {
1686
1725
  const {unifiedSwapStorage, reviver, wrappers} = this._chains[chainId];
@@ -1694,7 +1733,7 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1694
1733
  }
1695
1734
  return unifiedSwapStorage.query(queryParams, reviver);
1696
1735
  }));
1697
- return res.flat().filter(swap => swap.requiresAction());
1736
+ return res.flat();
1698
1737
  } else {
1699
1738
  const {unifiedSwapStorage, reviver, wrappers} = this._chains[chainId];
1700
1739
  const queryParams: Array<QueryParams[]> = [];
@@ -1705,7 +1744,23 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1705
1744
  swapTypeQueryParams.push({key: "state", value: wrapper._pendingSwapStates});
1706
1745
  queryParams.push(swapTypeQueryParams);
1707
1746
  }
1708
- return (await unifiedSwapStorage.query(queryParams, reviver)).filter(swap => swap.requiresAction());
1747
+ return await unifiedSwapStorage.query(queryParams, reviver);
1748
+ }
1749
+ }
1750
+
1751
+ /**
1752
+ * Returns all swaps where an action is required (either claim or refund)
1753
+ */
1754
+ getActionableSwaps(): Promise<ISwap[]>;
1755
+ /**
1756
+ * Returns swaps where an action is required (either claim or refund) for the specific chain, and optionally also for a specific signer's address
1757
+ */
1758
+ getActionableSwaps<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<ISwap<T[C]>[]>;
1759
+ async getActionableSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<ISwap[]> {
1760
+ if(chainId==null) {
1761
+ return (await this.getPendingSwaps()).filter(swap => swap.requiresAction());
1762
+ } else {
1763
+ return (await this.getPendingSwaps(chainId, signer)).filter(swap => swap.requiresAction());
1709
1764
  }
1710
1765
  }
1711
1766
 
@@ -1903,8 +1958,8 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1903
1958
  }
1904
1959
 
1905
1960
  this.logger.debug("_syncSwaps(): Done syncing "+swaps.length+" swaps, saving "+changedSwaps.length+" changed swaps, removing "+removeSwaps.length+" swaps!");
1906
- await unifiedSwapStorage.saveAll(changedSwaps);
1907
- await unifiedSwapStorage.removeAll(removeSwaps);
1961
+ await unifiedSwapStorage.saveAll(changedSwaps, true);
1962
+ await unifiedSwapStorage.removeAll(removeSwaps, true);
1908
1963
 
1909
1964
  changedSwaps.forEach(swap => swap._emitEvent());
1910
1965
  removeSwaps.forEach(swap => swap._emitEvent());
@@ -1961,6 +2016,20 @@ export class Swapper<T extends MultiChain> extends EventEmitter<{
1961
2016
  }
1962
2017
  }
1963
2018
 
2019
+ /**
2020
+ * When the swapper is initiated with the `noEvents` config this function allows you to manually poll for on-chain
2021
+ * events. It returns an events cursor which you should save and pass to the next call to the `poll()` function.
2022
+ *
2023
+ * @param chainId Chain for which to poll the chain events listener for
2024
+ * @param lastEventCursorState Event cursor state returned from the last call to the `poll()` function
2025
+ */
2026
+ async _pollChainEvents<C extends ChainIds<T>>(chainId: C, lastEventCursorState?: any): Promise<any> {
2027
+ const chain = this._chains[chainId];
2028
+ if(chain==null) throw new Error(`Invalid chain id ${chainId}!`);
2029
+
2030
+ return chain.unifiedChainEvents.poll(lastEventCursorState);
2031
+ }
2032
+
1964
2033
  /**
1965
2034
  * Recovers swaps from on-chain historical data.
1966
2035
  *
@@ -337,6 +337,22 @@ export class SwapperUtils<T extends MultiChain> {
337
337
  return this.parseSmartchainAddress(addressString);
338
338
  }
339
339
 
340
+ /**
341
+ * Strips the URL encoding around `bitcoin:` and `lightning:` addresses, leaving just the raw address
342
+ *
343
+ * @param addressString Address to strip
344
+ *
345
+ * @returns Raw clean address
346
+ */
347
+ stripAddress(addressString: string): string {
348
+ if(addressString.startsWith("lightning:") || addressString.startsWith("bitcoin:")) {
349
+ addressString = addressString.substring(addressString.indexOf(":")+1);
350
+ const delimeterIndex = addressString.indexOf("?");
351
+ if(delimeterIndex!==-1) addressString = addressString.substring(0, delimeterIndex);
352
+ }
353
+ return addressString;
354
+ }
355
+
340
356
  /**
341
357
  * Returns a random PSBT that can be used for fee estimation for SPV vault (UTXO-controlled vault) based swaps
342
358
  * {@link SwapType.SPV_VAULT_FROM_BTC}, the last output (the LP output) is omitted to allow for coinselection
@@ -477,11 +493,18 @@ export class SwapperUtils<T extends MultiChain> {
477
493
  }
478
494
 
479
495
  /**
480
- * Returns a random address for a given smart chain
496
+ * Returns a random address for a given smart chain or bitcoin
481
497
  *
482
498
  * @param chainIdentifier
483
499
  */
484
- randomAddress<ChainIdentifier extends ChainIds<T>>(chainIdentifier: ChainIdentifier): string {
500
+ randomAddress<ChainIdentifier extends ChainIds<T>>(chainIdentifier: ChainIdentifier | "BITCOIN"): string {
501
+ if(chainIdentifier==="BITCOIN") {
502
+ // Return random p2wkh address
503
+ return Address(this.bitcoinNetwork).encode({
504
+ type: "wpkh",
505
+ hash: randomBytes(20)
506
+ });
507
+ }
485
508
  if(this.root._chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
486
509
  return this.root._chains[chainIdentifier].chainInterface.randomAddress();
487
510
  }
@@ -524,6 +547,23 @@ export class SwapperUtils<T extends MultiChain> {
524
547
  return this.root._chains[chainIdentifier].chainInterface.sendSignedAndConfirm(txs, true, abortSignal, false, onBeforePublish);
525
548
  }
526
549
 
550
+ /**
551
+ * Prepares a set of unsigned transactions for signing, by adding required nonces or recent blockhashes, might
552
+ * also add hints of account deployment on e.g. Starknet
553
+ *
554
+ * @param chainIdentifier A chain for which to prepare the txs
555
+ * @param txs Transactions to prepare
556
+ */
557
+ prepareUnsignedTransactions<ChainIdentifier extends ChainIds<T>>(
558
+ chainIdentifier: ChainIdentifier,
559
+ txs: T[ChainIdentifier]["TX"][]
560
+ ): Promise<T[ChainIdentifier]["TX"][]> {
561
+ if(this.root._chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
562
+ const chainInterface = this.root._chains[chainIdentifier].chainInterface;
563
+ if(chainInterface.prepareTxs==null) throw new Error("Chain doesn't support tx preparation, chainId: "+chainIdentifier);
564
+ return chainInterface.prepareTxs(txs);
565
+ }
566
+
527
567
  /**
528
568
  * Serializes an unsigned smart chain transaction
529
569
  *