@atomiqlabs/sdk 8.4.4 → 8.5.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 (79) hide show
  1. package/README.md +8 -8
  2. package/dist/enums/SwapSide.d.ts +15 -0
  3. package/dist/enums/SwapSide.js +19 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +2 -2
  7. package/dist/intermediaries/apis/IntermediaryAPI.js +2 -2
  8. package/dist/storage/UnifiedSwapStorage.d.ts +2 -0
  9. package/dist/swapper/Swapper.d.ts +27 -21
  10. package/dist/swapper/Swapper.js +19 -26
  11. package/dist/swapper/SwapperWithChain.d.ts +14 -18
  12. package/dist/swapper/SwapperWithChain.js +2 -2
  13. package/dist/swapper/SwapperWithSigner.d.ts +9 -13
  14. package/dist/swaps/IBTCWalletSwap.d.ts +1 -1
  15. package/dist/swaps/ISwap.js +2 -0
  16. package/dist/swaps/ISwapWithGasDrop.d.ts +1 -1
  17. package/dist/swaps/ISwapWrapper.d.ts +12 -12
  18. package/dist/swaps/ISwapWrapper.js +22 -14
  19. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.d.ts +3 -3
  20. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +8 -8
  21. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +5 -5
  22. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +23 -2
  23. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +20 -17
  24. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +4 -4
  25. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +44 -3
  26. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +9 -14
  27. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +3 -3
  28. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +20 -2
  29. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +15 -8
  30. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +7 -7
  31. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.d.ts +1 -1
  32. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +52 -6
  33. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +20 -30
  34. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.d.ts +1 -1
  35. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +6 -0
  36. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +6 -6
  37. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +32 -1
  38. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +8 -5
  39. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +3 -3
  40. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +4 -4
  41. package/dist/types/Token.d.ts +65 -25
  42. package/dist/types/Token.js +28 -13
  43. package/dist/types/TokenAmount.d.ts +2 -2
  44. package/dist/types/fees/Fee.d.ts +3 -3
  45. package/dist/utils/Utils.d.ts +1 -0
  46. package/dist/utils/Utils.js +17 -1
  47. package/package.json +1 -1
  48. package/src/enums/SwapSide.ts +16 -0
  49. package/src/index.ts +1 -0
  50. package/src/intermediaries/apis/IntermediaryAPI.ts +4 -4
  51. package/src/storage/UnifiedSwapStorage.ts +2 -0
  52. package/src/swapper/Swapper.ts +46 -37
  53. package/src/swapper/SwapperWithChain.ts +15 -10
  54. package/src/swapper/SwapperWithSigner.ts +8 -3
  55. package/src/swaps/IBTCWalletSwap.ts +1 -1
  56. package/src/swaps/ISwap.ts +2 -0
  57. package/src/swaps/ISwapWithGasDrop.ts +1 -1
  58. package/src/swaps/ISwapWrapper.ts +24 -23
  59. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +3 -3
  60. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +8 -8
  61. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +5 -5
  62. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +48 -22
  63. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +4 -4
  64. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +56 -20
  65. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +3 -3
  66. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +57 -22
  67. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +7 -7
  68. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +1 -1
  69. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +80 -37
  70. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +1 -1
  71. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +12 -3
  72. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +6 -6
  73. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +53 -11
  74. package/src/swaps/trusted/ln/LnForGasSwap.ts +3 -3
  75. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +4 -4
  76. package/src/types/Token.ts +98 -32
  77. package/src/types/TokenAmount.ts +5 -7
  78. package/src/types/fees/Fee.ts +3 -3
  79. package/src/utils/Utils.ts +18 -2
@@ -10,6 +10,8 @@ import {UnifiedSwapStorage} from "../storage/UnifiedSwapStorage";
10
10
  import {SCToken} from "../types/Token";
11
11
  import {getLogger} from "../utils/Logger";
12
12
  import {PriceInfoType} from "../types/PriceInfoType";
13
+ import {fromHumanReadableString} from "../utils/TokenUtils";
14
+ import {UserError} from "../errors/UserError";
13
15
 
14
16
  /**
15
17
  * Options for swap wrapper configuration
@@ -26,15 +28,9 @@ export type ISwapWrapperOptions = {
26
28
  *
27
29
  * @category Swaps/Base
28
30
  */
29
- export type WrapperCtorTokens<T extends MultiChain = MultiChain> = {
30
- ticker: string,
31
- name: string,
32
- chains: {[chainId in ChainIds<T>]?: {
33
- address: string,
34
- decimals: number,
35
- displayDecimals?: number
36
- }}
37
- }[];
31
+ export type WrapperCtorTokens<T extends ChainType = ChainType> = {
32
+ [tokenAddress: string]: SCToken<T["ChainId"]>
33
+ };
38
34
 
39
35
  /**
40
36
  * Type definition linking wrapper and swap types
@@ -164,22 +160,27 @@ export abstract class ISwapWrapper<
164
160
  this._prices = prices;
165
161
  this.events = events || new EventEmitter();
166
162
  this._options = options;
167
- this._tokens = {};
168
- for(let tokenData of tokens) {
169
- const chainData = tokenData.chains[chainIdentifier];
170
- if(chainData==null) continue;
171
- this._tokens[chainData.address] = {
172
- chain: "SC",
173
- chainId: this.chainIdentifier,
174
- address: chainData.address,
175
- decimals: chainData.decimals,
176
- ticker: tokenData.ticker,
177
- name: tokenData.name,
178
- displayDecimals: chainData.displayDecimals
179
- };
180
- }
163
+ this._tokens = tokens;
181
164
  }
182
165
 
166
+ /**
167
+ * Parses the provided gas amount from its `string` or `bigint` representation to `bigint` base units.
168
+ *
169
+ * Defaults to `0n` if no gasAmount is provided
170
+ *
171
+ * @param gasAmount
172
+ * @internal
173
+ */
174
+ protected parseGasAmount(gasAmount?: string | bigint): bigint {
175
+ let result: bigint | undefined | null;
176
+ if(typeof(gasAmount)==="string") {
177
+ result = fromHumanReadableString(gasAmount, this._getNativeToken());
178
+ if(result==null) throw new UserError("Invalid `gasAmount` option provided, not a numerical string!");
179
+ } else {
180
+ result = gasAmount;
181
+ }
182
+ return result ?? 0n;
183
+ }
183
184
 
184
185
  /**
185
186
  * Pre-fetches swap price for a given swap
@@ -112,7 +112,7 @@ export abstract class IEscrowSelfInitSwap<
112
112
  /**
113
113
  * Returns the transaction fee paid on the smart chain side to initiate the escrow
114
114
  */
115
- async getSmartChainNetworkFee(): Promise<TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>> {
115
+ async getSmartChainNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>> {
116
116
  const swapContract: T["Contract"] = this.wrapper._contract;
117
117
  return toTokenAmount(
118
118
  await (
@@ -131,8 +131,8 @@ export abstract class IEscrowSelfInitSwap<
131
131
  */
132
132
  abstract hasEnoughForTxFees(): Promise<{
133
133
  enoughBalance: boolean,
134
- balance: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>,
135
- required: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>
134
+ balance: TokenAmount<SCToken<T["ChainId"]>, true>,
135
+ required: TokenAmount<SCToken<T["ChainId"]>, true>
136
136
  }>;
137
137
 
138
138
 
@@ -169,19 +169,19 @@ export abstract class IFromBTCSelfInitSwap<
169
169
  /**
170
170
  * @inheritDoc
171
171
  */
172
- getOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
172
+ getOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
173
173
  return toTokenAmount(this.getSwapData().getAmount(), this.wrapper._tokens[this.getSwapData().getToken()], this.wrapper._prices, this.pricingInfo);
174
174
  }
175
175
 
176
176
  /**
177
177
  * @inheritDoc
178
178
  */
179
- abstract getInput(): TokenAmount<T["ChainId"], BtcToken>;
179
+ abstract getInput(): TokenAmount<BtcToken>;
180
180
 
181
181
  /**
182
182
  * @inheritDoc
183
183
  */
184
- getInputWithoutFee(): TokenAmount<T["ChainId"], BtcToken> {
184
+ getInputWithoutFee(): TokenAmount<BtcToken> {
185
185
  const input = this.getInput();
186
186
  if(input.rawAmount==null) return toTokenAmount(null, this.inputToken, this.wrapper._prices, this.pricingInfo);
187
187
  return toTokenAmount(input.rawAmount - this.swapFeeBtc, this.inputToken, this.wrapper._prices, this.pricingInfo);
@@ -192,8 +192,8 @@ export abstract class IFromBTCSelfInitSwap<
192
192
  */
193
193
  async hasEnoughForTxFees(): Promise<{
194
194
  enoughBalance: boolean,
195
- balance: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>,
196
- required: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>
195
+ balance: TokenAmount<SCToken<T["ChainId"]>, true>,
196
+ required: TokenAmount<SCToken<T["ChainId"]>, true>
197
197
  }> {
198
198
  const [balance, commitFee] = await Promise.all([
199
199
  this.wrapper._contract.getBalance(this._getInitiator(), this.wrapper._chain.getNativeCurrencyAddress(), false),
@@ -212,7 +212,7 @@ export abstract class IFromBTCSelfInitSwap<
212
212
  * to act as a security deposit that can be taken by the intermediary (LP) if the user doesn't go through
213
213
  * with the swap
214
214
  */
215
- getSecurityDeposit(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
215
+ getSecurityDeposit(): TokenAmount<SCToken<T["ChainId"]>, true> {
216
216
  return toTokenAmount(this.getSwapData().getSecurityDeposit(), this.wrapper._getNativeToken(), this.wrapper._prices, this.pricingInfo);
217
217
  }
218
218
 
@@ -221,7 +221,7 @@ export abstract class IFromBTCSelfInitSwap<
221
221
  * This covers the security deposit and the watchtower fee (if applicable), it is calculated a maximum of those
222
222
  * two values.
223
223
  */
224
- getTotalDeposit(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
224
+ getTotalDeposit(): TokenAmount<SCToken<T["ChainId"]>, true> {
225
225
  return toTokenAmount(this.getSwapData().getTotalDeposit(), this.wrapper._getNativeToken(), this.wrapper._prices, this.pricingInfo);
226
226
  }
227
227
 
@@ -273,7 +273,7 @@ export abstract class IFromBTCSelfInitSwap<
273
273
  * Returns the transaction fee required for the claim transaction to settle the escrow on the destination
274
274
  * smart chain
275
275
  */
276
- async getClaimNetworkFee(): Promise<TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>> {
276
+ async getClaimNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>> {
277
277
  const swapContract: T["Contract"] = this.wrapper._contract;
278
278
  return toTokenAmount(
279
279
  await swapContract.getClaimFee(this._getInitiator(), this.getSwapData()),
@@ -448,7 +448,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
448
448
  /**
449
449
  * @inheritDoc
450
450
  */
451
- getInput(): TokenAmount<T["ChainId"], BtcToken<true>> {
451
+ getInput(): TokenAmount<BtcToken<true>> {
452
452
  if(this.pr==null || !this.pr.toLowerCase().startsWith("ln"))
453
453
  return toTokenAmount(null, this.inputToken, this.wrapper._prices, this.pricingInfo);
454
454
 
@@ -461,7 +461,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
461
461
  /**
462
462
  * @inheritDoc
463
463
  */
464
- getSmartChainNetworkFee(): Promise<TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>> {
464
+ getSmartChainNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>> {
465
465
  return this.getCommitAndClaimNetworkFee();
466
466
  }
467
467
 
@@ -470,8 +470,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
470
470
  */
471
471
  async hasEnoughForTxFees(): Promise<{
472
472
  enoughBalance: boolean,
473
- balance: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>,
474
- required: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>
473
+ balance: TokenAmount<SCToken<T["ChainId"]>, true>,
474
+ required: TokenAmount<SCToken<T["ChainId"]>, true>
475
475
  }> {
476
476
  const [balance, feeRate] = await Promise.all([
477
477
  this.wrapper._contract.getBalance(this._getInitiator(), this.wrapper._chain.getNativeCurrencyAddress(), false),
@@ -1082,7 +1082,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1082
1082
  * Estimated transaction fee for commit & claim transactions combined, required
1083
1083
  * to settle the swap on the smart chain destination side.
1084
1084
  */
1085
- async getCommitAndClaimNetworkFee(): Promise<TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>> {
1085
+ async getCommitAndClaimNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>> {
1086
1086
  const swapContract: T["Contract"] = this.wrapper._contract;
1087
1087
  const feeRate = this.feeRate ?? await swapContract.getInitFeeRate(
1088
1088
  this.getSwapData().getOfferer(),
@@ -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,
16
+ extendAbortController, parseHashValueExact32Bytes,
17
17
  throwIfUndefined
18
18
  } from "../../../../utils/Utils";
19
19
  import {FromBTCLNResponseType, IntermediaryAPI} from "../../../../intermediaries/apis/IntermediaryAPI";
@@ -33,9 +33,30 @@ import {AllOptional} from "../../../../utils/TypeUtils";
33
33
  import {sha256} from "@noble/hashes/sha2";
34
34
 
35
35
  export type FromBTCLNOptions = {
36
- paymentHash?: Buffer,
36
+ /**
37
+ * Instead of letting the SDK generate the preimage/paymentHash pair internally you can pass your computed
38
+ * paymentHash here, this will create the swap with the provided payment hash. Note that you would then
39
+ * have to reveal the preimage by passing it to the {@link FromBTCLNSwap.claim} or {@link FromBTCLNSwap.txsClaim}
40
+ * functions
41
+ *
42
+ * Accepts both, a {@link Buffer} and a hexadecimal `string`
43
+ */
44
+ paymentHash?: Buffer | string,
45
+ /**
46
+ * Optional description to use for the swap lightning network invoice, keep the invoice length below 500 characters
47
+ */
37
48
  description?: string,
38
- descriptionHash?: Buffer,
49
+ /**
50
+ * Optional description hash to use for the lightning network invoice, useful when returning the invoice as part of
51
+ * an LNURL-pay service endpoint.
52
+ *
53
+ * Accepts both, a {@link Buffer} and a hexadecimal `string`
54
+ */
55
+ descriptionHash?: Buffer | string,
56
+ /**
57
+ * A flag to skip checking whether the lightning network node of the LP has enough channel liquidity to facilitate
58
+ * the swap.
59
+ */
39
60
  unsafeSkipLnNodeCheck?: boolean
40
61
  };
41
62
 
@@ -179,7 +200,10 @@ export class FromBTCLNWrapper<
179
200
  resp: FromBTCLNResponseType,
180
201
  amountData: AmountData,
181
202
  lp: Intermediary,
182
- options: FromBTCLNOptions,
203
+ options: {
204
+ descriptionHash?: Buffer,
205
+ description?: string
206
+ },
183
207
  decodedPr: PaymentRequestObject & {tagsObject: TagsObject},
184
208
  paymentHash: Buffer
185
209
  ): void {
@@ -238,22 +262,20 @@ export class FromBTCLNWrapper<
238
262
  }[] {
239
263
  if(!this.isInitialized) throw new Error("Not initialized, call init() first!");
240
264
 
241
- if(options==null) options = {};
242
- options.unsafeSkipLnNodeCheck ??= this._options.unsafeSkipLnNodeCheck;
243
-
244
- if(options.paymentHash!=null && options.paymentHash.length!==32)
245
- throw new UserError("Invalid payment hash length, must be exactly 32 bytes!");
246
-
247
- if(options.descriptionHash!=null && options.descriptionHash.length!==32)
248
- throw new UserError("Invalid description hash length");
265
+ const _options = {
266
+ paymentHash: parseHashValueExact32Bytes(options?.paymentHash, "payment hash"),
267
+ description: options?.description,
268
+ descriptionHash: parseHashValueExact32Bytes(options?.descriptionHash, "description hash"),
269
+ unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? this._options.unsafeSkipLnNodeCheck
270
+ };
249
271
 
250
- if(options.description!=null && Buffer.byteLength(options.description, "utf8") > 500)
272
+ if(_options.description!=null && Buffer.byteLength(_options.description, "utf8") > 500)
251
273
  throw new UserError("Invalid description length");
252
274
 
253
275
  let secret: Buffer | undefined;
254
276
  let paymentHash: Buffer;
255
- if(options?.paymentHash!=null) {
256
- paymentHash = options.paymentHash;
277
+ if(_options.paymentHash!=null) {
278
+ paymentHash = _options.paymentHash;
257
279
  } else {
258
280
  ({secret, paymentHash} = this.getSecretAndHash());
259
281
  }
@@ -286,8 +308,8 @@ export class FromBTCLNWrapper<
286
308
  amount: amountData.amount,
287
309
  claimer: recipient,
288
310
  token: amountData.token.toString(),
289
- description: options?.description,
290
- descriptionHash: options?.descriptionHash,
311
+ description: _options.description,
312
+ descriptionHash: _options.descriptionHash,
291
313
  exactOut: !amountData.exactIn,
292
314
  feeRate: throwIfUndefined(_preFetches.feeRatePromise),
293
315
  additionalParams
@@ -296,7 +318,7 @@ export class FromBTCLNWrapper<
296
318
  );
297
319
 
298
320
  return {
299
- lnCapacityPromise: options?.unsafeSkipLnNodeCheck ? null : this.preFetchLnCapacity(lnPublicKey),
321
+ lnCapacityPromise: _options.unsafeSkipLnNodeCheck ? null : this.preFetchLnCapacity(lnPublicKey),
300
322
  resp: await response
301
323
  };
302
324
  }, undefined, RequestError, abortController.signal);
@@ -307,7 +329,7 @@ export class FromBTCLNWrapper<
307
329
  const amountIn = (BigInt(decodedPr.millisatoshis) + 999n) / 1000n;
308
330
 
309
331
  try {
310
- this.verifyReturnedData(resp, amountData, lp, options ?? {}, decodedPr, paymentHash);
332
+ this.verifyReturnedData(resp, amountData, lp, _options, decodedPr, paymentHash);
311
333
  const [pricingInfo] = await Promise.all([
312
334
  this.verifyReturnedPrice(
313
335
  lp.services[SwapType.FROM_BTCLN], false, amountIn, resp.total,
@@ -374,8 +396,12 @@ export class FromBTCLNWrapper<
374
396
  }[]> {
375
397
  if(!this.isInitialized) throw new Error("Not initialized, call init() first!");
376
398
 
377
- if(options?.paymentHash!=null && options.paymentHash.length!==32)
378
- throw new UserError("Invalid payment hash length, must be exactly 32 bytes!");
399
+ const _options = {
400
+ paymentHash: parseHashValueExact32Bytes(options?.paymentHash, "payment hash"),
401
+ description: options?.description,
402
+ descriptionHash: parseHashValueExact32Bytes(options?.descriptionHash, "description hash"),
403
+ unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? this._options.unsafeSkipLnNodeCheck
404
+ };
379
405
 
380
406
  const abortController = extendAbortController(abortSignal);
381
407
  const preFetches = {
@@ -408,7 +434,7 @@ export class FromBTCLNWrapper<
408
434
  if((amount * 105n / 100n) > max) throw new UserError("Amount more than LNURL-withdraw maximum");
409
435
  }
410
436
 
411
- return this.create(recipient, amountData, lps, options, additionalParams, abortSignal, preFetches).map(data => {
437
+ return this.create(recipient, amountData, lps, _options, additionalParams, abortSignal, preFetches).map(data => {
412
438
  return {
413
439
  quote: data.quote.then(quote => {
414
440
  quote._setLNURLData(
@@ -589,14 +589,14 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
589
589
  /**
590
590
  * @inheritDoc
591
591
  */
592
- getInput(): TokenAmount<T["ChainId"], BtcToken<true>> {
592
+ getInput(): TokenAmount<BtcToken<true>> {
593
593
  return toTokenAmount(this.getLightningInvoiceSats(), this.inputToken, this.wrapper._prices, this.pricingInfo);
594
594
  }
595
595
 
596
596
  /**
597
597
  * @inheritDoc
598
598
  */
599
- getInputWithoutFee(): TokenAmount<T["ChainId"], BtcToken<true>> {
599
+ getInputWithoutFee(): TokenAmount<BtcToken<true>> {
600
600
  return toTokenAmount(this.getInputAmountWithoutFee(), this.inputToken, this.wrapper._prices, this.pricingInfo);
601
601
  }
602
602
 
@@ -610,14 +610,14 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
610
610
  /**
611
611
  * @inheritDoc
612
612
  */
613
- getOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
613
+ getOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
614
614
  return toTokenAmount(this.getSwapData().getAmount(), this.wrapper._tokens[this.getSwapData().getToken()], this.wrapper._prices, this.pricingInfo);
615
615
  }
616
616
 
617
617
  /**
618
618
  * @inheritDoc
619
619
  */
620
- getGasDropOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
620
+ getGasDropOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
621
621
  return toTokenAmount(
622
622
  this.getSwapData().getSecurityDeposit() - this.getSwapData().getClaimerBounty(),
623
623
  this.wrapper._tokens[this.getSwapData().getDepositToken()], this.wrapper._prices, this.gasPricingInfo
@@ -12,7 +12,7 @@ import {UserError} from "../../../../errors/UserError";
12
12
  import {IntermediaryError} from "../../../../errors/IntermediaryError";
13
13
  import {SwapType} from "../../../../enums/SwapType";
14
14
  import {
15
- extendAbortController,
15
+ extendAbortController, parseHashValueExact32Bytes,
16
16
  randomBytes,
17
17
  throwIfUndefined
18
18
  } from "../../../../utils/Utils";
@@ -35,14 +35,56 @@ import {LNURLWithdrawParamsWithUrl} from "../../../../types/lnurl/LNURLWithdraw"
35
35
  import {tryWithRetries} from "../../../../utils/RetryUtils";
36
36
  import {AllOptional} from "../../../../utils/TypeUtils";
37
37
  import {sha256} from "@noble/hashes/sha2";
38
+ import {fromHumanReadableString} from "../../../../utils/TokenUtils";
38
39
 
39
40
  export type FromBTCLNAutoOptions = {
40
- paymentHash?: Buffer,
41
+ /**
42
+ * Instead of letting the SDK generate the preimage/paymentHash pair internally you can pass your computed
43
+ * paymentHash here, this will create the swap with the provided payment hash. Note that swaps created this way
44
+ * won't settle automatically (as the SDK is missing the preimage). Once the HTLC towards the user is created in
45
+ * the {@link FromBTCLNAutoSwapState.CLAIM_COMMITED} state, you should pass the secret preimage manually in the
46
+ * {@link FromBTCLNAutoSwap.waitTillClaimed}, {@link FromBTCLNAutoSwap.claim} or {@link FromBTCLNAutoSwap.txsClaim}
47
+ * functions.
48
+ *
49
+ * Accepts both, a {@link Buffer} and a hexadecimal `string`
50
+ */
51
+ paymentHash?: Buffer | string,
52
+ /**
53
+ * Optional description to use for the swap lightning network invoice, keep the invoice length below 500 characters
54
+ */
41
55
  description?: string,
42
- descriptionHash?: Buffer,
56
+ /**
57
+ * Optional description hash to use for the lightning network invoice, useful when returning the invoice as part of
58
+ * an LNURL-pay service endpoint.
59
+ *
60
+ * Accepts both, a {@link Buffer} and a hexadecimal `string`
61
+ */
62
+ descriptionHash?: Buffer | string,
63
+ /**
64
+ * Optional additional native token to receive as an output of the swap (e.g. STRK on Starknet or cBTC on Citrea).
65
+ * When passed as a `bigint` it is specified in base units of the token and in `string` it is the human readable
66
+ * decimal format.
67
+ */
68
+ gasAmount?: bigint | string,
69
+ /**
70
+ * A flag to skip checking whether the lightning network node of the LP has enough channel liquidity to facilitate
71
+ * the swap.
72
+ */
43
73
  unsafeSkipLnNodeCheck?: boolean,
44
- gasAmount?: bigint,
74
+ /**
75
+ * A flag to attach 0 watchtower fee to the swap, this would make the settlement unattractive for the watchtowers
76
+ * and therefore automatic settlement for such swaps will not be possible, you will have to settle manually
77
+ * with {@link FromBTCLNSwap.claim} or {@link FromBTCLNSwap.txsClaim} functions.
78
+ */
45
79
  unsafeZeroWatchtowerFee?: boolean,
80
+ /**
81
+ * A safety factor to use when estimating the watchtower fee to attach to the swap (this has to cover the gas fee
82
+ * of watchtowers settling the swap). A higher multiple here would mean that a swap is more attractive for
83
+ * watchtowers to settle automatically.
84
+ *
85
+ * Uses a `1.25` multiple by default (i.e. the current network fee is multiplied by 1.25 and then used to estimate
86
+ * the settlement gas fee cost)
87
+ */
46
88
  feeSafetyFactor?: number
47
89
  };
48
90
 
@@ -326,26 +368,21 @@ export class FromBTCLNAutoWrapper<
326
368
  if(!this.isInitialized) throw new Error("Not initialized, call init() first!");
327
369
 
328
370
  const _options = {
329
- paymentHash: options?.paymentHash,
371
+ paymentHash: parseHashValueExact32Bytes(options?.paymentHash, "payment hash"),
330
372
  unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? this._options.unsafeSkipLnNodeCheck,
331
- gasAmount: options?.gasAmount ?? 0n,
373
+ gasAmount: this.parseGasAmount(options?.gasAmount),
332
374
  feeSafetyFactor: options?.feeSafetyFactor ?? 1.25, //No need to add much of a margin, since the claim should happen rather soon
333
375
  unsafeZeroWatchtowerFee: options?.unsafeZeroWatchtowerFee ?? false,
334
376
  description: options?.description,
335
- descriptionHash: options?.descriptionHash
377
+ descriptionHash: parseHashValueExact32Bytes(options?.descriptionHash, "description hash")
336
378
  };
337
379
 
338
- if(_options.paymentHash!=null && _options.paymentHash.length!==32)
339
- throw new UserError("Invalid payment hash length, must be exactly 32 bytes!");
340
-
341
- if(_options.descriptionHash!=null && _options.descriptionHash.length!==32)
342
- throw new UserError("Invalid description hash length");
380
+ if(amountData.token===this._chain.getNativeCurrencyAddress() && _options.gasAmount!==0n)
381
+ throw new UserError("Cannot specify `gasAmount` for swaps to a native token!");
343
382
 
344
383
  if(_options.description!=null && Buffer.byteLength(_options.description, "utf8") > 500)
345
384
  throw new UserError("Invalid description length");
346
385
 
347
- if(preFetches==null) preFetches = {};
348
-
349
386
  let secret: Buffer | undefined;
350
387
  let paymentHash: Buffer;
351
388
  if(_options?.paymentHash!=null) {
@@ -358,6 +395,8 @@ export class FromBTCLNAutoWrapper<
358
395
  const nativeTokenAddress = this._chain.getNativeCurrencyAddress();
359
396
 
360
397
  const _abortController = extendAbortController(abortSignal);
398
+
399
+ preFetches ??= {};
361
400
  const _preFetches = {
362
401
  pricePrefetchPromise: preFetches?.pricePrefetchPromise ?? this.preFetchPrice(amountData, _abortController.signal),
363
402
  usdPricePrefetchPromise: preFetches?.usdPricePrefetchPromise ?? this.preFetchUsdPrice(_abortController.signal),
@@ -497,18 +536,15 @@ export class FromBTCLNAutoWrapper<
497
536
  if(!this.isInitialized) throw new Error("Not initialized, call init() first!");
498
537
 
499
538
  const _options = {
500
- paymentHash: options?.paymentHash,
539
+ paymentHash: parseHashValueExact32Bytes(options?.paymentHash, "payment hash"),
501
540
  unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? this._options.unsafeSkipLnNodeCheck,
502
- gasAmount: options?.gasAmount ?? 0n,
541
+ gasAmount: this.parseGasAmount(options?.gasAmount),
503
542
  feeSafetyFactor: options?.feeSafetyFactor ?? 1.25, //No need to add much of a margin, since the claim should happen rather soon
504
543
  unsafeZeroWatchtowerFee: options?.unsafeZeroWatchtowerFee ?? false,
505
544
  description: options?.description,
506
- descriptionHash: options?.descriptionHash
545
+ descriptionHash: parseHashValueExact32Bytes(options?.descriptionHash, "description hash")
507
546
  };
508
547
 
509
- if(_options.paymentHash!=null && _options.paymentHash.length!==32)
510
- throw new UserError("Invalid payment hash length, must be exactly 32 bytes!");
511
-
512
548
  const abortController = extendAbortController(abortSignal);
513
549
  const preFetches = {
514
550
  pricePrefetchPromise: this.preFetchPrice(amountData, abortController.signal),
@@ -356,7 +356,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
356
356
  /**
357
357
  * @inheritDoc
358
358
  */
359
- getInput(): TokenAmount<T["ChainId"], BtcToken<false>> {
359
+ getInput(): TokenAmount<BtcToken<false>> {
360
360
  return toTokenAmount(this.amount ?? null, this.inputToken, this.wrapper._prices);
361
361
  }
362
362
 
@@ -365,7 +365,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
365
365
  * this amount is pre-funded by the user on the destination chain when the swap escrow
366
366
  * is initiated. For total pre-funded deposit amount see {@link getTotalDeposit}.
367
367
  */
368
- getClaimerBounty(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
368
+ getClaimerBounty(): TokenAmount<SCToken<T["ChainId"]>, true> {
369
369
  return toTokenAmount(this._data.getClaimerBounty(), this.wrapper._tokens[this._data.getDepositToken()], this.wrapper._prices);
370
370
  }
371
371
 
@@ -661,7 +661,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
661
661
  /**
662
662
  * @inheritDoc
663
663
  */
664
- async estimateBitcoinFee(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number): Promise<TokenAmount<any, BtcToken<false>, true> | null> {
664
+ async estimateBitcoinFee(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number): Promise<TokenAmount<BtcToken<false>, true> | null> {
665
665
  if(this.address==null || this.amount==null) return null;
666
666
  const bitcoinWallet: IBitcoinWallet = toBitcoinWallet(_bitcoinWallet, this.wrapper._btcRpc, this.wrapper._options.bitcoinNetwork);
667
667
  const txFee = await bitcoinWallet.getTransactionFee(this.address, this.amount, feeRate);