@atomiqlabs/sdk 8.9.0 → 8.9.2
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.
- package/LICENSE +201 -201
- package/README.md +1760 -1760
- package/api/index.d.ts +1 -1
- package/api/index.js +3 -3
- package/dist/ApiList.d.ts +37 -37
- package/dist/ApiList.js +30 -30
- package/dist/SmartChainAssets.d.ts +181 -181
- package/dist/SmartChainAssets.js +181 -181
- package/dist/api/ApiEndpoints.d.ts +393 -393
- package/dist/api/ApiEndpoints.js +2 -2
- package/dist/api/ApiParser.d.ts +10 -10
- package/dist/api/ApiParser.js +134 -134
- package/dist/api/ApiTypes.d.ts +157 -157
- package/dist/api/ApiTypes.js +75 -75
- package/dist/api/SerializedAction.d.ts +40 -40
- package/dist/api/SerializedAction.js +59 -59
- package/dist/api/SwapperApi.d.ts +50 -50
- package/dist/api/SwapperApi.js +431 -431
- package/dist/api/index.d.ts +5 -5
- package/dist/api/index.js +24 -24
- package/dist/bitcoin/coinselect2/accumulative.d.ts +7 -7
- package/dist/bitcoin/coinselect2/accumulative.js +52 -52
- package/dist/bitcoin/coinselect2/blackjack.d.ts +7 -7
- package/dist/bitcoin/coinselect2/blackjack.js +38 -38
- package/dist/bitcoin/coinselect2/index.d.ts +20 -20
- package/dist/bitcoin/coinselect2/index.js +69 -69
- package/dist/bitcoin/coinselect2/utils.d.ts +82 -82
- package/dist/bitcoin/coinselect2/utils.js +158 -158
- package/dist/bitcoin/wallet/BitcoinWallet.d.ts +113 -113
- package/dist/bitcoin/wallet/BitcoinWallet.js +335 -335
- package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +116 -116
- package/dist/bitcoin/wallet/IBitcoinWallet.js +21 -21
- package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +106 -106
- package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +196 -196
- package/dist/enums/FeeType.d.ts +15 -15
- package/dist/enums/FeeType.js +19 -19
- package/dist/enums/SwapAmountType.d.ts +15 -15
- package/dist/enums/SwapAmountType.js +19 -19
- package/dist/enums/SwapDirection.d.ts +15 -15
- package/dist/enums/SwapDirection.js +19 -19
- package/dist/enums/SwapSide.d.ts +15 -15
- package/dist/enums/SwapSide.js +19 -19
- package/dist/enums/SwapType.d.ts +75 -75
- package/dist/enums/SwapType.js +79 -79
- package/dist/errors/IntermediaryError.d.ts +13 -13
- package/dist/errors/IntermediaryError.js +27 -27
- package/dist/errors/RequestError.d.ts +32 -32
- package/dist/errors/RequestError.js +54 -54
- package/dist/errors/UserError.d.ts +8 -8
- package/dist/errors/UserError.js +16 -16
- package/dist/events/UnifiedSwapEventListener.d.ts +24 -24
- package/dist/events/UnifiedSwapEventListener.js +138 -138
- package/dist/http/HttpUtils.d.ts +29 -29
- package/dist/http/HttpUtils.js +97 -97
- package/dist/http/paramcoders/IParamReader.d.ts +8 -8
- package/dist/http/paramcoders/IParamReader.js +2 -2
- package/dist/http/paramcoders/ParamDecoder.d.ts +44 -44
- package/dist/http/paramcoders/ParamDecoder.js +137 -137
- package/dist/http/paramcoders/ParamEncoder.d.ts +20 -20
- package/dist/http/paramcoders/ParamEncoder.js +36 -36
- package/dist/http/paramcoders/SchemaVerifier.d.ts +26 -26
- package/dist/http/paramcoders/SchemaVerifier.js +145 -145
- package/dist/http/paramcoders/client/ResponseParamDecoder.d.ts +11 -11
- package/dist/http/paramcoders/client/ResponseParamDecoder.js +57 -57
- package/dist/http/paramcoders/client/StreamParamEncoder.d.ts +13 -13
- package/dist/http/paramcoders/client/StreamParamEncoder.js +26 -26
- package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +17 -17
- package/dist/http/paramcoders/client/StreamingFetchPromise.js +175 -175
- package/dist/index.d.ts +86 -86
- package/dist/index.js +159 -159
- package/dist/intermediaries/Intermediary.d.ts +178 -178
- package/dist/intermediaries/Intermediary.js +166 -166
- package/dist/intermediaries/IntermediaryDiscovery.d.ts +216 -216
- package/dist/intermediaries/IntermediaryDiscovery.js +424 -424
- package/dist/intermediaries/apis/IntermediaryAPI.d.ts +607 -607
- package/dist/intermediaries/apis/IntermediaryAPI.js +764 -764
- package/dist/intermediaries/apis/TrustedIntermediaryAPI.d.ts +155 -155
- package/dist/intermediaries/apis/TrustedIntermediaryAPI.js +137 -137
- package/dist/intermediaries/auth/SignedKeyBasedAuth.d.ts +14 -14
- package/dist/intermediaries/auth/SignedKeyBasedAuth.js +68 -68
- package/dist/lnurl/LNURL.d.ts +102 -102
- package/dist/lnurl/LNURL.js +321 -321
- package/dist/prices/RedundantSwapPrice.d.ts +110 -110
- package/dist/prices/RedundantSwapPrice.js +222 -222
- package/dist/prices/SingleSwapPrice.d.ts +34 -34
- package/dist/prices/SingleSwapPrice.js +44 -44
- package/dist/prices/SwapPriceWithChain.d.ts +107 -107
- package/dist/prices/SwapPriceWithChain.js +128 -128
- package/dist/prices/abstract/ICachedSwapPrice.d.ts +28 -28
- package/dist/prices/abstract/ICachedSwapPrice.js +62 -62
- package/dist/prices/abstract/IPriceProvider.d.ts +81 -81
- package/dist/prices/abstract/IPriceProvider.js +74 -74
- package/dist/prices/abstract/ISwapPrice.d.ts +168 -168
- package/dist/prices/abstract/ISwapPrice.js +279 -279
- package/dist/prices/providers/BinancePriceProvider.d.ts +23 -23
- package/dist/prices/providers/BinancePriceProvider.js +30 -30
- package/dist/prices/providers/CoinGeckoPriceProvider.d.ts +23 -23
- package/dist/prices/providers/CoinGeckoPriceProvider.js +29 -29
- package/dist/prices/providers/CoinPaprikaPriceProvider.d.ts +25 -25
- package/dist/prices/providers/CoinPaprikaPriceProvider.js +29 -29
- package/dist/prices/providers/CustomPriceProvider.d.ts +24 -24
- package/dist/prices/providers/CustomPriceProvider.js +35 -35
- package/dist/prices/providers/KrakenPriceProvider.d.ts +38 -38
- package/dist/prices/providers/KrakenPriceProvider.js +45 -45
- package/dist/prices/providers/OKXPriceProvider.d.ts +34 -34
- package/dist/prices/providers/OKXPriceProvider.js +29 -29
- package/dist/prices/providers/abstract/ExchangePriceProvider.d.ts +17 -17
- package/dist/prices/providers/abstract/ExchangePriceProvider.js +21 -21
- package/dist/prices/providers/abstract/HttpPriceProvider.d.ts +7 -7
- package/dist/prices/providers/abstract/HttpPriceProvider.js +12 -12
- package/dist/storage/IUnifiedStorage.d.ts +127 -127
- package/dist/storage/IUnifiedStorage.js +2 -2
- package/dist/storage/UnifiedSwapStorage.d.ts +120 -120
- package/dist/storage/UnifiedSwapStorage.js +154 -154
- package/dist/storage-browser/IndexedDBUnifiedStorage.d.ts +63 -63
- package/dist/storage-browser/IndexedDBUnifiedStorage.js +298 -298
- package/dist/storage-browser/LocalStorageManager.d.ts +49 -49
- package/dist/storage-browser/LocalStorageManager.js +93 -93
- package/dist/swapper/Swapper.d.ts +765 -765
- package/dist/swapper/Swapper.js +1749 -1749
- package/dist/swapper/SwapperFactory.d.ts +135 -135
- package/dist/swapper/SwapperFactory.js +162 -162
- package/dist/swapper/SwapperUtils.d.ts +222 -222
- package/dist/swapper/SwapperUtils.js +519 -519
- package/dist/swapper/SwapperWithChain.d.ts +404 -404
- package/dist/swapper/SwapperWithChain.js +469 -469
- package/dist/swapper/SwapperWithSigner.d.ts +322 -322
- package/dist/swapper/SwapperWithSigner.js +318 -318
- package/dist/swaps/IAddressSwap.d.ts +22 -22
- package/dist/swaps/IAddressSwap.js +14 -14
- package/dist/swaps/IBTCWalletSwap.d.ts +73 -73
- package/dist/swaps/IBTCWalletSwap.js +18 -18
- package/dist/swaps/IClaimableSwap.d.ts +49 -49
- package/dist/swaps/IClaimableSwap.js +15 -15
- package/dist/swaps/IClaimableSwapWrapper.d.ts +15 -15
- package/dist/swaps/IClaimableSwapWrapper.js +2 -2
- package/dist/swaps/IRefundableSwap.d.ts +43 -43
- package/dist/swaps/IRefundableSwap.js +14 -14
- package/dist/swaps/ISwap.d.ts +453 -453
- package/dist/swaps/ISwap.js +371 -371
- package/dist/swaps/ISwapWithGasDrop.d.ts +21 -21
- package/dist/swaps/ISwapWithGasDrop.js +12 -12
- package/dist/swaps/ISwapWrapper.d.ts +295 -295
- package/dist/swaps/ISwapWrapper.js +373 -373
- package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.d.ts +98 -98
- package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +126 -126
- package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +139 -139
- package/dist/swaps/escrow_swaps/IEscrowSwap.js +172 -172
- package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +129 -129
- package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +167 -167
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +107 -107
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +130 -130
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +162 -162
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +190 -190
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +64 -64
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +82 -82
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +547 -547
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +1419 -1419
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +192 -192
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +432 -432
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +650 -650
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +1577 -1577
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +237 -237
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +525 -525
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +491 -491
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +1463 -1463
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +204 -204
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +406 -406
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +446 -446
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +1097 -1097
- package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +68 -68
- package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +117 -117
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.d.ts +127 -127
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +256 -256
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +252 -252
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +535 -535
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.d.ts +73 -73
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +155 -155
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +134 -134
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +286 -286
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +694 -694
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +1687 -1687
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +259 -259
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +947 -947
- package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +302 -302
- package/dist/swaps/trusted/ln/LnForGasSwap.js +625 -625
- package/dist/swaps/trusted/ln/LnForGasWrapper.d.ts +40 -40
- package/dist/swaps/trusted/ln/LnForGasWrapper.js +82 -82
- package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +343 -343
- package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +698 -698
- package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +71 -71
- package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +93 -93
- package/dist/types/AmountData.d.ts +10 -10
- package/dist/types/AmountData.js +2 -2
- package/dist/types/CustomPriceFunction.d.ts +11 -11
- package/dist/types/CustomPriceFunction.js +2 -2
- package/dist/types/PriceInfoType.d.ts +28 -28
- package/dist/types/PriceInfoType.js +57 -57
- package/dist/types/SwapExecutionAction.d.ts +195 -195
- package/dist/types/SwapExecutionAction.js +106 -106
- package/dist/types/SwapExecutionStep.d.ts +144 -144
- package/dist/types/SwapExecutionStep.js +87 -87
- package/dist/types/SwapStateInfo.d.ts +5 -5
- package/dist/types/SwapStateInfo.js +2 -2
- package/dist/types/SwapWithSigner.d.ts +17 -17
- package/dist/types/SwapWithSigner.js +43 -43
- package/dist/types/Token.d.ts +99 -99
- package/dist/types/Token.js +76 -76
- package/dist/types/TokenAmount.d.ts +75 -75
- package/dist/types/TokenAmount.js +85 -85
- package/dist/types/fees/Fee.d.ts +50 -50
- package/dist/types/fees/Fee.js +2 -2
- package/dist/types/fees/FeeBreakdown.d.ts +11 -11
- package/dist/types/fees/FeeBreakdown.js +2 -2
- package/dist/types/fees/PercentagePPM.d.ts +17 -17
- package/dist/types/fees/PercentagePPM.js +18 -18
- package/dist/types/lnurl/LNURLPay.d.ts +61 -61
- package/dist/types/lnurl/LNURLPay.js +31 -31
- package/dist/types/lnurl/LNURLWithdraw.d.ts +48 -48
- package/dist/types/lnurl/LNURLWithdraw.js +27 -27
- package/dist/types/wallets/LightningInvoiceCreateService.d.ts +24 -24
- package/dist/types/wallets/LightningInvoiceCreateService.js +15 -15
- package/dist/types/wallets/MinimalBitcoinWalletInterface.d.ts +23 -23
- package/dist/types/wallets/MinimalBitcoinWalletInterface.js +2 -2
- package/dist/types/wallets/MinimalLightningNetworkWalletInterface.d.ts +9 -9
- package/dist/types/wallets/MinimalLightningNetworkWalletInterface.js +2 -2
- package/dist/utils/AutomaticClockDriftCorrection.d.ts +1 -1
- package/dist/utils/AutomaticClockDriftCorrection.js +70 -70
- package/dist/utils/BitcoinUtils.d.ts +18 -18
- package/dist/utils/BitcoinUtils.js +174 -174
- package/dist/utils/BitcoinWalletUtils.d.ts +7 -7
- package/dist/utils/BitcoinWalletUtils.js +14 -14
- package/dist/utils/Logger.d.ts +7 -7
- package/dist/utils/Logger.js +12 -12
- package/dist/utils/RetryUtils.d.ts +22 -22
- package/dist/utils/RetryUtils.js +67 -67
- package/dist/utils/SwapUtils.d.ts +88 -88
- package/dist/utils/SwapUtils.js +72 -72
- package/dist/utils/TimeoutUtils.d.ts +17 -17
- package/dist/utils/TimeoutUtils.js +55 -55
- package/dist/utils/TokenUtils.d.ts +19 -19
- package/dist/utils/TokenUtils.js +37 -37
- package/dist/utils/TypeUtils.d.ts +7 -7
- package/dist/utils/TypeUtils.js +2 -2
- package/dist/utils/Utils.d.ts +69 -69
- package/dist/utils/Utils.js +214 -214
- package/package.json +46 -46
- package/src/SmartChainAssets.ts +186 -186
- package/src/api/ApiEndpoints.ts +427 -427
- package/src/api/ApiParser.ts +138 -138
- package/src/api/ApiTypes.ts +229 -229
- package/src/api/SerializedAction.ts +97 -97
- package/src/api/SwapperApi.ts +545 -545
- package/src/api/index.ts +5 -5
- package/src/bitcoin/coinselect2/accumulative.ts +69 -69
- package/src/bitcoin/coinselect2/blackjack.ts +50 -50
- package/src/bitcoin/coinselect2/index.ts +93 -93
- package/src/bitcoin/coinselect2/utils.ts +236 -236
- package/src/bitcoin/wallet/BitcoinWallet.ts +439 -439
- package/src/bitcoin/wallet/IBitcoinWallet.ts +140 -140
- package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +225 -225
- package/src/enums/FeeType.ts +15 -15
- package/src/enums/SwapAmountType.ts +16 -16
- package/src/enums/SwapDirection.ts +15 -15
- package/src/enums/SwapSide.ts +16 -16
- package/src/enums/SwapType.ts +75 -75
- package/src/errors/IntermediaryError.ts +28 -28
- package/src/errors/RequestError.ts +64 -64
- package/src/errors/UserError.ts +15 -15
- package/src/events/UnifiedSwapEventListener.ts +181 -181
- package/src/http/HttpUtils.ts +97 -97
- package/src/http/paramcoders/IParamReader.ts +9 -9
- package/src/http/paramcoders/ParamDecoder.ts +145 -145
- package/src/http/paramcoders/ParamEncoder.ts +40 -40
- package/src/http/paramcoders/SchemaVerifier.ts +153 -153
- package/src/http/paramcoders/client/ResponseParamDecoder.ts +57 -57
- package/src/http/paramcoders/client/StreamParamEncoder.ts +28 -28
- package/src/http/paramcoders/client/StreamingFetchPromise.ts +194 -194
- package/src/index.ts +141 -141
- package/src/intermediaries/Intermediary.ts +280 -280
- package/src/intermediaries/IntermediaryDiscovery.ts +548 -548
- package/src/intermediaries/apis/IntermediaryAPI.ts +1247 -1247
- package/src/intermediaries/auth/SignedKeyBasedAuth.ts +69 -69
- package/src/lnurl/LNURL.ts +402 -402
- package/src/prices/RedundantSwapPrice.ts +264 -264
- package/src/prices/SingleSwapPrice.ts +50 -50
- package/src/prices/SwapPriceWithChain.ts +194 -194
- package/src/prices/abstract/ICachedSwapPrice.ts +85 -85
- package/src/prices/abstract/IPriceProvider.ts +127 -127
- package/src/prices/abstract/ISwapPrice.ts +390 -390
- package/src/prices/providers/BinancePriceProvider.ts +48 -48
- package/src/prices/providers/CoinGeckoPriceProvider.ts +46 -46
- package/src/prices/providers/CoinPaprikaPriceProvider.ts +49 -49
- package/src/prices/providers/CustomPriceProvider.ts +40 -40
- package/src/prices/providers/KrakenPriceProvider.ts +83 -83
- package/src/prices/providers/OKXPriceProvider.ts +59 -59
- package/src/prices/providers/abstract/ExchangePriceProvider.ts +31 -31
- package/src/prices/providers/abstract/HttpPriceProvider.ts +14 -14
- package/src/storage/IUnifiedStorage.ts +136 -136
- package/src/storage/UnifiedSwapStorage.ts +175 -175
- package/src/storage-browser/IndexedDBUnifiedStorage.ts +350 -350
- package/src/storage-browser/LocalStorageManager.ts +106 -106
- package/src/swapper/Swapper.ts +2557 -2557
- package/src/swapper/SwapperFactory.ts +307 -307
- package/src/swapper/SwapperUtils.ts +610 -610
- package/src/swapper/SwapperWithChain.ts +707 -707
- package/src/swapper/SwapperWithSigner.ts +511 -511
- package/src/swaps/IAddressSwap.ts +30 -30
- package/src/swaps/IBTCWalletSwap.ts +92 -92
- package/src/swaps/IClaimableSwap.ts +65 -65
- package/src/swaps/IClaimableSwapWrapper.ts +17 -17
- package/src/swaps/IRefundableSwap.ts +58 -58
- package/src/swaps/ISwap.ts +775 -775
- package/src/swaps/ISwapWithGasDrop.ts +25 -25
- package/src/swaps/ISwapWrapper.ts +564 -564
- package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +217 -217
- package/src/swaps/escrow_swaps/IEscrowSwap.ts +271 -271
- package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +284 -284
- package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +172 -172
- package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +300 -300
- package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +107 -107
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +1670 -1671
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +603 -603
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +1883 -1883
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +752 -752
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +1753 -1753
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +612 -612
- package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +1327 -1327
- package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +138 -138
- package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +304 -304
- package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +787 -787
- package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +206 -206
- package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +403 -403
- package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +2148 -2148
- package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +1238 -1238
- package/src/swaps/trusted/ln/LnForGasSwap.ts +753 -753
- package/src/swaps/trusted/ln/LnForGasWrapper.ts +90 -90
- package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +843 -843
- package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +133 -133
- package/src/types/AmountData.ts +9 -9
- package/src/types/CustomPriceFunction.ts +11 -11
- package/src/types/PriceInfoType.ts +66 -66
- package/src/types/SwapExecutionAction.ts +323 -323
- package/src/types/SwapExecutionStep.ts +224 -224
- package/src/types/SwapStateInfo.ts +6 -6
- package/src/types/SwapWithSigner.ts +61 -61
- package/src/types/Token.ts +163 -163
- package/src/types/TokenAmount.ts +167 -167
- package/src/types/fees/Fee.ts +56 -56
- package/src/types/fees/FeeBreakdown.ts +11 -11
- package/src/types/fees/PercentagePPM.ts +26 -26
- package/src/types/lnurl/LNURLPay.ts +79 -79
- package/src/types/lnurl/LNURLWithdraw.ts +61 -61
- package/src/types/wallets/LightningInvoiceCreateService.ts +30 -30
- package/src/types/wallets/MinimalBitcoinWalletInterface.ts +21 -21
- package/src/types/wallets/MinimalLightningNetworkWalletInterface.ts +9 -9
- package/src/utils/AutomaticClockDriftCorrection.ts +71 -71
- package/src/utils/BitcoinUtils.ts +164 -164
- package/src/utils/BitcoinWalletUtils.ts +15 -15
- package/src/utils/Logger.ts +14 -14
- package/src/utils/RetryUtils.ts +78 -78
- package/src/utils/SwapUtils.ts +99 -99
- package/src/utils/TimeoutUtils.ts +49 -49
- package/src/utils/TokenUtils.ts +33 -33
- package/src/utils/TypeUtils.ts +8 -8
- package/src/utils/Utils.ts +221 -221
|
@@ -1,565 +1,565 @@
|
|
|
1
|
-
import {ChainEvent, ChainType, isAbstractSigner} from "@atomiqlabs/base";
|
|
2
|
-
import {EventEmitter} from "events";
|
|
3
|
-
import {ISwap} from "./ISwap";
|
|
4
|
-
import {ISwapPrice} from "../prices/abstract/ISwapPrice";
|
|
5
|
-
import {IntermediaryError} from "../errors/IntermediaryError";
|
|
6
|
-
import {ChainIds, MultiChain} from "../swapper/Swapper";
|
|
7
|
-
import {UnifiedSwapEventListener} from "../events/UnifiedSwapEventListener";
|
|
8
|
-
import {SwapType} from "../enums/SwapType";
|
|
9
|
-
import {UnifiedSwapStorage} from "../storage/UnifiedSwapStorage";
|
|
10
|
-
import {SCToken} from "../types/Token";
|
|
11
|
-
import {getLogger} from "../utils/Logger";
|
|
12
|
-
import {PriceInfoType} from "../types/PriceInfoType";
|
|
13
|
-
import {fromHumanReadableString} from "../utils/TokenUtils";
|
|
14
|
-
import {UserError} from "../errors/UserError";
|
|
15
|
-
import {IntermediaryAPI} from "../intermediaries/apis/IntermediaryAPI";
|
|
16
|
-
|
|
17
|
-
export const DEFAULT_MAX_PARALLEL_SWAP_TICKS = 50;
|
|
18
|
-
export const DEFAULT_MAX_PARALLEL_SWAP_SYNCS = 50;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Options for swap wrapper configuration
|
|
22
|
-
*
|
|
23
|
-
* @category Swaps/Base
|
|
24
|
-
*/
|
|
25
|
-
export type ISwapWrapperOptions = {
|
|
26
|
-
getRequestTimeout?: number,
|
|
27
|
-
postRequestTimeout?: number,
|
|
28
|
-
/**
|
|
29
|
-
* How many swaps to call `_tick()` for in parallel
|
|
30
|
-
*/
|
|
31
|
-
maxParallelSwapTicks?: number,
|
|
32
|
-
/**
|
|
33
|
-
* How many swaps to call `_sync()` for in parallel
|
|
34
|
-
*/
|
|
35
|
-
maxParallelSwapSyncs?: number,
|
|
36
|
-
/**
|
|
37
|
-
* Whether to save swaps that are not initialized into the persistent storage
|
|
38
|
-
*/
|
|
39
|
-
saveUninitializedSwaps?: boolean
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Token configuration for wrapper constructors
|
|
44
|
-
*
|
|
45
|
-
* @category Swaps/Base
|
|
46
|
-
*/
|
|
47
|
-
export type WrapperCtorTokens<T extends ChainType = ChainType> = {
|
|
48
|
-
[tokenAddress: string]: SCToken<T["ChainId"]>
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Type definition linking wrapper and swap types
|
|
53
|
-
*
|
|
54
|
-
* @category Swaps/Base
|
|
55
|
-
*/
|
|
56
|
-
export type SwapTypeDefinition<T extends ChainType, W extends ISwapWrapper<T, any>, S extends ISwap<T>> = {
|
|
57
|
-
Wrapper: W;
|
|
58
|
-
Swap: S;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Base abstract class for swap handler implementations
|
|
63
|
-
*
|
|
64
|
-
* @category Swaps/Base
|
|
65
|
-
*/
|
|
66
|
-
export abstract class ISwapWrapper<
|
|
67
|
-
T extends ChainType,
|
|
68
|
-
D extends SwapTypeDefinition<T, ISwapWrapper<T, D>, ISwap<T, D>>,
|
|
69
|
-
O extends ISwapWrapperOptions = ISwapWrapperOptions
|
|
70
|
-
> {
|
|
71
|
-
/**
|
|
72
|
-
* Swap type
|
|
73
|
-
*/
|
|
74
|
-
abstract readonly TYPE: SwapType;
|
|
75
|
-
/**
|
|
76
|
-
* Function for deserializing swaps
|
|
77
|
-
* @internal
|
|
78
|
-
*/
|
|
79
|
-
abstract readonly _swapDeserializer: new (wrapper: D["Wrapper"], data: any) => D["Swap"];
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Logger instance
|
|
84
|
-
* @internal
|
|
85
|
-
*/
|
|
86
|
-
protected readonly logger = getLogger(this.constructor.name+": ");
|
|
87
|
-
/**
|
|
88
|
-
* Persistent storage backend for the swaps
|
|
89
|
-
* @internal
|
|
90
|
-
*/
|
|
91
|
-
protected readonly unifiedStorage: UnifiedSwapStorage<T>;
|
|
92
|
-
/**
|
|
93
|
-
* Smart chain events listener for listening to and parsing of on-chain events
|
|
94
|
-
* @internal
|
|
95
|
-
*/
|
|
96
|
-
protected readonly unifiedChainEvents: UnifiedSwapEventListener<T>;
|
|
97
|
-
/**
|
|
98
|
-
* States of the swaps where {@link ISwap._tick} should be called every second
|
|
99
|
-
* @internal
|
|
100
|
-
*/
|
|
101
|
-
protected readonly tickSwapState?: Array<D["Swap"]["_state"]>;
|
|
102
|
-
/**
|
|
103
|
-
* In-memory mapping of pending (not initiated) swaps, utilizing weak references to automatically
|
|
104
|
-
* free memory when swaps are dereferenced in not initiated state
|
|
105
|
-
* @internal
|
|
106
|
-
*/
|
|
107
|
-
protected readonly pendingSwaps: Map<string, WeakRef<D["Swap"]>> = new Map();
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Whether this wrapper is initialized (have to call {@link init} to initialize a wrapper)
|
|
112
|
-
* @internal
|
|
113
|
-
*/
|
|
114
|
-
protected isInitialized: boolean = false;
|
|
115
|
-
/**
|
|
116
|
-
* An interval for calling tick functions on the underlying swaps
|
|
117
|
-
* @internal
|
|
118
|
-
*/
|
|
119
|
-
protected tickInterval?: NodeJS.Timeout;
|
|
120
|
-
/**
|
|
121
|
-
* An internal abort controller for the running tick handler
|
|
122
|
-
* @internal
|
|
123
|
-
*/
|
|
124
|
-
protected tickAbortController?: AbortController;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* States of the swaps in pending (non-final state), these are checked automatically on initial swap synchronization
|
|
129
|
-
* @internal
|
|
130
|
-
*/
|
|
131
|
-
abstract readonly _pendingSwapStates: Array<D["Swap"]["_state"]>;
|
|
132
|
-
/**
|
|
133
|
-
* Chain interface of the underlying smart chain
|
|
134
|
-
* @internal
|
|
135
|
-
*/
|
|
136
|
-
readonly _chain: T["ChainInterface"];
|
|
137
|
-
/**
|
|
138
|
-
* Pricing API
|
|
139
|
-
* @internal
|
|
140
|
-
*/
|
|
141
|
-
readonly _prices: ISwapPrice;
|
|
142
|
-
/**
|
|
143
|
-
* Wrapper options
|
|
144
|
-
* @internal
|
|
145
|
-
*/
|
|
146
|
-
readonly _options: O;
|
|
147
|
-
/**
|
|
148
|
-
* Tokens indexed by their token address
|
|
149
|
-
* @internal
|
|
150
|
-
*/
|
|
151
|
-
readonly _tokens: {
|
|
152
|
-
[tokenAddress: string]: SCToken<T["ChainId"]>
|
|
153
|
-
};
|
|
154
|
-
/**
|
|
155
|
-
* LP API Used to communicate with the LPs
|
|
156
|
-
* @internal
|
|
157
|
-
*/
|
|
158
|
-
readonly _lpApi: IntermediaryAPI;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Chain identifier string of this wrapper
|
|
163
|
-
*/
|
|
164
|
-
readonly chainIdentifier: T["ChainId"];
|
|
165
|
-
/**
|
|
166
|
-
* Event emitter emitting `"swapState"` event when swap's state changes
|
|
167
|
-
*/
|
|
168
|
-
readonly events: EventEmitter<{swapState: [D["Swap"]]}>;
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
constructor(
|
|
172
|
-
chainIdentifier: T["ChainId"],
|
|
173
|
-
unifiedStorage: UnifiedSwapStorage<T>,
|
|
174
|
-
unifiedChainEvents: UnifiedSwapEventListener<T>,
|
|
175
|
-
chain: T["ChainInterface"],
|
|
176
|
-
prices: ISwapPrice,
|
|
177
|
-
tokens: WrapperCtorTokens,
|
|
178
|
-
lpApi: IntermediaryAPI,
|
|
179
|
-
options: O,
|
|
180
|
-
events?: EventEmitter<{swapState: [ISwap]}>
|
|
181
|
-
) {
|
|
182
|
-
if(options?.maxParallelSwapTicks!=null && options.maxParallelSwapTicks < 1)
|
|
183
|
-
throw new Error("maxParallelSwapTicks must be at least 1!");
|
|
184
|
-
if(options?.maxParallelSwapSyncs!=null && options.maxParallelSwapSyncs < 1)
|
|
185
|
-
throw new Error("maxParallelSwapSyncs must be at least 1!");
|
|
186
|
-
|
|
187
|
-
this.unifiedStorage = unifiedStorage;
|
|
188
|
-
this.unifiedChainEvents = unifiedChainEvents;
|
|
189
|
-
|
|
190
|
-
this.chainIdentifier = chainIdentifier;
|
|
191
|
-
this._chain = chain;
|
|
192
|
-
this._prices = prices;
|
|
193
|
-
this.events = events || new EventEmitter();
|
|
194
|
-
this._lpApi = lpApi;
|
|
195
|
-
this._options = options;
|
|
196
|
-
this._tokens = tokens;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Parses the provided gas amount from its `string` or `bigint` representation to `bigint` base units.
|
|
201
|
-
*
|
|
202
|
-
* Defaults to `0n` if no gasAmount is provided
|
|
203
|
-
*
|
|
204
|
-
* @param gasAmount
|
|
205
|
-
* @internal
|
|
206
|
-
*/
|
|
207
|
-
protected parseGasAmount(gasAmount?: string | bigint): bigint {
|
|
208
|
-
let result: bigint | undefined | null;
|
|
209
|
-
if(typeof(gasAmount)==="string") {
|
|
210
|
-
result = fromHumanReadableString(gasAmount, this._getNativeToken());
|
|
211
|
-
if(result==null) throw new UserError("Invalid `gasAmount` option provided, not a numerical string!");
|
|
212
|
-
} else {
|
|
213
|
-
result = gasAmount;
|
|
214
|
-
}
|
|
215
|
-
return result ?? 0n;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Pre-fetches swap price for a given swap
|
|
220
|
-
*
|
|
221
|
-
* @param amountData Amount data
|
|
222
|
-
* @param abortSignal Abort signal
|
|
223
|
-
* @returns Price of the token in uSats (micro sats)
|
|
224
|
-
* @internal
|
|
225
|
-
*/
|
|
226
|
-
protected preFetchPrice(amountData: { token: string }, abortSignal?: AbortSignal): Promise<bigint | undefined> {
|
|
227
|
-
return this._prices.preFetchPrice(this.chainIdentifier, amountData.token, abortSignal).catch(e => {
|
|
228
|
-
this.logger.error("preFetchPrice.token(): Error: ", e);
|
|
229
|
-
return undefined;
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Pre-fetches bitcoin's USD price
|
|
235
|
-
*
|
|
236
|
-
* @param abortSignal Abort signal
|
|
237
|
-
* @internal
|
|
238
|
-
*/
|
|
239
|
-
protected preFetchUsdPrice(abortSignal?: AbortSignal): Promise<number | undefined> {
|
|
240
|
-
return this._prices.preFetchUsdPrice(abortSignal).catch(e => {
|
|
241
|
-
this.logger.error("preFetchPrice.usd(): Error: ", e);
|
|
242
|
-
return undefined;
|
|
243
|
-
})
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Verifies returned price for swaps
|
|
248
|
-
*
|
|
249
|
-
* @param lpServiceData Service data for the service in question (TO_BTCLN, TO_BTC, etc.) of the given intermediary
|
|
250
|
-
* @param send Whether this is a send (Smart chain -> Bitcoin) or receive (Bitcoin -> Smart chain) swap
|
|
251
|
-
* @param amountSats Amount in BTC
|
|
252
|
-
* @param amountToken Amount in token
|
|
253
|
-
* @param token Token used in the swap
|
|
254
|
-
* @param feeData Fee data as returned by the intermediary
|
|
255
|
-
* @param pricePrefetchPromise Optional price pre-fetch promise
|
|
256
|
-
* @param usdPricePrefetchPromise Optiona USD price pre-fetch promise
|
|
257
|
-
* @param abortSignal Abort signal
|
|
258
|
-
* @returns Price info object
|
|
259
|
-
* @throws {IntermediaryError} if the calculated fee is too high
|
|
260
|
-
*
|
|
261
|
-
* @internal
|
|
262
|
-
*/
|
|
263
|
-
protected async verifyReturnedPrice(
|
|
264
|
-
lpServiceData: {swapBaseFee: number, swapFeePPM: number},
|
|
265
|
-
send: boolean,
|
|
266
|
-
amountSats: bigint,
|
|
267
|
-
amountToken: bigint,
|
|
268
|
-
token: string,
|
|
269
|
-
feeData: {
|
|
270
|
-
networkFee?: bigint,
|
|
271
|
-
swapFeeBtc?: bigint
|
|
272
|
-
},
|
|
273
|
-
pricePrefetchPromise: Promise<bigint | undefined> = Promise.resolve(undefined),
|
|
274
|
-
usdPricePrefetchPromise: Promise<number | undefined> = Promise.resolve(undefined),
|
|
275
|
-
abortSignal?: AbortSignal
|
|
276
|
-
): Promise<PriceInfoType> {
|
|
277
|
-
const swapBaseFee = BigInt(lpServiceData.swapBaseFee);
|
|
278
|
-
const swapFeePPM = BigInt(lpServiceData.swapFeePPM);
|
|
279
|
-
if(send && feeData.networkFee!=null) amountToken = amountToken - feeData.networkFee;
|
|
280
|
-
|
|
281
|
-
const [isValidAmount, usdPrice] = await Promise.all([
|
|
282
|
-
send ?
|
|
283
|
-
this._prices.isValidAmountSend(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc) :
|
|
284
|
-
this._prices.isValidAmountReceive(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc),
|
|
285
|
-
usdPricePrefetchPromise.then(value => {
|
|
286
|
-
if(value!=null) return value;
|
|
287
|
-
return this._prices.preFetchUsdPrice(abortSignal);
|
|
288
|
-
})
|
|
289
|
-
]);
|
|
290
|
-
if(!isValidAmount.isValid) throw new IntermediaryError("Fee too high");
|
|
291
|
-
isValidAmount.realPriceUsdPerBitcoin = usdPrice;
|
|
292
|
-
|
|
293
|
-
return isValidAmount;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Processes a single smart chain on-chain event
|
|
298
|
-
*
|
|
299
|
-
* @param event Smart chain event to process
|
|
300
|
-
* @param swap A swap related to the event
|
|
301
|
-
* @internal
|
|
302
|
-
*/
|
|
303
|
-
protected abstract processEvent?(event: ChainEvent<T["Data"]>, swap: D["Swap"]): Promise<void>;
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Starts the interval calling the {@link ISwap._tick} on all the known swaps in tick-enabled states
|
|
307
|
-
* @internal
|
|
308
|
-
*/
|
|
309
|
-
protected startTickInterval(): void {
|
|
310
|
-
if(this.tickSwapState==null || this.tickSwapState.length===0) return;
|
|
311
|
-
if(this.tickAbortController!=null) this.tickAbortController.abort("New tick interval has been started!");
|
|
312
|
-
const abortController = this.tickAbortController = new AbortController();
|
|
313
|
-
let run: () => Promise<void>;
|
|
314
|
-
run = async () => {
|
|
315
|
-
if(!this.isInitialized) return;
|
|
316
|
-
await this.tick(undefined, abortController.signal).catch(e => {
|
|
317
|
-
if(abortController.signal.aborted) return;
|
|
318
|
-
this.logger.warn("startTickInterval(): Tick on swaps failed, error: ", e);
|
|
319
|
-
});
|
|
320
|
-
if(abortController.signal.aborted) return;
|
|
321
|
-
if(!this.isInitialized) return;
|
|
322
|
-
this.tickInterval = setTimeout(run, 1000);
|
|
323
|
-
}
|
|
324
|
-
run();
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Runs checks on passed swaps, syncing their state from on-chain data
|
|
329
|
-
*
|
|
330
|
-
* @param pastSwaps Swaps to check
|
|
331
|
-
* @internal
|
|
332
|
-
*/
|
|
333
|
-
protected async _checkPastSwaps(pastSwaps: D["Swap"][]): Promise<{changedSwaps: D["Swap"][], removeSwaps: D["Swap"][]}> {
|
|
334
|
-
const changedSwaps: D["Swap"][] = [];
|
|
335
|
-
const removeSwaps: D["Swap"][] = [];
|
|
336
|
-
|
|
337
|
-
await Promise.all(pastSwaps.map((swap: D["Swap"]) =>
|
|
338
|
-
swap._sync(false).then(changed => {
|
|
339
|
-
if(swap.isQuoteExpired()) {
|
|
340
|
-
removeSwaps.push(swap);
|
|
341
|
-
this.logger.debug("_checkPastSwaps(): Removing expired swap: "+swap.getId());
|
|
342
|
-
} else {
|
|
343
|
-
if(changed) changedSwaps.push(swap);
|
|
344
|
-
}
|
|
345
|
-
}).catch(e => this.logger.error("_checkPastSwaps(): Error when checking swap "+swap.getId()+": ", e))
|
|
346
|
-
));
|
|
347
|
-
|
|
348
|
-
return {changedSwaps, removeSwaps};
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Initializes the swap wrapper, needs to be called before any other action can be taken
|
|
354
|
-
*
|
|
355
|
-
* @param noTimers Whether to skip scheduling a tick timer for the swaps, if the tick timer is not initiated
|
|
356
|
-
* the swap states depending on e.g. expiry can be out of sync with the actual expiration of the swap
|
|
357
|
-
* @param noCheckPastSwaps Whether to skip checking past swaps on initialization (by default all pending swaps
|
|
358
|
-
* are re-checked on init, and their state is synchronized from the on-chain data)
|
|
359
|
-
*/
|
|
360
|
-
public async init(noTimers: boolean = false, noCheckPastSwaps: boolean = false): Promise<void> {
|
|
361
|
-
if(this.isInitialized) return;
|
|
362
|
-
|
|
363
|
-
if(!noCheckPastSwaps) {
|
|
364
|
-
//Save events received in the meantime into the event queue and process them only after we've checked and
|
|
365
|
-
// processed all the past swaps
|
|
366
|
-
let eventQueue: {
|
|
367
|
-
event: ChainEvent<T["Data"]>,
|
|
368
|
-
swap: D["Swap"]
|
|
369
|
-
}[] = [];
|
|
370
|
-
const initListener = (event: ChainEvent<T["Data"]>, swap: D["Swap"]) => {
|
|
371
|
-
eventQueue.push({event, swap});
|
|
372
|
-
return Promise.resolve();
|
|
373
|
-
}
|
|
374
|
-
if(this.processEvent!=null) this.unifiedChainEvents.registerListener(this.TYPE, initListener, this._swapDeserializer.bind(null, this));
|
|
375
|
-
|
|
376
|
-
await this.checkPastSwaps();
|
|
377
|
-
|
|
378
|
-
if(this.processEvent!=null) {
|
|
379
|
-
//Process accumulated event queue
|
|
380
|
-
for(let event of eventQueue) {
|
|
381
|
-
await this.processEvent(event.event, event.swap);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
//Unregister the temporary event handler
|
|
385
|
-
this.unifiedChainEvents.unregisterListener(this.TYPE);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if(this.processEvent!=null) this.unifiedChainEvents.registerListener(this.TYPE, this.processEvent.bind(this), this._swapDeserializer.bind(null, this));
|
|
390
|
-
|
|
391
|
-
this.isInitialized = true;
|
|
392
|
-
|
|
393
|
-
if(!noTimers) this.startTickInterval();
|
|
394
|
-
|
|
395
|
-
// this.logger.info("init(): Swap wrapper initialized");
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Un-subscribes from event listeners on the smart chain, terminates the tick interval and stops this wrapper
|
|
400
|
-
*/
|
|
401
|
-
public async stop() {
|
|
402
|
-
this.isInitialized = false;
|
|
403
|
-
this.unifiedChainEvents.unregisterListener(this.TYPE);
|
|
404
|
-
this.logger.info("stop(): Swap wrapper stopped");
|
|
405
|
-
if(this.tickInterval!=null) {
|
|
406
|
-
clearTimeout(this.tickInterval);
|
|
407
|
-
delete this.tickInterval;
|
|
408
|
-
}
|
|
409
|
-
if(this.tickAbortController!=null) {
|
|
410
|
-
this.tickAbortController.abort("Wrapper instance stopped!");
|
|
411
|
-
delete this.tickAbortController;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Runs checks on all the known pending swaps, syncing their state from on-chain data
|
|
417
|
-
*
|
|
418
|
-
* @remarks Doesn't work properly if you pass non-persisted swaps
|
|
419
|
-
*
|
|
420
|
-
* @param pastSwaps Optional array of past swaps to check, otherwise all relevant swaps will be fetched
|
|
421
|
-
* from the persistent storage
|
|
422
|
-
* @param noSave Whether to skip saving the swap changes in the persistent storage
|
|
423
|
-
*/
|
|
424
|
-
public async checkPastSwaps(pastSwaps?: D["Swap"][], noSave?: boolean): Promise<{ removeSwaps: D["Swap"][], changedSwaps: D["Swap"][] }> {
|
|
425
|
-
if (pastSwaps == null) pastSwaps = await this.unifiedStorage.query<D["Swap"]>(
|
|
426
|
-
[[{key: "type", value: this.TYPE}, {key: "state", value: this._pendingSwapStates}]],
|
|
427
|
-
(val: any) => new this._swapDeserializer(this, val)
|
|
428
|
-
);
|
|
429
|
-
|
|
430
|
-
const maxParallelSyncs = this._options.maxParallelSwapSyncs ?? DEFAULT_MAX_PARALLEL_SWAP_SYNCS;
|
|
431
|
-
|
|
432
|
-
const totalRemoveSwaps: D["Swap"][] = [];
|
|
433
|
-
const totalChangedSwaps: D["Swap"][] = [];
|
|
434
|
-
for(let i=0; i<pastSwaps.length; i+=maxParallelSyncs) {
|
|
435
|
-
const {removeSwaps, changedSwaps} = await this._checkPastSwaps(pastSwaps.slice(i, i+maxParallelSyncs));
|
|
436
|
-
if (!noSave) {
|
|
437
|
-
await this.unifiedStorage.removeAll(removeSwaps, true);
|
|
438
|
-
await this.unifiedStorage.saveAll(changedSwaps, true);
|
|
439
|
-
changedSwaps.forEach(swap => swap._emitEvent());
|
|
440
|
-
removeSwaps.forEach(swap => swap._emitEvent());
|
|
441
|
-
}
|
|
442
|
-
totalRemoveSwaps.push(...removeSwaps);
|
|
443
|
-
totalChangedSwaps.push(...changedSwaps);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return {
|
|
447
|
-
removeSwaps: totalRemoveSwaps,
|
|
448
|
-
changedSwaps: totalChangedSwaps
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Invokes {@link ISwap._tick} on all the known swaps
|
|
454
|
-
*
|
|
455
|
-
* @param swaps Optional array of swaps to invoke `_tick()` on, otherwise all relevant swaps will be fetched
|
|
456
|
-
* from the persistent storage
|
|
457
|
-
* @param abortSignal Abort signal
|
|
458
|
-
*/
|
|
459
|
-
public async tick(swaps?: D["Swap"][], abortSignal?: AbortSignal): Promise<void> {
|
|
460
|
-
if(swaps==null) swaps = await this.unifiedStorage.query<D["Swap"]>(
|
|
461
|
-
[[{key: "type", value: this.TYPE}, {key: "state", value: this.tickSwapState}]],
|
|
462
|
-
(val: any) => new this._swapDeserializer(this, val)
|
|
463
|
-
);
|
|
464
|
-
abortSignal?.throwIfAborted();
|
|
465
|
-
|
|
466
|
-
const parallelTicks = this._options.maxParallelSwapTicks ?? DEFAULT_MAX_PARALLEL_SWAP_TICKS;
|
|
467
|
-
|
|
468
|
-
let promises: Promise<any>[] = [];
|
|
469
|
-
for(let pendingSwap of this.pendingSwaps.values()) {
|
|
470
|
-
const value = pendingSwap.deref();
|
|
471
|
-
if(value != null) promises.push(value._tick(true).catch(e => {
|
|
472
|
-
this.logger.warn(`tick(): Error ticking swap ${value.getId()}: `, e);
|
|
473
|
-
}));
|
|
474
|
-
if(promises.length >= parallelTicks) {
|
|
475
|
-
await Promise.all(promises);
|
|
476
|
-
abortSignal?.throwIfAborted();
|
|
477
|
-
promises = [];
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
for(let value of swaps) {
|
|
482
|
-
promises.push(value._tick(true).catch(e => {
|
|
483
|
-
this.logger.warn(`tick(): Error ticking swap ${value.getId()}: `, e);
|
|
484
|
-
}));
|
|
485
|
-
if(promises.length >= parallelTicks) {
|
|
486
|
-
await Promise.all(promises);
|
|
487
|
-
abortSignal?.throwIfAborted();
|
|
488
|
-
promises = [];
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
if(promises.length>0) await Promise.all(promises);
|
|
493
|
-
abortSignal?.throwIfAborted();
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
/**
|
|
497
|
-
* Returns the smart chain's native token used to pay for fees
|
|
498
|
-
* @internal
|
|
499
|
-
*/
|
|
500
|
-
_getNativeToken(): SCToken<T["ChainId"]> {
|
|
501
|
-
return this._tokens[this._chain.getNativeCurrencyAddress()];
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* Saves the swap, if it is not initiated it is only saved to pending swaps
|
|
506
|
-
*
|
|
507
|
-
* @param swap Swap to save
|
|
508
|
-
*
|
|
509
|
-
* @internal
|
|
510
|
-
*/
|
|
511
|
-
_saveSwapData(swap: D["Swap"]): Promise<void> {
|
|
512
|
-
if(!this._options.saveUninitializedSwaps) {
|
|
513
|
-
if(!swap.isInitiated()) {
|
|
514
|
-
this.logger.debug("saveSwapData(): Swap "+swap.getId()+" not initiated, saving to pending swaps");
|
|
515
|
-
this.pendingSwaps.set(swap.getId(), new WeakRef<D["Swap"]>(swap));
|
|
516
|
-
return Promise.resolve();
|
|
517
|
-
} else {
|
|
518
|
-
this.pendingSwaps.delete(swap.getId());
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
return this.unifiedStorage.save(swap);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Removes the swap from the persistent storage and pending swaps
|
|
526
|
-
*
|
|
527
|
-
* @param swap Swap to remove
|
|
528
|
-
*
|
|
529
|
-
* @internal
|
|
530
|
-
*/
|
|
531
|
-
_removeSwapData(swap: D["Swap"]): Promise<void> {
|
|
532
|
-
this.pendingSwaps.delete(swap.getId());
|
|
533
|
-
if(!swap._persisted) return Promise.resolve();
|
|
534
|
-
return this.unifiedStorage.remove(swap);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Retrieves a swap by its ID from the pending swap mapping
|
|
539
|
-
*
|
|
540
|
-
* @param id
|
|
541
|
-
*
|
|
542
|
-
* @internal
|
|
543
|
-
*/
|
|
544
|
-
_getPendingSwap(id: string): D["Swap"] | null {
|
|
545
|
-
return this.pendingSwaps.get(id)?.deref() ?? null;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
/**
|
|
549
|
-
* @internal
|
|
550
|
-
*/
|
|
551
|
-
async _getSignerAddress(signer?: string | T["Signer"] | T["NativeSigner"]): Promise<string | undefined> {
|
|
552
|
-
let address: string | undefined = undefined;
|
|
553
|
-
if(signer!=null) {
|
|
554
|
-
if (typeof (signer) === "string") {
|
|
555
|
-
address = signer;
|
|
556
|
-
} else if (isAbstractSigner(signer)) {
|
|
557
|
-
address = signer.getAddress();
|
|
558
|
-
} else {
|
|
559
|
-
address = (await this._chain.wrapSigner(signer)).getAddress();
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
return address;
|
|
563
|
-
}
|
|
564
|
-
|
|
1
|
+
import {ChainEvent, ChainType, isAbstractSigner} from "@atomiqlabs/base";
|
|
2
|
+
import {EventEmitter} from "events";
|
|
3
|
+
import {ISwap} from "./ISwap";
|
|
4
|
+
import {ISwapPrice} from "../prices/abstract/ISwapPrice";
|
|
5
|
+
import {IntermediaryError} from "../errors/IntermediaryError";
|
|
6
|
+
import {ChainIds, MultiChain} from "../swapper/Swapper";
|
|
7
|
+
import {UnifiedSwapEventListener} from "../events/UnifiedSwapEventListener";
|
|
8
|
+
import {SwapType} from "../enums/SwapType";
|
|
9
|
+
import {UnifiedSwapStorage} from "../storage/UnifiedSwapStorage";
|
|
10
|
+
import {SCToken} from "../types/Token";
|
|
11
|
+
import {getLogger} from "../utils/Logger";
|
|
12
|
+
import {PriceInfoType} from "../types/PriceInfoType";
|
|
13
|
+
import {fromHumanReadableString} from "../utils/TokenUtils";
|
|
14
|
+
import {UserError} from "../errors/UserError";
|
|
15
|
+
import {IntermediaryAPI} from "../intermediaries/apis/IntermediaryAPI";
|
|
16
|
+
|
|
17
|
+
export const DEFAULT_MAX_PARALLEL_SWAP_TICKS = 50;
|
|
18
|
+
export const DEFAULT_MAX_PARALLEL_SWAP_SYNCS = 50;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for swap wrapper configuration
|
|
22
|
+
*
|
|
23
|
+
* @category Swaps/Base
|
|
24
|
+
*/
|
|
25
|
+
export type ISwapWrapperOptions = {
|
|
26
|
+
getRequestTimeout?: number,
|
|
27
|
+
postRequestTimeout?: number,
|
|
28
|
+
/**
|
|
29
|
+
* How many swaps to call `_tick()` for in parallel
|
|
30
|
+
*/
|
|
31
|
+
maxParallelSwapTicks?: number,
|
|
32
|
+
/**
|
|
33
|
+
* How many swaps to call `_sync()` for in parallel
|
|
34
|
+
*/
|
|
35
|
+
maxParallelSwapSyncs?: number,
|
|
36
|
+
/**
|
|
37
|
+
* Whether to save swaps that are not initialized into the persistent storage
|
|
38
|
+
*/
|
|
39
|
+
saveUninitializedSwaps?: boolean
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Token configuration for wrapper constructors
|
|
44
|
+
*
|
|
45
|
+
* @category Swaps/Base
|
|
46
|
+
*/
|
|
47
|
+
export type WrapperCtorTokens<T extends ChainType = ChainType> = {
|
|
48
|
+
[tokenAddress: string]: SCToken<T["ChainId"]>
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Type definition linking wrapper and swap types
|
|
53
|
+
*
|
|
54
|
+
* @category Swaps/Base
|
|
55
|
+
*/
|
|
56
|
+
export type SwapTypeDefinition<T extends ChainType, W extends ISwapWrapper<T, any>, S extends ISwap<T>> = {
|
|
57
|
+
Wrapper: W;
|
|
58
|
+
Swap: S;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Base abstract class for swap handler implementations
|
|
63
|
+
*
|
|
64
|
+
* @category Swaps/Base
|
|
65
|
+
*/
|
|
66
|
+
export abstract class ISwapWrapper<
|
|
67
|
+
T extends ChainType,
|
|
68
|
+
D extends SwapTypeDefinition<T, ISwapWrapper<T, D>, ISwap<T, D>>,
|
|
69
|
+
O extends ISwapWrapperOptions = ISwapWrapperOptions
|
|
70
|
+
> {
|
|
71
|
+
/**
|
|
72
|
+
* Swap type
|
|
73
|
+
*/
|
|
74
|
+
abstract readonly TYPE: SwapType;
|
|
75
|
+
/**
|
|
76
|
+
* Function for deserializing swaps
|
|
77
|
+
* @internal
|
|
78
|
+
*/
|
|
79
|
+
abstract readonly _swapDeserializer: new (wrapper: D["Wrapper"], data: any) => D["Swap"];
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Logger instance
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
protected readonly logger = getLogger(this.constructor.name+": ");
|
|
87
|
+
/**
|
|
88
|
+
* Persistent storage backend for the swaps
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
protected readonly unifiedStorage: UnifiedSwapStorage<T>;
|
|
92
|
+
/**
|
|
93
|
+
* Smart chain events listener for listening to and parsing of on-chain events
|
|
94
|
+
* @internal
|
|
95
|
+
*/
|
|
96
|
+
protected readonly unifiedChainEvents: UnifiedSwapEventListener<T>;
|
|
97
|
+
/**
|
|
98
|
+
* States of the swaps where {@link ISwap._tick} should be called every second
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
protected readonly tickSwapState?: Array<D["Swap"]["_state"]>;
|
|
102
|
+
/**
|
|
103
|
+
* In-memory mapping of pending (not initiated) swaps, utilizing weak references to automatically
|
|
104
|
+
* free memory when swaps are dereferenced in not initiated state
|
|
105
|
+
* @internal
|
|
106
|
+
*/
|
|
107
|
+
protected readonly pendingSwaps: Map<string, WeakRef<D["Swap"]>> = new Map();
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Whether this wrapper is initialized (have to call {@link init} to initialize a wrapper)
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
protected isInitialized: boolean = false;
|
|
115
|
+
/**
|
|
116
|
+
* An interval for calling tick functions on the underlying swaps
|
|
117
|
+
* @internal
|
|
118
|
+
*/
|
|
119
|
+
protected tickInterval?: NodeJS.Timeout;
|
|
120
|
+
/**
|
|
121
|
+
* An internal abort controller for the running tick handler
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
protected tickAbortController?: AbortController;
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* States of the swaps in pending (non-final state), these are checked automatically on initial swap synchronization
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
131
|
+
abstract readonly _pendingSwapStates: Array<D["Swap"]["_state"]>;
|
|
132
|
+
/**
|
|
133
|
+
* Chain interface of the underlying smart chain
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
readonly _chain: T["ChainInterface"];
|
|
137
|
+
/**
|
|
138
|
+
* Pricing API
|
|
139
|
+
* @internal
|
|
140
|
+
*/
|
|
141
|
+
readonly _prices: ISwapPrice;
|
|
142
|
+
/**
|
|
143
|
+
* Wrapper options
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
readonly _options: O;
|
|
147
|
+
/**
|
|
148
|
+
* Tokens indexed by their token address
|
|
149
|
+
* @internal
|
|
150
|
+
*/
|
|
151
|
+
readonly _tokens: {
|
|
152
|
+
[tokenAddress: string]: SCToken<T["ChainId"]>
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* LP API Used to communicate with the LPs
|
|
156
|
+
* @internal
|
|
157
|
+
*/
|
|
158
|
+
readonly _lpApi: IntermediaryAPI;
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Chain identifier string of this wrapper
|
|
163
|
+
*/
|
|
164
|
+
readonly chainIdentifier: T["ChainId"];
|
|
165
|
+
/**
|
|
166
|
+
* Event emitter emitting `"swapState"` event when swap's state changes
|
|
167
|
+
*/
|
|
168
|
+
readonly events: EventEmitter<{swapState: [D["Swap"]]}>;
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
constructor(
|
|
172
|
+
chainIdentifier: T["ChainId"],
|
|
173
|
+
unifiedStorage: UnifiedSwapStorage<T>,
|
|
174
|
+
unifiedChainEvents: UnifiedSwapEventListener<T>,
|
|
175
|
+
chain: T["ChainInterface"],
|
|
176
|
+
prices: ISwapPrice,
|
|
177
|
+
tokens: WrapperCtorTokens,
|
|
178
|
+
lpApi: IntermediaryAPI,
|
|
179
|
+
options: O,
|
|
180
|
+
events?: EventEmitter<{swapState: [ISwap]}>
|
|
181
|
+
) {
|
|
182
|
+
if(options?.maxParallelSwapTicks!=null && options.maxParallelSwapTicks < 1)
|
|
183
|
+
throw new Error("maxParallelSwapTicks must be at least 1!");
|
|
184
|
+
if(options?.maxParallelSwapSyncs!=null && options.maxParallelSwapSyncs < 1)
|
|
185
|
+
throw new Error("maxParallelSwapSyncs must be at least 1!");
|
|
186
|
+
|
|
187
|
+
this.unifiedStorage = unifiedStorage;
|
|
188
|
+
this.unifiedChainEvents = unifiedChainEvents;
|
|
189
|
+
|
|
190
|
+
this.chainIdentifier = chainIdentifier;
|
|
191
|
+
this._chain = chain;
|
|
192
|
+
this._prices = prices;
|
|
193
|
+
this.events = events || new EventEmitter();
|
|
194
|
+
this._lpApi = lpApi;
|
|
195
|
+
this._options = options;
|
|
196
|
+
this._tokens = tokens;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Parses the provided gas amount from its `string` or `bigint` representation to `bigint` base units.
|
|
201
|
+
*
|
|
202
|
+
* Defaults to `0n` if no gasAmount is provided
|
|
203
|
+
*
|
|
204
|
+
* @param gasAmount
|
|
205
|
+
* @internal
|
|
206
|
+
*/
|
|
207
|
+
protected parseGasAmount(gasAmount?: string | bigint): bigint {
|
|
208
|
+
let result: bigint | undefined | null;
|
|
209
|
+
if(typeof(gasAmount)==="string") {
|
|
210
|
+
result = fromHumanReadableString(gasAmount, this._getNativeToken());
|
|
211
|
+
if(result==null) throw new UserError("Invalid `gasAmount` option provided, not a numerical string!");
|
|
212
|
+
} else {
|
|
213
|
+
result = gasAmount;
|
|
214
|
+
}
|
|
215
|
+
return result ?? 0n;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Pre-fetches swap price for a given swap
|
|
220
|
+
*
|
|
221
|
+
* @param amountData Amount data
|
|
222
|
+
* @param abortSignal Abort signal
|
|
223
|
+
* @returns Price of the token in uSats (micro sats)
|
|
224
|
+
* @internal
|
|
225
|
+
*/
|
|
226
|
+
protected preFetchPrice(amountData: { token: string }, abortSignal?: AbortSignal): Promise<bigint | undefined> {
|
|
227
|
+
return this._prices.preFetchPrice(this.chainIdentifier, amountData.token, abortSignal).catch(e => {
|
|
228
|
+
this.logger.error("preFetchPrice.token(): Error: ", e);
|
|
229
|
+
return undefined;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Pre-fetches bitcoin's USD price
|
|
235
|
+
*
|
|
236
|
+
* @param abortSignal Abort signal
|
|
237
|
+
* @internal
|
|
238
|
+
*/
|
|
239
|
+
protected preFetchUsdPrice(abortSignal?: AbortSignal): Promise<number | undefined> {
|
|
240
|
+
return this._prices.preFetchUsdPrice(abortSignal).catch(e => {
|
|
241
|
+
this.logger.error("preFetchPrice.usd(): Error: ", e);
|
|
242
|
+
return undefined;
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Verifies returned price for swaps
|
|
248
|
+
*
|
|
249
|
+
* @param lpServiceData Service data for the service in question (TO_BTCLN, TO_BTC, etc.) of the given intermediary
|
|
250
|
+
* @param send Whether this is a send (Smart chain -> Bitcoin) or receive (Bitcoin -> Smart chain) swap
|
|
251
|
+
* @param amountSats Amount in BTC
|
|
252
|
+
* @param amountToken Amount in token
|
|
253
|
+
* @param token Token used in the swap
|
|
254
|
+
* @param feeData Fee data as returned by the intermediary
|
|
255
|
+
* @param pricePrefetchPromise Optional price pre-fetch promise
|
|
256
|
+
* @param usdPricePrefetchPromise Optiona USD price pre-fetch promise
|
|
257
|
+
* @param abortSignal Abort signal
|
|
258
|
+
* @returns Price info object
|
|
259
|
+
* @throws {IntermediaryError} if the calculated fee is too high
|
|
260
|
+
*
|
|
261
|
+
* @internal
|
|
262
|
+
*/
|
|
263
|
+
protected async verifyReturnedPrice(
|
|
264
|
+
lpServiceData: {swapBaseFee: number, swapFeePPM: number},
|
|
265
|
+
send: boolean,
|
|
266
|
+
amountSats: bigint,
|
|
267
|
+
amountToken: bigint,
|
|
268
|
+
token: string,
|
|
269
|
+
feeData: {
|
|
270
|
+
networkFee?: bigint,
|
|
271
|
+
swapFeeBtc?: bigint
|
|
272
|
+
},
|
|
273
|
+
pricePrefetchPromise: Promise<bigint | undefined> = Promise.resolve(undefined),
|
|
274
|
+
usdPricePrefetchPromise: Promise<number | undefined> = Promise.resolve(undefined),
|
|
275
|
+
abortSignal?: AbortSignal
|
|
276
|
+
): Promise<PriceInfoType> {
|
|
277
|
+
const swapBaseFee = BigInt(lpServiceData.swapBaseFee);
|
|
278
|
+
const swapFeePPM = BigInt(lpServiceData.swapFeePPM);
|
|
279
|
+
if(send && feeData.networkFee!=null) amountToken = amountToken - feeData.networkFee;
|
|
280
|
+
|
|
281
|
+
const [isValidAmount, usdPrice] = await Promise.all([
|
|
282
|
+
send ?
|
|
283
|
+
this._prices.isValidAmountSend(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc) :
|
|
284
|
+
this._prices.isValidAmountReceive(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc),
|
|
285
|
+
usdPricePrefetchPromise.then(value => {
|
|
286
|
+
if(value!=null) return value;
|
|
287
|
+
return this._prices.preFetchUsdPrice(abortSignal);
|
|
288
|
+
})
|
|
289
|
+
]);
|
|
290
|
+
if(!isValidAmount.isValid) throw new IntermediaryError("Fee too high");
|
|
291
|
+
isValidAmount.realPriceUsdPerBitcoin = usdPrice;
|
|
292
|
+
|
|
293
|
+
return isValidAmount;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Processes a single smart chain on-chain event
|
|
298
|
+
*
|
|
299
|
+
* @param event Smart chain event to process
|
|
300
|
+
* @param swap A swap related to the event
|
|
301
|
+
* @internal
|
|
302
|
+
*/
|
|
303
|
+
protected abstract processEvent?(event: ChainEvent<T["Data"]>, swap: D["Swap"]): Promise<void>;
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Starts the interval calling the {@link ISwap._tick} on all the known swaps in tick-enabled states
|
|
307
|
+
* @internal
|
|
308
|
+
*/
|
|
309
|
+
protected startTickInterval(): void {
|
|
310
|
+
if(this.tickSwapState==null || this.tickSwapState.length===0) return;
|
|
311
|
+
if(this.tickAbortController!=null) this.tickAbortController.abort("New tick interval has been started!");
|
|
312
|
+
const abortController = this.tickAbortController = new AbortController();
|
|
313
|
+
let run: () => Promise<void>;
|
|
314
|
+
run = async () => {
|
|
315
|
+
if(!this.isInitialized) return;
|
|
316
|
+
await this.tick(undefined, abortController.signal).catch(e => {
|
|
317
|
+
if(abortController.signal.aborted) return;
|
|
318
|
+
this.logger.warn("startTickInterval(): Tick on swaps failed, error: ", e);
|
|
319
|
+
});
|
|
320
|
+
if(abortController.signal.aborted) return;
|
|
321
|
+
if(!this.isInitialized) return;
|
|
322
|
+
this.tickInterval = setTimeout(run, 1000);
|
|
323
|
+
}
|
|
324
|
+
run();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Runs checks on passed swaps, syncing their state from on-chain data
|
|
329
|
+
*
|
|
330
|
+
* @param pastSwaps Swaps to check
|
|
331
|
+
* @internal
|
|
332
|
+
*/
|
|
333
|
+
protected async _checkPastSwaps(pastSwaps: D["Swap"][]): Promise<{changedSwaps: D["Swap"][], removeSwaps: D["Swap"][]}> {
|
|
334
|
+
const changedSwaps: D["Swap"][] = [];
|
|
335
|
+
const removeSwaps: D["Swap"][] = [];
|
|
336
|
+
|
|
337
|
+
await Promise.all(pastSwaps.map((swap: D["Swap"]) =>
|
|
338
|
+
swap._sync(false).then(changed => {
|
|
339
|
+
if(swap.isQuoteExpired()) {
|
|
340
|
+
removeSwaps.push(swap);
|
|
341
|
+
this.logger.debug("_checkPastSwaps(): Removing expired swap: "+swap.getId());
|
|
342
|
+
} else {
|
|
343
|
+
if(changed) changedSwaps.push(swap);
|
|
344
|
+
}
|
|
345
|
+
}).catch(e => this.logger.error("_checkPastSwaps(): Error when checking swap "+swap.getId()+": ", e))
|
|
346
|
+
));
|
|
347
|
+
|
|
348
|
+
return {changedSwaps, removeSwaps};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Initializes the swap wrapper, needs to be called before any other action can be taken
|
|
354
|
+
*
|
|
355
|
+
* @param noTimers Whether to skip scheduling a tick timer for the swaps, if the tick timer is not initiated
|
|
356
|
+
* the swap states depending on e.g. expiry can be out of sync with the actual expiration of the swap
|
|
357
|
+
* @param noCheckPastSwaps Whether to skip checking past swaps on initialization (by default all pending swaps
|
|
358
|
+
* are re-checked on init, and their state is synchronized from the on-chain data)
|
|
359
|
+
*/
|
|
360
|
+
public async init(noTimers: boolean = false, noCheckPastSwaps: boolean = false): Promise<void> {
|
|
361
|
+
if(this.isInitialized) return;
|
|
362
|
+
|
|
363
|
+
if(!noCheckPastSwaps) {
|
|
364
|
+
//Save events received in the meantime into the event queue and process them only after we've checked and
|
|
365
|
+
// processed all the past swaps
|
|
366
|
+
let eventQueue: {
|
|
367
|
+
event: ChainEvent<T["Data"]>,
|
|
368
|
+
swap: D["Swap"]
|
|
369
|
+
}[] = [];
|
|
370
|
+
const initListener = (event: ChainEvent<T["Data"]>, swap: D["Swap"]) => {
|
|
371
|
+
eventQueue.push({event, swap});
|
|
372
|
+
return Promise.resolve();
|
|
373
|
+
}
|
|
374
|
+
if(this.processEvent!=null) this.unifiedChainEvents.registerListener(this.TYPE, initListener, this._swapDeserializer.bind(null, this));
|
|
375
|
+
|
|
376
|
+
await this.checkPastSwaps();
|
|
377
|
+
|
|
378
|
+
if(this.processEvent!=null) {
|
|
379
|
+
//Process accumulated event queue
|
|
380
|
+
for(let event of eventQueue) {
|
|
381
|
+
await this.processEvent(event.event, event.swap);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
//Unregister the temporary event handler
|
|
385
|
+
this.unifiedChainEvents.unregisterListener(this.TYPE);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if(this.processEvent!=null) this.unifiedChainEvents.registerListener(this.TYPE, this.processEvent.bind(this), this._swapDeserializer.bind(null, this));
|
|
390
|
+
|
|
391
|
+
this.isInitialized = true;
|
|
392
|
+
|
|
393
|
+
if(!noTimers) this.startTickInterval();
|
|
394
|
+
|
|
395
|
+
// this.logger.info("init(): Swap wrapper initialized");
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Un-subscribes from event listeners on the smart chain, terminates the tick interval and stops this wrapper
|
|
400
|
+
*/
|
|
401
|
+
public async stop() {
|
|
402
|
+
this.isInitialized = false;
|
|
403
|
+
this.unifiedChainEvents.unregisterListener(this.TYPE);
|
|
404
|
+
this.logger.info("stop(): Swap wrapper stopped");
|
|
405
|
+
if(this.tickInterval!=null) {
|
|
406
|
+
clearTimeout(this.tickInterval);
|
|
407
|
+
delete this.tickInterval;
|
|
408
|
+
}
|
|
409
|
+
if(this.tickAbortController!=null) {
|
|
410
|
+
this.tickAbortController.abort("Wrapper instance stopped!");
|
|
411
|
+
delete this.tickAbortController;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Runs checks on all the known pending swaps, syncing their state from on-chain data
|
|
417
|
+
*
|
|
418
|
+
* @remarks Doesn't work properly if you pass non-persisted swaps
|
|
419
|
+
*
|
|
420
|
+
* @param pastSwaps Optional array of past swaps to check, otherwise all relevant swaps will be fetched
|
|
421
|
+
* from the persistent storage
|
|
422
|
+
* @param noSave Whether to skip saving the swap changes in the persistent storage
|
|
423
|
+
*/
|
|
424
|
+
public async checkPastSwaps(pastSwaps?: D["Swap"][], noSave?: boolean): Promise<{ removeSwaps: D["Swap"][], changedSwaps: D["Swap"][] }> {
|
|
425
|
+
if (pastSwaps == null) pastSwaps = await this.unifiedStorage.query<D["Swap"]>(
|
|
426
|
+
[[{key: "type", value: this.TYPE}, {key: "state", value: this._pendingSwapStates}]],
|
|
427
|
+
(val: any) => new this._swapDeserializer(this, val)
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
const maxParallelSyncs = this._options.maxParallelSwapSyncs ?? DEFAULT_MAX_PARALLEL_SWAP_SYNCS;
|
|
431
|
+
|
|
432
|
+
const totalRemoveSwaps: D["Swap"][] = [];
|
|
433
|
+
const totalChangedSwaps: D["Swap"][] = [];
|
|
434
|
+
for(let i=0; i<pastSwaps.length; i+=maxParallelSyncs) {
|
|
435
|
+
const {removeSwaps, changedSwaps} = await this._checkPastSwaps(pastSwaps.slice(i, i+maxParallelSyncs));
|
|
436
|
+
if (!noSave) {
|
|
437
|
+
await this.unifiedStorage.removeAll(removeSwaps, true);
|
|
438
|
+
await this.unifiedStorage.saveAll(changedSwaps, true);
|
|
439
|
+
changedSwaps.forEach(swap => swap._emitEvent());
|
|
440
|
+
removeSwaps.forEach(swap => swap._emitEvent());
|
|
441
|
+
}
|
|
442
|
+
totalRemoveSwaps.push(...removeSwaps);
|
|
443
|
+
totalChangedSwaps.push(...changedSwaps);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return {
|
|
447
|
+
removeSwaps: totalRemoveSwaps,
|
|
448
|
+
changedSwaps: totalChangedSwaps
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Invokes {@link ISwap._tick} on all the known swaps
|
|
454
|
+
*
|
|
455
|
+
* @param swaps Optional array of swaps to invoke `_tick()` on, otherwise all relevant swaps will be fetched
|
|
456
|
+
* from the persistent storage
|
|
457
|
+
* @param abortSignal Abort signal
|
|
458
|
+
*/
|
|
459
|
+
public async tick(swaps?: D["Swap"][], abortSignal?: AbortSignal): Promise<void> {
|
|
460
|
+
if(swaps==null) swaps = await this.unifiedStorage.query<D["Swap"]>(
|
|
461
|
+
[[{key: "type", value: this.TYPE}, {key: "state", value: this.tickSwapState}]],
|
|
462
|
+
(val: any) => new this._swapDeserializer(this, val)
|
|
463
|
+
);
|
|
464
|
+
abortSignal?.throwIfAborted();
|
|
465
|
+
|
|
466
|
+
const parallelTicks = this._options.maxParallelSwapTicks ?? DEFAULT_MAX_PARALLEL_SWAP_TICKS;
|
|
467
|
+
|
|
468
|
+
let promises: Promise<any>[] = [];
|
|
469
|
+
for(let pendingSwap of this.pendingSwaps.values()) {
|
|
470
|
+
const value = pendingSwap.deref();
|
|
471
|
+
if(value != null) promises.push(value._tick(true).catch(e => {
|
|
472
|
+
this.logger.warn(`tick(): Error ticking swap ${value.getId()}: `, e);
|
|
473
|
+
}));
|
|
474
|
+
if(promises.length >= parallelTicks) {
|
|
475
|
+
await Promise.all(promises);
|
|
476
|
+
abortSignal?.throwIfAborted();
|
|
477
|
+
promises = [];
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
for(let value of swaps) {
|
|
482
|
+
promises.push(value._tick(true).catch(e => {
|
|
483
|
+
this.logger.warn(`tick(): Error ticking swap ${value.getId()}: `, e);
|
|
484
|
+
}));
|
|
485
|
+
if(promises.length >= parallelTicks) {
|
|
486
|
+
await Promise.all(promises);
|
|
487
|
+
abortSignal?.throwIfAborted();
|
|
488
|
+
promises = [];
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if(promises.length>0) await Promise.all(promises);
|
|
493
|
+
abortSignal?.throwIfAborted();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Returns the smart chain's native token used to pay for fees
|
|
498
|
+
* @internal
|
|
499
|
+
*/
|
|
500
|
+
_getNativeToken(): SCToken<T["ChainId"]> {
|
|
501
|
+
return this._tokens[this._chain.getNativeCurrencyAddress()];
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Saves the swap, if it is not initiated it is only saved to pending swaps
|
|
506
|
+
*
|
|
507
|
+
* @param swap Swap to save
|
|
508
|
+
*
|
|
509
|
+
* @internal
|
|
510
|
+
*/
|
|
511
|
+
_saveSwapData(swap: D["Swap"]): Promise<void> {
|
|
512
|
+
if(!this._options.saveUninitializedSwaps) {
|
|
513
|
+
if(!swap.isInitiated()) {
|
|
514
|
+
this.logger.debug("saveSwapData(): Swap "+swap.getId()+" not initiated, saving to pending swaps");
|
|
515
|
+
this.pendingSwaps.set(swap.getId(), new WeakRef<D["Swap"]>(swap));
|
|
516
|
+
return Promise.resolve();
|
|
517
|
+
} else {
|
|
518
|
+
this.pendingSwaps.delete(swap.getId());
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return this.unifiedStorage.save(swap);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Removes the swap from the persistent storage and pending swaps
|
|
526
|
+
*
|
|
527
|
+
* @param swap Swap to remove
|
|
528
|
+
*
|
|
529
|
+
* @internal
|
|
530
|
+
*/
|
|
531
|
+
_removeSwapData(swap: D["Swap"]): Promise<void> {
|
|
532
|
+
this.pendingSwaps.delete(swap.getId());
|
|
533
|
+
if(!swap._persisted) return Promise.resolve();
|
|
534
|
+
return this.unifiedStorage.remove(swap);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Retrieves a swap by its ID from the pending swap mapping
|
|
539
|
+
*
|
|
540
|
+
* @param id
|
|
541
|
+
*
|
|
542
|
+
* @internal
|
|
543
|
+
*/
|
|
544
|
+
_getPendingSwap(id: string): D["Swap"] | null {
|
|
545
|
+
return this.pendingSwaps.get(id)?.deref() ?? null;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* @internal
|
|
550
|
+
*/
|
|
551
|
+
async _getSignerAddress(signer?: string | T["Signer"] | T["NativeSigner"]): Promise<string | undefined> {
|
|
552
|
+
let address: string | undefined = undefined;
|
|
553
|
+
if(signer!=null) {
|
|
554
|
+
if (typeof (signer) === "string") {
|
|
555
|
+
address = signer;
|
|
556
|
+
} else if (isAbstractSigner(signer)) {
|
|
557
|
+
address = signer.getAddress();
|
|
558
|
+
} else {
|
|
559
|
+
address = (await this._chain.wrapSigner(signer)).getAddress();
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return address;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
565
|
}
|