@atomiqlabs/sdk 8.4.4 → 8.6.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 (80) 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 +36 -24
  10. package/dist/swapper/Swapper.js +20 -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 +4 -2
  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 +13 -17
  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 +8 -6
  37. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +12 -3
  38. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +32 -1
  39. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +8 -5
  40. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +3 -3
  41. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +4 -4
  42. package/dist/types/Token.d.ts +65 -25
  43. package/dist/types/Token.js +28 -13
  44. package/dist/types/TokenAmount.d.ts +2 -2
  45. package/dist/types/fees/Fee.d.ts +3 -3
  46. package/dist/utils/Utils.d.ts +1 -0
  47. package/dist/utils/Utils.js +17 -1
  48. package/package.json +1 -1
  49. package/src/enums/SwapSide.ts +16 -0
  50. package/src/index.ts +1 -0
  51. package/src/intermediaries/apis/IntermediaryAPI.ts +4 -4
  52. package/src/storage/UnifiedSwapStorage.ts +2 -0
  53. package/src/swapper/Swapper.ts +56 -40
  54. package/src/swapper/SwapperWithChain.ts +15 -10
  55. package/src/swapper/SwapperWithSigner.ts +8 -3
  56. package/src/swaps/IBTCWalletSwap.ts +1 -1
  57. package/src/swaps/ISwap.ts +5 -3
  58. package/src/swaps/ISwapWithGasDrop.ts +1 -1
  59. package/src/swaps/ISwapWrapper.ts +24 -23
  60. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +3 -3
  61. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +8 -8
  62. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +5 -5
  63. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +48 -22
  64. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +4 -4
  65. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +57 -21
  66. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +3 -3
  67. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +57 -22
  68. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +7 -7
  69. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +1 -1
  70. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +80 -37
  71. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +1 -1
  72. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +12 -3
  73. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +21 -9
  74. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +53 -11
  75. package/src/swaps/trusted/ln/LnForGasSwap.ts +3 -3
  76. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +4 -4
  77. package/src/types/Token.ts +98 -32
  78. package/src/types/TokenAmount.ts +5 -7
  79. package/src/types/fees/Fee.ts +3 -3
  80. package/src/utils/Utils.ts +18 -2
@@ -25,11 +25,17 @@ import {UnifiedSwapStorage} from "../../../../storage/UnifiedSwapStorage";
25
25
  import {ISwap} from "../../../ISwap";
26
26
  import {AmountData} from "../../../../types/AmountData";
27
27
  import {tryWithRetries} from "../../../../utils/RetryUtils";
28
- import {AllOptional, AllRequired} from "../../../../utils/TypeUtils";
28
+ import {AllOptional} from "../../../../utils/TypeUtils";
29
29
  import {ToBTCSwapState} from "../IToBTCSwap";
30
30
 
31
31
  export type ToBTCOptions = {
32
+ /**
33
+ * @deprecated Ignored by the LP anyway
34
+ */
32
35
  confirmationTarget?: number,
36
+ /**
37
+ * @deprecated Default 2 confirmations should be enough for any currently supported amount by atomiq
38
+ */
33
39
  confirmations?: number
34
40
  }
35
41
 
@@ -154,7 +160,10 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
154
160
  resp: ToBTCResponseType,
155
161
  amountData: AmountData,
156
162
  lp: Intermediary,
157
- options: AllRequired<ToBTCOptions>,
163
+ options: {
164
+ confirmations: number,
165
+ confirmationTarget: number
166
+ },
158
167
  data: T["Data"],
159
168
  hash: string
160
169
  ): void {
@@ -220,7 +229,7 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
220
229
  intermediary: Intermediary
221
230
  }[] {
222
231
  if(!this.isInitialized) throw new Error("Not initialized, call init() first!");
223
- const _options: AllRequired<ToBTCOptions> = {
232
+ const _options = {
224
233
  confirmationTarget: options?.confirmationTarget ?? 3,
225
234
  confirmations: options?.confirmations ?? 2
226
235
  };
@@ -193,6 +193,8 @@ export class SpvFromBTCSwap<T extends ChainType>
193
193
  extends ISwap<T, SpvFromBTCTypeDefinition<T>>
194
194
  implements IBTCWalletSwap, ISwapWithGasDrop<T>, IClaimableSwap<T, SpvFromBTCTypeDefinition<T>, SpvFromBTCSwapState> {
195
195
 
196
+ protected readonly currentVersion: number = 2;
197
+
196
198
  readonly TYPE: SwapType.SPV_VAULT_FROM_BTC = SwapType.SPV_VAULT_FROM_BTC;
197
199
 
198
200
  /**
@@ -240,6 +242,8 @@ export class SpvFromBTCSwap<T extends ChainType>
240
242
 
241
243
  private readonly gasPricingInfo?: PriceInfoType;
242
244
 
245
+ private posted?: boolean;
246
+
243
247
  /**
244
248
  * @internal
245
249
  */
@@ -337,6 +341,7 @@ export class SpvFromBTCSwap<T extends ChainType>
337
341
  this._frontTxId = initOrObject.frontTxId;
338
342
  this.gasPricingInfo = deserializePriceInfoType(initOrObject.gasPricingInfo);
339
343
  this.btcTxConfirmedAt = initOrObject.btcTxConfirmedAt;
344
+ this.posted = initOrObject.posted;
340
345
  if(initOrObject.data!=null) this._data = new this.wrapper._spvWithdrawalDataDeserializer(initOrObject.data);
341
346
  }
342
347
  this.tryCalculateSwapFee();
@@ -347,7 +352,12 @@ export class SpvFromBTCSwap<T extends ChainType>
347
352
  * @inheritDoc
348
353
  * @internal
349
354
  */
350
- protected upgradeVersion() { /*NOOP*/ }
355
+ protected upgradeVersion() {
356
+ if(this.version===1) {
357
+ this.posted = this.initiated;
358
+ this.version = 2;
359
+ }
360
+ }
351
361
 
352
362
  /**
353
363
  * @inheritDoc
@@ -582,7 +592,7 @@ export class SpvFromBTCSwap<T extends ChainType>
582
592
  *
583
593
  * @internal
584
594
  */
585
- protected getOutputWithoutFee(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
595
+ protected getOutputWithoutFee(): TokenAmount<SCToken<T["ChainId"]>, true> {
586
596
  return toTokenAmount(
587
597
  (this.outputTotalSwap * (100_000n + this.callerFeeShare + this.frontingFeeShare + this.executionFeeShare) / 100_000n) + (this.swapFee ?? 0n),
588
598
  this.wrapper._tokens[this.outputSwapToken], this.wrapper._prices, this.pricingInfo
@@ -704,21 +714,21 @@ export class SpvFromBTCSwap<T extends ChainType>
704
714
  /**
705
715
  * @inheritDoc
706
716
  */
707
- getOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
717
+ getOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
708
718
  return toTokenAmount(this.outputTotalSwap, this.wrapper._tokens[this.outputSwapToken], this.wrapper._prices, this.pricingInfo);
709
719
  }
710
720
 
711
721
  /**
712
722
  * @inheritDoc
713
723
  */
714
- getGasDropOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
724
+ getGasDropOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
715
725
  return toTokenAmount(this.outputTotalGas, this.wrapper._tokens[this.outputGasToken], this.wrapper._prices, this.gasPricingInfo);
716
726
  }
717
727
 
718
728
  /**
719
729
  * @inheritDoc
720
730
  */
721
- getInputWithoutFee(): TokenAmount<T["ChainId"], BtcToken<false>, true> {
731
+ getInputWithoutFee(): TokenAmount<BtcToken<false>, true> {
722
732
  return toTokenAmount(this.getInputAmountWithoutFee(), BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo);
723
733
  }
724
734
 
@@ -732,7 +742,7 @@ export class SpvFromBTCSwap<T extends ChainType>
732
742
  /**
733
743
  * @inheritDoc
734
744
  */
735
- getInput(): TokenAmount<T["ChainId"], BtcToken<false>, true> {
745
+ getInput(): TokenAmount<BtcToken<false>, true> {
736
746
  return toTokenAmount(this.btcAmount, BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo);
737
747
  }
738
748
 
@@ -973,6 +983,7 @@ export class SpvFromBTCSwap<T extends ChainType>
973
983
 
974
984
  this._data = data;
975
985
  this.initiated = true;
986
+ this.posted = true;
976
987
  await this._saveAndEmit(SpvFromBTCSwapState.SIGNED);
977
988
 
978
989
  try {
@@ -996,7 +1007,7 @@ export class SpvFromBTCSwap<T extends ChainType>
996
1007
  /**
997
1008
  * @inheritDoc
998
1009
  */
999
- async estimateBitcoinFee(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number): Promise<TokenAmount<any, BtcToken<false>, true> | null> {
1010
+ async estimateBitcoinFee(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number): Promise<TokenAmount<BtcToken<false>, true> | null> {
1000
1011
  const bitcoinWallet: IBitcoinWallet = toBitcoinWallet(_bitcoinWallet, this.wrapper._btcRpc, this.wrapper._options.bitcoinNetwork);
1001
1012
  const txFee = await bitcoinWallet.getFundedPsbtFee((await this.getPsbt()).psbt, feeRate);
1002
1013
  if(txFee==null) return null;
@@ -1186,7 +1197,7 @@ export class SpvFromBTCSwap<T extends ChainType>
1186
1197
  if(
1187
1198
  this._state!==SpvFromBTCSwapState.POSTED &&
1188
1199
  this._state!==SpvFromBTCSwapState.BROADCASTED &&
1189
- !(this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED && this.initiated)
1200
+ !(this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED && this.posted)
1190
1201
  ) throw new Error("Must be in POSTED or BROADCASTED state!");
1191
1202
  if(this._data==null) throw new Error("Expected swap to have withdrawal data filled!");
1192
1203
 
@@ -1529,6 +1540,7 @@ export class SpvFromBTCSwap<T extends ChainType>
1529
1540
  executionFeeShare: this.executionFeeShare.toString(10),
1530
1541
  genesisSmartChainBlockHeight: this._genesisSmartChainBlockHeight,
1531
1542
  gasPricingInfo: serializePriceInfoType(this.gasPricingInfo),
1543
+ posted: this.posted,
1532
1544
 
1533
1545
  senderAddress: this._senderAddress,
1534
1546
  claimTxId: this._claimTxId,
@@ -1704,7 +1716,7 @@ export class SpvFromBTCSwap<T extends ChainType>
1704
1716
  }
1705
1717
  }
1706
1718
 
1707
- if(this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED && !this.initiated) {
1719
+ if(this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED && !this.posted) {
1708
1720
  if(this.expiry<Date.now()) {
1709
1721
  this._state = SpvFromBTCSwapState.QUOTE_EXPIRED;
1710
1722
  if(save) await this._saveAndEmit();
@@ -32,13 +32,47 @@ import {ISwap} from "../ISwap";
32
32
  import {IClaimableSwapWrapper} from "../IClaimableSwapWrapper";
33
33
  import {AmountData} from "../../types/AmountData";
34
34
  import {tryWithRetries} from "../../utils/RetryUtils";
35
- import {AllOptional, AllRequired} from "../../utils/TypeUtils";
35
+ import {AllOptional} from "../../utils/TypeUtils";
36
+ import {fromHumanReadableString} from "../../utils/TokenUtils";
37
+ import {UserError} from "../../errors/UserError";
36
38
 
37
39
  export type SpvFromBTCOptions = {
38
- gasAmount?: bigint,
40
+ /**
41
+ * Optional additional native token to receive as an output of the swap (e.g. STRK on Starknet or cBTC on Citrea).
42
+ *
43
+ * When passed as a `bigint` it is specified in base units of the token and in `string` it is the human readable
44
+ * decimal format.
45
+ */
46
+ gasAmount?: bigint | string,
47
+ /**
48
+ * The LP enforces a minimum bitcoin fee rate in sats/vB for the swap transaction. With this config you can optionally
49
+ * limit how high of a minimum fee rate would you accept.
50
+ *
51
+ * By default the maximum allowed fee rate is calculated dynamically based on current bitcoin fee rate as:
52
+ *
53
+ * `maxAllowedBitcoinFeeRate` = 10 + `currentBitcoinFeeRate` * 1.5
54
+ */
55
+ maxAllowedBitcoinFeeRate?: number,
56
+ /**
57
+ * A flag to attach 0 watchtower fee to the swap, this would make the settlement unattractive for the watchtowers
58
+ * and therefore automatic settlement for such swaps will not be possible, you will have to settle manually
59
+ * with {@link FromBTCLNSwap.claim} or {@link FromBTCLNSwap.txsClaim} functions.
60
+ */
39
61
  unsafeZeroWatchtowerFee?: boolean,
62
+ /**
63
+ * A safety factor to use when estimating the watchtower fee to attach to the swap (this has to cover the gas fee
64
+ * of watchtowers settling the swap). A higher multiple here would mean that a swap is more attractive for
65
+ * watchtowers to settle automatically.
66
+ *
67
+ * Uses a `1.25` multiple by default (i.e. the current network fee is multiplied by 1.25 and then used to estimate
68
+ * the settlement gas fee cost)
69
+ */
40
70
  feeSafetyFactor?: number,
41
- maxAllowedNetworkFeeRate?: number
71
+
72
+ /**
73
+ * @deprecated Use `maxAllowedBitcoinFeeRate` instead!
74
+ */
75
+ maxAllowedNetworkFeeRate?: number,
42
76
  };
43
77
 
44
78
  export type SpvFromBTCWrapperOptions = ISwapWrapperOptions & {
@@ -275,7 +309,10 @@ export class SpvFromBTCWrapper<
275
309
  */
276
310
  private async preFetchCallerFeeShare(
277
311
  amountData: AmountData,
278
- options: AllRequired<SpvFromBTCOptions>,
312
+ options: {
313
+ unsafeZeroWatchtowerFee: boolean,
314
+ feeSafetyFactor: number
315
+ },
279
316
  pricePrefetch: Promise<bigint | undefined>,
280
317
  nativeTokenPricePrefetch: Promise<bigint | undefined> | undefined,
281
318
  abortController: AbortController
@@ -355,7 +392,9 @@ export class SpvFromBTCWrapper<
355
392
  resp: SpvFromBTCPrepareResponseType,
356
393
  amountData: AmountData,
357
394
  lp: Intermediary,
358
- options: SpvFromBTCOptions,
395
+ options: {
396
+ gasAmount: bigint
397
+ },
359
398
  callerFeeShare: bigint,
360
399
  bitcoinFeeRatePromise: Promise<number | undefined>,
361
400
  abortSignal: AbortSignal
@@ -438,7 +477,7 @@ export class SpvFromBTCWrapper<
438
477
  throw new IntermediaryError("Invalid amount0 multiplier used, rawAmount diff too high");
439
478
  if(resp.total !== adjustedAmount) throw new IntermediaryError("Invalid total returned");
440
479
  }
441
- if(options.gasAmount==null || options.gasAmount===0n) {
480
+ if(options.gasAmount===0n) {
442
481
  if(resp.totalGas !== 0n) throw new IntermediaryError("Invalid gas total returned");
443
482
  } else {
444
483
  //Check the difference between amount adjusted due to scaling to raw amount
@@ -548,13 +587,16 @@ export class SpvFromBTCWrapper<
548
587
  quote: Promise<SpvFromBTCSwap<T>>,
549
588
  intermediary: Intermediary
550
589
  }[] {
551
- const _options: AllRequired<SpvFromBTCOptions> = {
552
- gasAmount: options?.gasAmount ?? 0n,
590
+ const _options = {
591
+ gasAmount: this.parseGasAmount(options?.gasAmount),
553
592
  unsafeZeroWatchtowerFee: options?.unsafeZeroWatchtowerFee ?? false,
554
593
  feeSafetyFactor: options?.feeSafetyFactor ?? 1.25,
555
- maxAllowedNetworkFeeRate: options?.maxAllowedNetworkFeeRate ?? Infinity
594
+ maxAllowedBitcoinFeeRate: options?.maxAllowedBitcoinFeeRate ?? options?.maxAllowedNetworkFeeRate ?? Infinity
556
595
  };
557
596
 
597
+ if(amountData.token===this._chain.getNativeCurrencyAddress() && _options.gasAmount!==0n)
598
+ throw new UserError("Cannot specify `gasAmount` for swaps to a native token!");
599
+
558
600
  const _abortController = extendAbortController(abortSignal);
559
601
  const pricePrefetchPromise: Promise<bigint | undefined> = this.preFetchPrice(amountData, _abortController.signal);
560
602
  const usdPricePrefetchPromise: Promise<number | undefined> = this.preFetchUsdPrice(_abortController.signal);
@@ -564,8 +606,8 @@ export class SpvFromBTCWrapper<
564
606
  undefined :
565
607
  this.preFetchPrice({token: nativeTokenAddress}, _abortController.signal);
566
608
  const callerFeePrefetchPromise = this.preFetchCallerFeeShare(amountData, _options, pricePrefetchPromise, gasTokenPricePrefetchPromise, _abortController);
567
- const bitcoinFeeRatePromise: Promise<number | undefined> = _options.maxAllowedNetworkFeeRate!=Infinity ?
568
- Promise.resolve(_options.maxAllowedNetworkFeeRate) :
609
+ const bitcoinFeeRatePromise: Promise<number | undefined> = _options.maxAllowedBitcoinFeeRate!=Infinity ?
610
+ Promise.resolve(_options.maxAllowedBitcoinFeeRate) :
569
611
  this._btcRpc.getFeeRate().then(x => this._options.maxBtcFeeOffset + (x*this._options.maxBtcFeeMultiplier)).catch(e => {
570
612
  _abortController.abort(e);
571
613
  return undefined;
@@ -318,7 +318,7 @@ export class LnForGasSwap<T extends ChainType = ChainType> extends ISwap<T, LnFo
318
318
  /**
319
319
  * @inheritDoc
320
320
  */
321
- getOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
321
+ getOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
322
322
  return toTokenAmount(
323
323
  this.outputAmount, this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()],
324
324
  this.wrapper._prices, this.pricingInfo
@@ -335,7 +335,7 @@ export class LnForGasSwap<T extends ChainType = ChainType> extends ISwap<T, LnFo
335
335
  /**
336
336
  * @inheritDoc
337
337
  */
338
- getInput(): TokenAmount<T["ChainId"], BtcToken<true>, true> {
338
+ getInput(): TokenAmount<BtcToken<true>, true> {
339
339
  const parsed = bolt11Decode(this.pr);
340
340
  const msats = parsed.millisatoshis;
341
341
  if(msats==null) throw new Error("Swap lightning invoice has no msat amount field!");
@@ -346,7 +346,7 @@ export class LnForGasSwap<T extends ChainType = ChainType> extends ISwap<T, LnFo
346
346
  /**
347
347
  * @inheritDoc
348
348
  */
349
- getInputWithoutFee(): TokenAmount<T["ChainId"], BtcToken<true>, true> {
349
+ getInputWithoutFee(): TokenAmount<BtcToken<true>, true> {
350
350
  const parsed = bolt11Decode(this.pr);
351
351
  const msats = parsed.millisatoshis;
352
352
  if(msats==null) throw new Error("Swap lightning invoice has no msat amount field!");
@@ -362,7 +362,7 @@ export class OnchainForGasSwap<T extends ChainType = ChainType> extends ISwap<T,
362
362
  /**
363
363
  * @inheritDoc
364
364
  */
365
- getOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
365
+ getOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
366
366
  return toTokenAmount(
367
367
  this.outputAmount, this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()],
368
368
  this.wrapper._prices, this.pricingInfo
@@ -379,14 +379,14 @@ export class OnchainForGasSwap<T extends ChainType = ChainType> extends ISwap<T,
379
379
  /**
380
380
  * @inheritDoc
381
381
  */
382
- getInput(): TokenAmount<T["ChainId"], BtcToken<false>, true> {
382
+ getInput(): TokenAmount<BtcToken<false>, true> {
383
383
  return toTokenAmount(this.inputAmount, BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo);
384
384
  }
385
385
 
386
386
  /**
387
387
  * @inheritDoc
388
388
  */
389
- getInputWithoutFee(): TokenAmount<T["ChainId"], BtcToken<false>, true> {
389
+ getInputWithoutFee(): TokenAmount<BtcToken<false>, true> {
390
390
  return toTokenAmount(
391
391
  this.inputAmount - (this.swapFeeBtc ?? 0n), BitcoinTokens.BTC,
392
392
  this.wrapper._prices, this.pricingInfo
@@ -526,7 +526,7 @@ export class OnchainForGasSwap<T extends ChainType = ChainType> extends ISwap<T,
526
526
  /**
527
527
  * @inheritDoc
528
528
  */
529
- async estimateBitcoinFee(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number): Promise<TokenAmount<any, BtcToken<false>, true> | null> {
529
+ async estimateBitcoinFee(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number): Promise<TokenAmount<BtcToken<false>, true> | null> {
530
530
  const bitcoinWallet: IBitcoinWallet = toBitcoinWallet(_bitcoinWallet, this.wrapper._btcRpc, this.wrapper._options.bitcoinNetwork);
531
531
  const txFee = await bitcoinWallet.getTransactionFee(this.address, this.inputAmount, feeRate);
532
532
  if(txFee==null) return null;
@@ -1,15 +1,89 @@
1
+ /**
2
+ * Type for all token types (BTC or smart chain)
3
+ *
4
+ * @category Tokens
5
+ */
6
+ export type Token<ChainIdentifier extends string = string> = {
7
+ /**
8
+ * Chain identifier for the token's chain
9
+ */
10
+ chainId: ChainIdentifier | "BITCOIN" | "LIGHTNING",
11
+
12
+ /**
13
+ * Ticker of the token
14
+ */
15
+ ticker: string,
16
+ /**
17
+ * Full name of the token
18
+ */
19
+ name: string,
20
+ /**
21
+ * Actual decimal places of the tokens
22
+ */
23
+ decimals: number,
24
+ /**
25
+ * The decimal places that should be rendered and displayed to the user
26
+ */
27
+ displayDecimals?: number,
28
+
29
+ /**
30
+ * Address of the token contract, or `""` for Bitcoin
31
+ */
32
+ address: string,
33
+
34
+ // legacy compatibility
35
+ /**
36
+ * Legacy chain identifier distinguishing between Smart Chain and Bitcoin tokens
37
+ */
38
+ chain: "SC" | "BTC",
39
+ /**
40
+ * Legacy lightning flag, determines whether a Bitcoin token is an Lightning or on-chain one
41
+ */
42
+ lightning?: boolean,
43
+
44
+ // helpers
45
+ /**
46
+ * Equality check between tokens
47
+ */
48
+ equals: (other: Token) => boolean,
49
+ /**
50
+ * Returns the
51
+ */
52
+ toString: () => string
53
+ };
54
+
55
+ /**
56
+ * Type guard for a {@link Token} type, encompassing all tokens (BTC or smart chain)
57
+ *
58
+ * @category Tokens
59
+ */
60
+ export function isToken(obj: any): obj is Token {
61
+ return typeof (obj) === "object" &&
62
+ (obj.chain === "SC" || obj.chain === "BTC") &&
63
+ typeof (obj.ticker) === "string" &&
64
+ typeof (obj.decimals) === "number" &&
65
+ typeof (obj.name) === "string";
66
+ }
67
+
1
68
  /**
2
69
  * Bitcoin token type (BTC on on-chain or lightning)
3
70
  *
4
71
  * @category Tokens
5
72
  */
6
- export type BtcToken<L = boolean> = {
7
- chain: "BTC",
8
- lightning: L,
73
+ export type BtcToken<L = boolean> = Token & {
74
+ chainId: L extends true ? "LIGHTNING" : "BITCOIN",
9
75
  ticker: "BTC",
10
- decimals: 8,
11
76
  name: L extends true ? "Bitcoin (lightning L2)" : "Bitcoin (on-chain L1)",
12
- displayDecimals?: number
77
+ decimals: 8,
78
+ displayDecimals: 8,
79
+
80
+ address: "",
81
+
82
+ // legacy compatibility
83
+ chain: "BTC",
84
+ lightning: L,
85
+
86
+ toString: () => L extends true ? "BTC-LN" : "BTC"
13
87
  };
14
88
 
15
89
  /**
@@ -37,17 +111,27 @@ export const BitcoinTokens: {
37
111
  } = {
38
112
  BTC: {
39
113
  chain: "BTC",
114
+ chainId: "BITCOIN",
40
115
  lightning: false,
41
116
  ticker: "BTC",
42
117
  decimals: 8,
43
- name: "Bitcoin (on-chain L1)"
118
+ displayDecimals: 8,
119
+ name: "Bitcoin (on-chain L1)",
120
+ address: "",
121
+ equals: (other: Token) => other.chainId==="BITCOIN" && other.ticker==="BTC",
122
+ toString: () => "BTC"
44
123
  },
45
124
  BTCLN: {
46
125
  chain: "BTC",
126
+ chainId: "LIGHTNING",
47
127
  lightning: true,
48
128
  ticker: "BTC",
49
129
  decimals: 8,
50
- name: "Bitcoin (lightning L2)"
130
+ displayDecimals: 8,
131
+ name: "Bitcoin (lightning L2)",
132
+ address: "",
133
+ equals: (other: Token) => other.chainId==="LIGHTNING" && other.ticker==="BTC",
134
+ toString: () => "BTC-LN"
51
135
  }
52
136
  };
53
137
 
@@ -56,42 +140,24 @@ export const BitcoinTokens: {
56
140
  *
57
141
  * @category Tokens
58
142
  */
59
- export type SCToken<ChainIdentifier extends string = string> = {
60
- chain: "SC",
143
+ export type SCToken<ChainIdentifier extends string = string> = Token<ChainIdentifier> & {
61
144
  chainId: ChainIdentifier,
62
- address: string,
63
- ticker: string,
64
- decimals: number,
65
- displayDecimals?: number,
66
- name: string
67
- }
145
+ chain: "SC"
146
+
147
+ toString: () => `${ChainIdentifier}-${string}`
148
+ };
68
149
 
69
150
  /**
70
151
  * Type guard for {@link SCToken} (token on the smart chain)
71
152
  * @category Tokens
72
153
  */
73
- export function isSCToken(obj: any): obj is SCToken {
154
+ export function isSCToken<ChainIdentifier extends string = string>(obj: any, chainIdentifier?: ChainIdentifier[]): obj is SCToken<ChainIdentifier> {
74
155
  return typeof (obj) === "object" &&
75
156
  obj.chain === "SC" &&
76
157
  typeof (obj.chainId) === "string" &&
158
+ (chainIdentifier==null || chainIdentifier.includes(obj.chainId)) &&
77
159
  typeof (obj.address) === "string" &&
78
160
  typeof (obj.ticker) === "string" &&
79
161
  typeof (obj.decimals) === "number" &&
80
162
  typeof (obj.name) === "string";
81
163
  }
82
-
83
- /**
84
- * Union type for all token types (BTC or smart chain)
85
- *
86
- * @category Tokens
87
- */
88
- export type Token<ChainIdentifier extends string = string> = BtcToken | SCToken<ChainIdentifier>;
89
-
90
- /**
91
- * Type guard for an union {@link Token} type, encompassing all tokens (BTC or smart chain)
92
- *
93
- * @category Tokens
94
- */
95
- export function isToken(obj: any): obj is Token {
96
- return isBtcToken(obj) || isSCToken(obj);
97
- }
@@ -9,8 +9,7 @@ import {toDecimal} from "../utils/Utils";
9
9
  * @category Tokens
10
10
  */
11
11
  export type TokenAmount<
12
- ChainIdentifier extends string = string,
13
- T extends Token<ChainIdentifier> = Token<ChainIdentifier>,
12
+ T extends Token = Token,
14
13
  Known extends boolean = boolean
15
14
  > = {
16
15
  /**
@@ -74,15 +73,14 @@ export type TokenAmount<
74
73
  * @internal
75
74
  */
76
75
  export function toTokenAmount<
77
- ChainIdentifier extends string = string,
78
- T extends Token<ChainIdentifier> = Token<ChainIdentifier>,
76
+ T extends Token = Token,
79
77
  Known extends boolean = boolean
80
78
  >(
81
79
  amount: Known extends true ? bigint : null,
82
80
  token: T,
83
81
  prices: ISwapPrice,
84
82
  pricingInfo?: PriceInfoType
85
- ): TokenAmount<ChainIdentifier, T, Known> {
83
+ ): TokenAmount<T, Known> {
86
84
  if (amount == null) return {
87
85
  rawAmount: undefined,
88
86
  amount: "",
@@ -93,7 +91,7 @@ export function toTokenAmount<
93
91
  usdValue: () => Promise.resolve(NaN),
94
92
  toString: () => "??? " + token.ticker,
95
93
  isUnknown: true
96
- } as TokenAmount<ChainIdentifier, T>;
94
+ } as TokenAmount<T>;
97
95
  const amountStr = toDecimal(amount, token.decimals, undefined, token.displayDecimals);
98
96
  const _amount = parseFloat(amountStr);
99
97
 
@@ -131,5 +129,5 @@ export function toTokenAmount<
131
129
  },
132
130
  toString: () => amountStr + " " + token.ticker,
133
131
  isUnknown: false
134
- } as TokenAmount<ChainIdentifier, T>;
132
+ } as TokenAmount<T>;
135
133
  }
@@ -16,11 +16,11 @@ export type Fee<
16
16
  /**
17
17
  * Fee value equivalent in source token
18
18
  */
19
- amountInSrcToken: TokenAmount<ChainIdentifier, TSrc, true>,
19
+ amountInSrcToken: TokenAmount<TSrc, true>,
20
20
  /**
21
21
  * Fee value equivalent in destination token
22
22
  */
23
- amountInDstToken: TokenAmount<ChainIdentifier, TDst, true>,
23
+ amountInDstToken: TokenAmount<TDst, true>,
24
24
  /**
25
25
  * Fetches the current USD value of the fee
26
26
  *
@@ -49,7 +49,7 @@ export type Fee<
49
49
  * base_fee + amount * percentage_fee
50
50
  */
51
51
  composition?: {
52
- base: TokenAmount<ChainIdentifier>,
52
+ base: TokenAmount,
53
53
  percentage: PercentagePPM
54
54
  }
55
55
  }
@@ -1,7 +1,9 @@
1
1
  import {Buffer} from "buffer";
2
2
  import {randomBytes as randomBytesNoble} from "@noble/hashes/utils";
3
3
  import {sha256} from "@noble/hashes/sha2";
4
- import {BigIntBufferUtils} from "@atomiqlabs/base";
4
+ import {BigIntBufferUtils, ChainType} from "@atomiqlabs/base";
5
+ import {IFromBTCLNWrapper} from "../swaps/escrow_swaps/frombtc/IFromBTCLNWrapper";
6
+ import {UserError} from "../errors/UserError";
5
7
 
6
8
  /**
7
9
  * Returns a promise that rejects if the passed promise resolves to `undefined` or `null`
@@ -179,4 +181,18 @@ export function toDecimal(amount: bigint, decimalCount: number, cut?: boolean, d
179
181
  if (displayDecimals === 0) return amountStr.substring(0, splitPoint);
180
182
  if (displayDecimals != null && cutTo > displayDecimals) cutTo = displayDecimals;
181
183
  return amountStr.substring(0, splitPoint) + "." + decimalPart.substring(0, cutTo);
182
- }
184
+ }
185
+
186
+ export function parseHashValueExact32Bytes(value?: Buffer | string, variableName?: string): Buffer | undefined {
187
+ let hash: Buffer | undefined;
188
+ if(typeof(value)==="string") {
189
+ if(value.length!==64)
190
+ throw new UserError(`Invalid ${variableName} length, must be exactly 64 hexadecimal characters!`)
191
+ hash = Buffer.from(value, "hex");
192
+ } else {
193
+ hash = value;
194
+ }
195
+ if(hash!=null && hash.length!==32)
196
+ throw new UserError(`Invalid ${variableName} length, must be exactly 32 bytes!`);
197
+ return hash;
198
+ }