@atomiqlabs/sdk 8.9.1 → 8.9.3
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 +770 -770
- package/dist/swapper/Swapper.js +1758 -1758
- 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 +2570 -2570
- 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,753 +1,753 @@
|
|
|
1
|
-
import {decode as bolt11Decode} from "@atomiqlabs/bolt11";
|
|
2
|
-
import {SwapType} from "../../../enums/SwapType";
|
|
3
|
-
import {ChainType} from "@atomiqlabs/base";
|
|
4
|
-
import {LnForGasSwapTypeDefinition, LnForGasWrapper} from "./LnForGasWrapper";
|
|
5
|
-
import {extendAbortController, toBigInt} from "../../../utils/Utils";
|
|
6
|
-
import {isISwapInit, ISwap, ISwapInit} from "../../ISwap";
|
|
7
|
-
import {TrustedInvoiceStatusResponseCodes} from "../../../intermediaries/apis/IntermediaryAPI";
|
|
8
|
-
import {Fee} from "../../../types/fees/Fee";
|
|
9
|
-
import {IAddressSwap} from "../../IAddressSwap";
|
|
10
|
-
import {FeeType} from "../../../enums/FeeType";
|
|
11
|
-
import {ppmToPercentage} from "../../../types/fees/PercentagePPM";
|
|
12
|
-
import {TokenAmount, toTokenAmount} from "../../../types/TokenAmount";
|
|
13
|
-
import {BitcoinTokens, BtcToken, SCToken} from "../../../types/Token";
|
|
14
|
-
import {getLogger, LoggerType} from "../../../utils/Logger";
|
|
15
|
-
import {timeoutPromise} from "../../../utils/TimeoutUtils";
|
|
16
|
-
import {
|
|
17
|
-
SwapExecutionActionSendToAddress,
|
|
18
|
-
SwapExecutionActionWait
|
|
19
|
-
} from "../../../types/SwapExecutionAction";
|
|
20
|
-
import {
|
|
21
|
-
SwapExecutionStepPayment,
|
|
22
|
-
SwapExecutionStepSettlement
|
|
23
|
-
} from "../../../types/SwapExecutionStep";
|
|
24
|
-
import {SwapStateInfo} from "../../../types/SwapStateInfo";
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* State enum for trusted Lightning gas swaps
|
|
28
|
-
*
|
|
29
|
-
* @category Swaps/Trusted Gas Swaps
|
|
30
|
-
*/
|
|
31
|
-
export enum LnForGasSwapState {
|
|
32
|
-
/**
|
|
33
|
-
* The swap quote expired before the user paid the Lightning invoice
|
|
34
|
-
*/
|
|
35
|
-
EXPIRED = -2,
|
|
36
|
-
/**
|
|
37
|
-
* The swap has failed before the destination payout completed, and the held Lightning invoice was released
|
|
38
|
-
*/
|
|
39
|
-
FAILED = -1,
|
|
40
|
-
/**
|
|
41
|
-
* Swap was created, pay the provided Lightning invoice which will remain held until destination payout succeeds
|
|
42
|
-
*/
|
|
43
|
-
PR_CREATED = 0,
|
|
44
|
-
/**
|
|
45
|
-
* The Lightning invoice was paid and is currently held until the user receives the destination funds
|
|
46
|
-
*/
|
|
47
|
-
PR_PAID = 1,
|
|
48
|
-
/**
|
|
49
|
-
* The swap is finished after the destination payout succeeded and the held Lightning invoice was settled
|
|
50
|
-
*/
|
|
51
|
-
FINISHED = 2
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const LnForGasSwapStateDescription = {
|
|
55
|
-
[LnForGasSwapState.EXPIRED]:
|
|
56
|
-
"The swap quote expired before the user paid the Lightning invoice",
|
|
57
|
-
[LnForGasSwapState.FAILED]:
|
|
58
|
-
"The swap failed before destination payout completed, and the held Lightning invoice was released back to the user",
|
|
59
|
-
[LnForGasSwapState.PR_CREATED]:
|
|
60
|
-
"Swap was created, pay the provided Lightning invoice. The invoice will remain held until destination payout succeeds",
|
|
61
|
-
[LnForGasSwapState.PR_PAID]:
|
|
62
|
-
"The Lightning invoice was paid and is currently held. It will only settle once the user receives the destination funds",
|
|
63
|
-
[LnForGasSwapState.FINISHED]:
|
|
64
|
-
"The swap is finished after the destination payout succeeded and the held Lightning invoice was settled"
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export type LnForGasSwapInit = ISwapInit & {
|
|
68
|
-
pr: string;
|
|
69
|
-
outputAmount: bigint;
|
|
70
|
-
recipient: string;
|
|
71
|
-
token: string;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export function isLnForGasSwapInit(obj: any): obj is LnForGasSwapInit {
|
|
75
|
-
return typeof(obj.pr)==="string" &&
|
|
76
|
-
typeof(obj.outputAmount) === "bigint" &&
|
|
77
|
-
typeof(obj.recipient)==="string" &&
|
|
78
|
-
typeof(obj.token)==="string" &&
|
|
79
|
-
isISwapInit(obj);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Trusted swap for Bitcoin Lightning -> Smart chains, to be used for minor amounts to get gas tokens on
|
|
84
|
-
* the destination chain, which is only needed for Solana, which still uses legacy swaps
|
|
85
|
-
*
|
|
86
|
-
* @category Swaps/Trusted Gas Swaps
|
|
87
|
-
*/
|
|
88
|
-
export class LnForGasSwap<T extends ChainType = ChainType> extends ISwap<T, LnForGasSwapTypeDefinition<T>, LnForGasSwapState> implements IAddressSwap {
|
|
89
|
-
protected readonly TYPE: SwapType.TRUSTED_FROM_BTCLN = SwapType.TRUSTED_FROM_BTCLN;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @internal
|
|
93
|
-
*/
|
|
94
|
-
protected readonly swapStateDescription = LnForGasSwapStateDescription;
|
|
95
|
-
/**
|
|
96
|
-
* @internal
|
|
97
|
-
*/
|
|
98
|
-
protected readonly swapStateName = (state: number) => LnForGasSwapState[state];
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @internal
|
|
102
|
-
*/
|
|
103
|
-
protected readonly currentVersion: number = 2;
|
|
104
|
-
/**
|
|
105
|
-
* @internal
|
|
106
|
-
*/
|
|
107
|
-
protected readonly logger: LoggerType;
|
|
108
|
-
|
|
109
|
-
//State: PR_CREATED
|
|
110
|
-
private readonly pr: string;
|
|
111
|
-
private readonly outputAmount: bigint;
|
|
112
|
-
private readonly recipient: string;
|
|
113
|
-
private readonly token: string;
|
|
114
|
-
|
|
115
|
-
//State: FINISHED
|
|
116
|
-
/**
|
|
117
|
-
* Destination transaction ID on the smart chain side
|
|
118
|
-
* @private
|
|
119
|
-
*/
|
|
120
|
-
private scTxId?: string;
|
|
121
|
-
|
|
122
|
-
constructor(wrapper: LnForGasWrapper<T>, init: LnForGasSwapInit);
|
|
123
|
-
constructor(wrapper: LnForGasWrapper<T>, obj: any);
|
|
124
|
-
constructor(
|
|
125
|
-
wrapper: LnForGasWrapper<T>,
|
|
126
|
-
initOrObj: LnForGasSwapInit | any
|
|
127
|
-
) {
|
|
128
|
-
if(isLnForGasSwapInit(initOrObj) && initOrObj.url!=null) initOrObj.url += "/lnforgas";
|
|
129
|
-
super(wrapper, initOrObj);
|
|
130
|
-
if(isLnForGasSwapInit(initOrObj)) {
|
|
131
|
-
this.pr = initOrObj.pr;
|
|
132
|
-
this.outputAmount = initOrObj.outputAmount;
|
|
133
|
-
this.recipient = initOrObj.recipient;
|
|
134
|
-
this.token = initOrObj.token;
|
|
135
|
-
this._state = LnForGasSwapState.PR_CREATED;
|
|
136
|
-
} else {
|
|
137
|
-
this.pr = initOrObj.pr;
|
|
138
|
-
this.outputAmount = toBigInt(initOrObj.outputAmount);
|
|
139
|
-
this.recipient = initOrObj.recipient;
|
|
140
|
-
this.token = initOrObj.token;
|
|
141
|
-
this.scTxId = initOrObj.scTxId;
|
|
142
|
-
}
|
|
143
|
-
this.tryRecomputeSwapPrice();
|
|
144
|
-
if(this.pr!=null) {
|
|
145
|
-
const decoded = bolt11Decode(this.pr);
|
|
146
|
-
if(decoded.timeExpireDate!=null) this.expiry = decoded.timeExpireDate*1000;
|
|
147
|
-
}
|
|
148
|
-
this.logger = getLogger("LnForGas("+this.getId()+"): ");
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* @inheritDoc
|
|
153
|
-
* @internal
|
|
154
|
-
*/
|
|
155
|
-
protected upgradeVersion() {
|
|
156
|
-
if(this.version == 1) {
|
|
157
|
-
if(this._state===1) this._state = LnForGasSwapState.FINISHED;
|
|
158
|
-
this.version = 2;
|
|
159
|
-
}
|
|
160
|
-
if(this.version == null) {
|
|
161
|
-
//Noop
|
|
162
|
-
this.version = 1;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* @inheritDoc
|
|
168
|
-
* @internal
|
|
169
|
-
*/
|
|
170
|
-
protected tryRecomputeSwapPrice() {
|
|
171
|
-
if(this.swapFeeBtc==null && this.swapFee!=null) {
|
|
172
|
-
this.swapFeeBtc = this.swapFee * this.getInput().rawAmount / this.getOutAmountWithoutFee();
|
|
173
|
-
}
|
|
174
|
-
super.tryRecomputeSwapPrice();
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
//////////////////////////////
|
|
179
|
-
//// Getters & utils
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* @inheritDoc
|
|
183
|
-
* @internal
|
|
184
|
-
*/
|
|
185
|
-
_getEscrowHash(): string {
|
|
186
|
-
return this.getId();
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* @inheritDoc
|
|
191
|
-
*/
|
|
192
|
-
getOutputAddress(): string | null {
|
|
193
|
-
return this.recipient;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* @inheritDoc
|
|
198
|
-
*/
|
|
199
|
-
getInputAddress(): string | null {
|
|
200
|
-
return this.pr;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* @inheritDoc
|
|
205
|
-
*/
|
|
206
|
-
getInputTxId(): string | null {
|
|
207
|
-
return this.getId();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* @inheritDoc
|
|
212
|
-
*/
|
|
213
|
-
getOutputTxId(): string | null {
|
|
214
|
-
return this.scTxId ?? null;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @inheritDoc
|
|
219
|
-
*/
|
|
220
|
-
getId(): string {
|
|
221
|
-
if(this.pr==null) throw new Error("No payment request assigned to this swap!");
|
|
222
|
-
const decodedPR = bolt11Decode(this.pr);
|
|
223
|
-
if(decodedPR.tagsObject.payment_hash==null) throw new Error("Lightning invoice has no payment hash!");
|
|
224
|
-
return decodedPR.tagsObject.payment_hash;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap
|
|
229
|
-
*/
|
|
230
|
-
getAddress(): string {
|
|
231
|
-
return this.pr;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Returns a string that can be displayed as QR code representation of the lightning invoice (with lightning: prefix)
|
|
236
|
-
*/
|
|
237
|
-
getHyperlink(): string {
|
|
238
|
-
return "lightning:"+this.pr.toUpperCase();
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* @inheritDoc
|
|
243
|
-
*/
|
|
244
|
-
requiresAction(): boolean {
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* @inheritDoc
|
|
250
|
-
*/
|
|
251
|
-
isFinished(): boolean {
|
|
252
|
-
return this._state===LnForGasSwapState.FINISHED || this._state===LnForGasSwapState.FAILED || this._state===LnForGasSwapState.EXPIRED;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* @inheritDoc
|
|
257
|
-
*/
|
|
258
|
-
isQuoteExpired(): boolean {
|
|
259
|
-
return this._state===LnForGasSwapState.EXPIRED;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* @inheritDoc
|
|
264
|
-
*/
|
|
265
|
-
isQuoteSoftExpired(): boolean {
|
|
266
|
-
return this.expiry<Date.now();
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* @inheritDoc
|
|
271
|
-
*/
|
|
272
|
-
isFailed(): boolean {
|
|
273
|
-
return this._state===LnForGasSwapState.FAILED;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* @inheritDoc
|
|
278
|
-
*/
|
|
279
|
-
isSuccessful(): boolean {
|
|
280
|
-
return this._state===LnForGasSwapState.FINISHED;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* @inheritDoc
|
|
285
|
-
*/
|
|
286
|
-
isInProgress(): boolean {
|
|
287
|
-
return (this._state===LnForGasSwapState.PR_CREATED && this.initiated) || this._state===LnForGasSwapState.PR_PAID;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* @inheritDoc
|
|
292
|
-
* @internal
|
|
293
|
-
*/
|
|
294
|
-
_verifyQuoteDefinitelyExpired(): Promise<boolean> {
|
|
295
|
-
return Promise.resolve(this.expiry<Date.now());
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* @inheritDoc
|
|
300
|
-
* @internal
|
|
301
|
-
*/
|
|
302
|
-
_verifyQuoteValid(): Promise<boolean> {
|
|
303
|
-
return Promise.resolve(this.expiry>Date.now());
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
//////////////////////////////
|
|
307
|
-
//// Amounts & fees
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Returns an output amount in base units without a swap fee included, hence this value
|
|
311
|
-
* is larger than the actual output amount
|
|
312
|
-
*
|
|
313
|
-
* @internal
|
|
314
|
-
*/
|
|
315
|
-
protected getOutAmountWithoutFee(): bigint {
|
|
316
|
-
return this.outputAmount + (this.swapFee ?? 0n);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* @inheritDoc
|
|
321
|
-
*/
|
|
322
|
-
getOutputToken(): SCToken<T["ChainId"]> {
|
|
323
|
-
return this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()];
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* @inheritDoc
|
|
328
|
-
*/
|
|
329
|
-
getOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
|
|
330
|
-
return toTokenAmount(
|
|
331
|
-
this.outputAmount, this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()],
|
|
332
|
-
this.wrapper._prices, this.pricingInfo
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* @inheritDoc
|
|
338
|
-
*/
|
|
339
|
-
getInputToken(): BtcToken<true> {
|
|
340
|
-
return BitcoinTokens.BTCLN;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* @inheritDoc
|
|
345
|
-
*/
|
|
346
|
-
getInput(): TokenAmount<BtcToken<true>, true> {
|
|
347
|
-
const parsed = bolt11Decode(this.pr);
|
|
348
|
-
const msats = parsed.millisatoshis;
|
|
349
|
-
if(msats==null) throw new Error("Swap lightning invoice has no msat amount field!");
|
|
350
|
-
const amount = (BigInt(msats) + 999n) / 1000n;
|
|
351
|
-
return toTokenAmount(amount, BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* @inheritDoc
|
|
356
|
-
*/
|
|
357
|
-
getInputWithoutFee(): TokenAmount<BtcToken<true>, true> {
|
|
358
|
-
const parsed = bolt11Decode(this.pr);
|
|
359
|
-
const msats = parsed.millisatoshis;
|
|
360
|
-
if(msats==null) throw new Error("Swap lightning invoice has no msat amount field!");
|
|
361
|
-
const amount = (BigInt(msats) + 999n) / 1000n;
|
|
362
|
-
return toTokenAmount(
|
|
363
|
-
amount - (this.swapFeeBtc ?? 0n), BitcoinTokens.BTCLN,
|
|
364
|
-
this.wrapper._prices, this.pricingInfo
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Returns the swap fee charged by the intermediary (LP) on this swap
|
|
370
|
-
*
|
|
371
|
-
* @internal
|
|
372
|
-
*/
|
|
373
|
-
protected getSwapFee(): Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>> {
|
|
374
|
-
if(this.pricingInfo==null) throw new Error("No pricing info known, cannot estimate swap fee!");
|
|
375
|
-
const feeWithoutBaseFee = this.swapFeeBtc==null ? 0n : this.swapFeeBtc - this.pricingInfo.satsBaseFee;
|
|
376
|
-
const swapFeePPM = feeWithoutBaseFee * 1000000n / this.getInputWithoutFee().rawAmount;
|
|
377
|
-
|
|
378
|
-
const amountInSrcToken = toTokenAmount(this.swapFeeBtc ?? 0n, BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
|
|
379
|
-
return {
|
|
380
|
-
amountInSrcToken,
|
|
381
|
-
amountInDstToken: toTokenAmount(this.swapFee ?? 0n, this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()], this.wrapper._prices, this.pricingInfo),
|
|
382
|
-
currentUsdValue: amountInSrcToken.currentUsdValue,
|
|
383
|
-
usdValue: amountInSrcToken.usdValue,
|
|
384
|
-
pastUsdValue: amountInSrcToken.pastUsdValue,
|
|
385
|
-
composition: {
|
|
386
|
-
base: toTokenAmount(this.pricingInfo.satsBaseFee, BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo),
|
|
387
|
-
percentage: ppmToPercentage(swapFeePPM)
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* @inheritDoc
|
|
394
|
-
*/
|
|
395
|
-
getFee(): Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>> {
|
|
396
|
-
return this.getSwapFee();
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* @inheritDoc
|
|
401
|
-
*/
|
|
402
|
-
getFeeBreakdown(): [{type: FeeType.SWAP, fee: Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>>}] {
|
|
403
|
-
return [{
|
|
404
|
-
type: FeeType.SWAP,
|
|
405
|
-
fee: this.getSwapFee()
|
|
406
|
-
}];
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
//////////////////////////////
|
|
411
|
-
//// Payment
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* @remarks Not supported
|
|
415
|
-
*/
|
|
416
|
-
async execute(): Promise<boolean> {
|
|
417
|
-
throw new Error("Not supported");
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* @internal
|
|
422
|
-
*/
|
|
423
|
-
protected async _getExecutionStatus() {
|
|
424
|
-
const state = this._state;
|
|
425
|
-
|
|
426
|
-
let lightningPaymentStatus: SwapExecutionStepPayment<"LIGHTNING">["status"] = "inactive";
|
|
427
|
-
let destinationSettlementStatus: SwapExecutionStepSettlement<T["ChainId"]>["status"] = "inactive";
|
|
428
|
-
let buildCurrentAction: () => Promise<
|
|
429
|
-
SwapExecutionActionSendToAddress<true> |
|
|
430
|
-
SwapExecutionActionWait<"LP"> |
|
|
431
|
-
undefined
|
|
432
|
-
> = async () => undefined;
|
|
433
|
-
|
|
434
|
-
switch(state) {
|
|
435
|
-
case LnForGasSwapState.PR_CREATED: {
|
|
436
|
-
const quoteValid = await this._verifyQuoteValid();
|
|
437
|
-
lightningPaymentStatus = quoteValid ? "awaiting" : "soft_expired";
|
|
438
|
-
if(quoteValid) {
|
|
439
|
-
buildCurrentAction = this._buildLightningPaymentAction.bind(this);
|
|
440
|
-
}
|
|
441
|
-
break;
|
|
442
|
-
}
|
|
443
|
-
case LnForGasSwapState.EXPIRED:
|
|
444
|
-
lightningPaymentStatus = "expired";
|
|
445
|
-
break;
|
|
446
|
-
case LnForGasSwapState.PR_PAID:
|
|
447
|
-
lightningPaymentStatus = "received";
|
|
448
|
-
destinationSettlementStatus = "waiting_lp";
|
|
449
|
-
buildCurrentAction = this._buildWaitLpAction.bind(this);
|
|
450
|
-
break;
|
|
451
|
-
case LnForGasSwapState.FAILED:
|
|
452
|
-
lightningPaymentStatus = "expired";
|
|
453
|
-
destinationSettlementStatus = "expired";
|
|
454
|
-
break;
|
|
455
|
-
case LnForGasSwapState.FINISHED:
|
|
456
|
-
lightningPaymentStatus = "confirmed";
|
|
457
|
-
destinationSettlementStatus = "settled";
|
|
458
|
-
break;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
return {
|
|
462
|
-
steps: [
|
|
463
|
-
{
|
|
464
|
-
type: "Payment",
|
|
465
|
-
side: "source",
|
|
466
|
-
chain: "LIGHTNING",
|
|
467
|
-
title: "Lightning payment",
|
|
468
|
-
description: "Pay the Lightning network invoice to initiate the swap",
|
|
469
|
-
status: lightningPaymentStatus
|
|
470
|
-
},
|
|
471
|
-
{
|
|
472
|
-
type: "Settlement",
|
|
473
|
-
side: "destination",
|
|
474
|
-
chain: this.chainIdentifier,
|
|
475
|
-
title: "Destination payout",
|
|
476
|
-
description: "Wait for the intermediary to send the gas tokens on the destination smart chain",
|
|
477
|
-
status: destinationSettlementStatus
|
|
478
|
-
}
|
|
479
|
-
] as [
|
|
480
|
-
SwapExecutionStepPayment<"LIGHTNING">,
|
|
481
|
-
SwapExecutionStepSettlement<T["ChainId"], never>
|
|
482
|
-
],
|
|
483
|
-
buildCurrentAction,
|
|
484
|
-
state
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* @internal
|
|
490
|
-
* @inheritDoc
|
|
491
|
-
*/
|
|
492
|
-
_submitExecutionTransactions(): Promise<string[]> {
|
|
493
|
-
throw new Error("Invalid swap state for transaction submission!");
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
/**
|
|
497
|
-
* @internal
|
|
498
|
-
*/
|
|
499
|
-
private async _buildLightningPaymentAction(): Promise<SwapExecutionActionSendToAddress<true>> {
|
|
500
|
-
return {
|
|
501
|
-
type: "SendToAddress",
|
|
502
|
-
name: "Deposit on Lightning",
|
|
503
|
-
description: "Pay the lightning network invoice to initiate the swap",
|
|
504
|
-
chain: "LIGHTNING",
|
|
505
|
-
txs: [{
|
|
506
|
-
type: "BOLT11_PAYMENT_REQUEST",
|
|
507
|
-
address: this.pr,
|
|
508
|
-
hyperlink: this.getHyperlink(),
|
|
509
|
-
amount: this.getInput()
|
|
510
|
-
}],
|
|
511
|
-
waitForTransactions: async (
|
|
512
|
-
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal
|
|
513
|
-
) => {
|
|
514
|
-
const abortController = extendAbortController(
|
|
515
|
-
abortSignal, maxWaitTimeSeconds, "Timed out waiting for lightning payment"
|
|
516
|
-
);
|
|
517
|
-
let lightningTxId: string | undefined;
|
|
518
|
-
try {
|
|
519
|
-
const success = await this.waitForPayment(
|
|
520
|
-
pollIntervalSeconds, abortController.signal,
|
|
521
|
-
(txId: string) => {
|
|
522
|
-
lightningTxId = txId;
|
|
523
|
-
abortController.abort();
|
|
524
|
-
}
|
|
525
|
-
);
|
|
526
|
-
if(!success) throw new Error("Quote expired while waiting for lightning payment");
|
|
527
|
-
} catch (e) {
|
|
528
|
-
if(lightningTxId!=null) return lightningTxId;
|
|
529
|
-
throw e;
|
|
530
|
-
}
|
|
531
|
-
return this.getInputTxId()!;
|
|
532
|
-
}
|
|
533
|
-
} as SwapExecutionActionSendToAddress<true>;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
/**
|
|
537
|
-
* @internal
|
|
538
|
-
*/
|
|
539
|
-
private async _buildWaitLpAction(): Promise<SwapExecutionActionWait<"LP">> {
|
|
540
|
-
return {
|
|
541
|
-
type: "Wait",
|
|
542
|
-
name: "Awaiting LP payout",
|
|
543
|
-
description: "Wait for the intermediary to send the gas tokens on the destination smart chain",
|
|
544
|
-
pollTimeSeconds: 5,
|
|
545
|
-
expectedTimeSeconds: 10,
|
|
546
|
-
wait: async (
|
|
547
|
-
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal
|
|
548
|
-
) => {
|
|
549
|
-
const abortController = extendAbortController(
|
|
550
|
-
abortSignal, maxWaitTimeSeconds, "Timed out waiting for LP payout"
|
|
551
|
-
);
|
|
552
|
-
await this.waitForPayment(pollIntervalSeconds, abortController.signal);
|
|
553
|
-
}
|
|
554
|
-
} as SwapExecutionActionWait<"LP">;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
/**
|
|
558
|
-
* @inheritDoc
|
|
559
|
-
*/
|
|
560
|
-
async getExecutionAction(): Promise<
|
|
561
|
-
SwapExecutionActionSendToAddress<true> |
|
|
562
|
-
SwapExecutionActionWait<"LP"> |
|
|
563
|
-
undefined
|
|
564
|
-
> {
|
|
565
|
-
const executionStatus = await this._getExecutionStatus();
|
|
566
|
-
return executionStatus.buildCurrentAction();
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
/**
|
|
570
|
-
* @inheritDoc
|
|
571
|
-
*/
|
|
572
|
-
async getExecutionStatus(options?: {skipBuildingAction?: boolean}): Promise<{
|
|
573
|
-
steps: [
|
|
574
|
-
SwapExecutionStepPayment<"LIGHTNING">,
|
|
575
|
-
SwapExecutionStepSettlement<T["ChainId"], never>
|
|
576
|
-
],
|
|
577
|
-
currentAction:
|
|
578
|
-
SwapExecutionActionSendToAddress<true> |
|
|
579
|
-
SwapExecutionActionWait<"LP"> |
|
|
580
|
-
undefined,
|
|
581
|
-
stateInfo: SwapStateInfo<LnForGasSwapState>
|
|
582
|
-
}> {
|
|
583
|
-
const executionStatus = await this._getExecutionStatus();
|
|
584
|
-
return {
|
|
585
|
-
steps: executionStatus.steps,
|
|
586
|
-
currentAction: options?.skipBuildingAction ? undefined : await executionStatus.buildCurrentAction(),
|
|
587
|
-
stateInfo: this._getStateInfo(executionStatus.state)
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
/**
|
|
592
|
-
* @inheritDoc
|
|
593
|
-
*/
|
|
594
|
-
async getExecutionSteps(): Promise<[
|
|
595
|
-
SwapExecutionStepPayment<"LIGHTNING">,
|
|
596
|
-
SwapExecutionStepSettlement<T["ChainId"], never>
|
|
597
|
-
]> {
|
|
598
|
-
return (await this._getExecutionStatus()).steps;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
/**
|
|
602
|
-
* Queries the intermediary (LP) node for the state of the swap
|
|
603
|
-
*
|
|
604
|
-
* @param save Whether the save the result or not
|
|
605
|
-
*
|
|
606
|
-
* @returns Whether the swap was successful as `boolean` or `null` if the swap is still pending
|
|
607
|
-
* @internal
|
|
608
|
-
*/
|
|
609
|
-
protected async checkInvoicePaid(save: boolean = true): Promise<boolean | null> {
|
|
610
|
-
if(this._state===LnForGasSwapState.FAILED || this._state===LnForGasSwapState.EXPIRED) return false;
|
|
611
|
-
if(this._state===LnForGasSwapState.FINISHED) return true;
|
|
612
|
-
if(this.url==null) return false;
|
|
613
|
-
|
|
614
|
-
const decodedPR = bolt11Decode(this.pr);
|
|
615
|
-
const paymentHash = decodedPR.tagsObject.payment_hash;
|
|
616
|
-
if(paymentHash==null) throw new Error("Invalid swap invoice, payment hash not found!");
|
|
617
|
-
|
|
618
|
-
const response = await this.wrapper._lpApi.getTrustedInvoiceStatus(
|
|
619
|
-
this.url, paymentHash, this.wrapper._options.getRequestTimeout
|
|
620
|
-
);
|
|
621
|
-
this.logger.debug("checkInvoicePaid(): LP response: ", response);
|
|
622
|
-
switch(response.code) {
|
|
623
|
-
case TrustedInvoiceStatusResponseCodes.PAID:
|
|
624
|
-
this.scTxId = response.data.txId;
|
|
625
|
-
const txStatus = await this.wrapper._chain.getTxIdStatus(this.scTxId);
|
|
626
|
-
if(txStatus==="success") {
|
|
627
|
-
this._state = LnForGasSwapState.FINISHED;
|
|
628
|
-
if(save) await this._saveAndEmit();
|
|
629
|
-
return true;
|
|
630
|
-
}
|
|
631
|
-
return null;
|
|
632
|
-
case TrustedInvoiceStatusResponseCodes.EXPIRED:
|
|
633
|
-
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
634
|
-
this._state = LnForGasSwapState.EXPIRED;
|
|
635
|
-
} else {
|
|
636
|
-
this._state = LnForGasSwapState.FAILED;
|
|
637
|
-
}
|
|
638
|
-
if(save) await this._saveAndEmit();
|
|
639
|
-
return false;
|
|
640
|
-
case TrustedInvoiceStatusResponseCodes.TX_SENT:
|
|
641
|
-
this.scTxId = response.data.txId;
|
|
642
|
-
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
643
|
-
this._state = LnForGasSwapState.PR_PAID;
|
|
644
|
-
if(save) await this._saveAndEmit();
|
|
645
|
-
}
|
|
646
|
-
return null;
|
|
647
|
-
case TrustedInvoiceStatusResponseCodes.PENDING:
|
|
648
|
-
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
649
|
-
this._state = LnForGasSwapState.PR_PAID;
|
|
650
|
-
if(save) await this._saveAndEmit();
|
|
651
|
-
}
|
|
652
|
-
return null;
|
|
653
|
-
case TrustedInvoiceStatusResponseCodes.AWAIT_PAYMENT:
|
|
654
|
-
return null;
|
|
655
|
-
default:
|
|
656
|
-
this._state = LnForGasSwapState.FAILED;
|
|
657
|
-
if(save) await this._saveAndEmit();
|
|
658
|
-
return false;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
/**
|
|
663
|
-
* A blocking promise resolving when payment was received by the intermediary and client can continue,
|
|
664
|
-
* rejecting in case of failure. The swap must be in {@link LnForGasSwapState.PR_CREATED} or
|
|
665
|
-
* {@link LnForGasSwapState.PR_PAID} state!
|
|
666
|
-
*
|
|
667
|
-
* @param checkIntervalSeconds How often to poll the intermediary for answer (default 5 seconds)
|
|
668
|
-
* @param abortSignal Abort signal
|
|
669
|
-
* @param onPaymentReceived Callback as for when the LP reports having received the ln payment
|
|
670
|
-
* @throws {Error} When in invalid state (not PR_CREATED)
|
|
671
|
-
*/
|
|
672
|
-
async waitForPayment(checkIntervalSeconds?: number, abortSignal?: AbortSignal, onPaymentReceived?: (txId: string) => void): Promise<boolean> {
|
|
673
|
-
if(this._state!==LnForGasSwapState.PR_CREATED && this._state!==LnForGasSwapState.PR_PAID)
|
|
674
|
-
throw new Error("Must be in PR_CREATED or PR_PAID state!");
|
|
675
|
-
|
|
676
|
-
if(!this.initiated) {
|
|
677
|
-
this.initiated = true;
|
|
678
|
-
await this._saveAndEmit();
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
while(!abortSignal?.aborted && (this._state===LnForGasSwapState.PR_CREATED || this._state===LnForGasSwapState.PR_PAID)) {
|
|
682
|
-
await this.checkInvoicePaid(true);
|
|
683
|
-
if((this._state as LnForGasSwapState)===LnForGasSwapState.PR_PAID) {
|
|
684
|
-
if(onPaymentReceived!=null) {
|
|
685
|
-
onPaymentReceived(this.getInputTxId()!);
|
|
686
|
-
onPaymentReceived = undefined; // Set to null so it only triggers once
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
if(this._state===LnForGasSwapState.PR_CREATED || this._state===LnForGasSwapState.PR_PAID) await timeoutPromise((checkIntervalSeconds ?? 5)*1000, abortSignal);
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
if(abortSignal!=null) abortSignal.throwIfAborted();
|
|
693
|
-
|
|
694
|
-
if(this.isFailed()) throw new Error("Swap failed");
|
|
695
|
-
return !this.isQuoteExpired();
|
|
696
|
-
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
//////////////////////////////
|
|
701
|
-
//// Storage
|
|
702
|
-
|
|
703
|
-
/**
|
|
704
|
-
* @inheritDoc
|
|
705
|
-
*/
|
|
706
|
-
serialize(): any{
|
|
707
|
-
return {
|
|
708
|
-
...super.serialize(),
|
|
709
|
-
pr: this.pr,
|
|
710
|
-
outputAmount: this.outputAmount==null ? null : this.outputAmount.toString(10),
|
|
711
|
-
recipient: this.recipient,
|
|
712
|
-
token: this.token,
|
|
713
|
-
scTxId: this.scTxId
|
|
714
|
-
};
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
/**
|
|
718
|
-
* @inheritDoc
|
|
719
|
-
* @internal
|
|
720
|
-
*/
|
|
721
|
-
_getInitiator(): string {
|
|
722
|
-
return this.recipient;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
//////////////////////////////
|
|
727
|
-
//// Swap ticks & sync
|
|
728
|
-
|
|
729
|
-
/**
|
|
730
|
-
* @inheritDoc
|
|
731
|
-
* @internal
|
|
732
|
-
*/
|
|
733
|
-
async _sync(save?: boolean): Promise<boolean> {
|
|
734
|
-
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
735
|
-
//Check if it's maybe already paid
|
|
736
|
-
const res = await this.checkInvoicePaid(false);
|
|
737
|
-
if(res!==null) {
|
|
738
|
-
if(save) await this._saveAndEmit();
|
|
739
|
-
return true;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
return false;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* @inheritDoc
|
|
747
|
-
* @internal
|
|
748
|
-
*/
|
|
749
|
-
_tick(save?: boolean): Promise<boolean> {
|
|
750
|
-
return Promise.resolve(false);
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
}
|
|
1
|
+
import {decode as bolt11Decode} from "@atomiqlabs/bolt11";
|
|
2
|
+
import {SwapType} from "../../../enums/SwapType";
|
|
3
|
+
import {ChainType} from "@atomiqlabs/base";
|
|
4
|
+
import {LnForGasSwapTypeDefinition, LnForGasWrapper} from "./LnForGasWrapper";
|
|
5
|
+
import {extendAbortController, toBigInt} from "../../../utils/Utils";
|
|
6
|
+
import {isISwapInit, ISwap, ISwapInit} from "../../ISwap";
|
|
7
|
+
import {TrustedInvoiceStatusResponseCodes} from "../../../intermediaries/apis/IntermediaryAPI";
|
|
8
|
+
import {Fee} from "../../../types/fees/Fee";
|
|
9
|
+
import {IAddressSwap} from "../../IAddressSwap";
|
|
10
|
+
import {FeeType} from "../../../enums/FeeType";
|
|
11
|
+
import {ppmToPercentage} from "../../../types/fees/PercentagePPM";
|
|
12
|
+
import {TokenAmount, toTokenAmount} from "../../../types/TokenAmount";
|
|
13
|
+
import {BitcoinTokens, BtcToken, SCToken} from "../../../types/Token";
|
|
14
|
+
import {getLogger, LoggerType} from "../../../utils/Logger";
|
|
15
|
+
import {timeoutPromise} from "../../../utils/TimeoutUtils";
|
|
16
|
+
import {
|
|
17
|
+
SwapExecutionActionSendToAddress,
|
|
18
|
+
SwapExecutionActionWait
|
|
19
|
+
} from "../../../types/SwapExecutionAction";
|
|
20
|
+
import {
|
|
21
|
+
SwapExecutionStepPayment,
|
|
22
|
+
SwapExecutionStepSettlement
|
|
23
|
+
} from "../../../types/SwapExecutionStep";
|
|
24
|
+
import {SwapStateInfo} from "../../../types/SwapStateInfo";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* State enum for trusted Lightning gas swaps
|
|
28
|
+
*
|
|
29
|
+
* @category Swaps/Trusted Gas Swaps
|
|
30
|
+
*/
|
|
31
|
+
export enum LnForGasSwapState {
|
|
32
|
+
/**
|
|
33
|
+
* The swap quote expired before the user paid the Lightning invoice
|
|
34
|
+
*/
|
|
35
|
+
EXPIRED = -2,
|
|
36
|
+
/**
|
|
37
|
+
* The swap has failed before the destination payout completed, and the held Lightning invoice was released
|
|
38
|
+
*/
|
|
39
|
+
FAILED = -1,
|
|
40
|
+
/**
|
|
41
|
+
* Swap was created, pay the provided Lightning invoice which will remain held until destination payout succeeds
|
|
42
|
+
*/
|
|
43
|
+
PR_CREATED = 0,
|
|
44
|
+
/**
|
|
45
|
+
* The Lightning invoice was paid and is currently held until the user receives the destination funds
|
|
46
|
+
*/
|
|
47
|
+
PR_PAID = 1,
|
|
48
|
+
/**
|
|
49
|
+
* The swap is finished after the destination payout succeeded and the held Lightning invoice was settled
|
|
50
|
+
*/
|
|
51
|
+
FINISHED = 2
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const LnForGasSwapStateDescription = {
|
|
55
|
+
[LnForGasSwapState.EXPIRED]:
|
|
56
|
+
"The swap quote expired before the user paid the Lightning invoice",
|
|
57
|
+
[LnForGasSwapState.FAILED]:
|
|
58
|
+
"The swap failed before destination payout completed, and the held Lightning invoice was released back to the user",
|
|
59
|
+
[LnForGasSwapState.PR_CREATED]:
|
|
60
|
+
"Swap was created, pay the provided Lightning invoice. The invoice will remain held until destination payout succeeds",
|
|
61
|
+
[LnForGasSwapState.PR_PAID]:
|
|
62
|
+
"The Lightning invoice was paid and is currently held. It will only settle once the user receives the destination funds",
|
|
63
|
+
[LnForGasSwapState.FINISHED]:
|
|
64
|
+
"The swap is finished after the destination payout succeeded and the held Lightning invoice was settled"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type LnForGasSwapInit = ISwapInit & {
|
|
68
|
+
pr: string;
|
|
69
|
+
outputAmount: bigint;
|
|
70
|
+
recipient: string;
|
|
71
|
+
token: string;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export function isLnForGasSwapInit(obj: any): obj is LnForGasSwapInit {
|
|
75
|
+
return typeof(obj.pr)==="string" &&
|
|
76
|
+
typeof(obj.outputAmount) === "bigint" &&
|
|
77
|
+
typeof(obj.recipient)==="string" &&
|
|
78
|
+
typeof(obj.token)==="string" &&
|
|
79
|
+
isISwapInit(obj);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Trusted swap for Bitcoin Lightning -> Smart chains, to be used for minor amounts to get gas tokens on
|
|
84
|
+
* the destination chain, which is only needed for Solana, which still uses legacy swaps
|
|
85
|
+
*
|
|
86
|
+
* @category Swaps/Trusted Gas Swaps
|
|
87
|
+
*/
|
|
88
|
+
export class LnForGasSwap<T extends ChainType = ChainType> extends ISwap<T, LnForGasSwapTypeDefinition<T>, LnForGasSwapState> implements IAddressSwap {
|
|
89
|
+
protected readonly TYPE: SwapType.TRUSTED_FROM_BTCLN = SwapType.TRUSTED_FROM_BTCLN;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @internal
|
|
93
|
+
*/
|
|
94
|
+
protected readonly swapStateDescription = LnForGasSwapStateDescription;
|
|
95
|
+
/**
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
protected readonly swapStateName = (state: number) => LnForGasSwapState[state];
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
protected readonly currentVersion: number = 2;
|
|
104
|
+
/**
|
|
105
|
+
* @internal
|
|
106
|
+
*/
|
|
107
|
+
protected readonly logger: LoggerType;
|
|
108
|
+
|
|
109
|
+
//State: PR_CREATED
|
|
110
|
+
private readonly pr: string;
|
|
111
|
+
private readonly outputAmount: bigint;
|
|
112
|
+
private readonly recipient: string;
|
|
113
|
+
private readonly token: string;
|
|
114
|
+
|
|
115
|
+
//State: FINISHED
|
|
116
|
+
/**
|
|
117
|
+
* Destination transaction ID on the smart chain side
|
|
118
|
+
* @private
|
|
119
|
+
*/
|
|
120
|
+
private scTxId?: string;
|
|
121
|
+
|
|
122
|
+
constructor(wrapper: LnForGasWrapper<T>, init: LnForGasSwapInit);
|
|
123
|
+
constructor(wrapper: LnForGasWrapper<T>, obj: any);
|
|
124
|
+
constructor(
|
|
125
|
+
wrapper: LnForGasWrapper<T>,
|
|
126
|
+
initOrObj: LnForGasSwapInit | any
|
|
127
|
+
) {
|
|
128
|
+
if(isLnForGasSwapInit(initOrObj) && initOrObj.url!=null) initOrObj.url += "/lnforgas";
|
|
129
|
+
super(wrapper, initOrObj);
|
|
130
|
+
if(isLnForGasSwapInit(initOrObj)) {
|
|
131
|
+
this.pr = initOrObj.pr;
|
|
132
|
+
this.outputAmount = initOrObj.outputAmount;
|
|
133
|
+
this.recipient = initOrObj.recipient;
|
|
134
|
+
this.token = initOrObj.token;
|
|
135
|
+
this._state = LnForGasSwapState.PR_CREATED;
|
|
136
|
+
} else {
|
|
137
|
+
this.pr = initOrObj.pr;
|
|
138
|
+
this.outputAmount = toBigInt(initOrObj.outputAmount);
|
|
139
|
+
this.recipient = initOrObj.recipient;
|
|
140
|
+
this.token = initOrObj.token;
|
|
141
|
+
this.scTxId = initOrObj.scTxId;
|
|
142
|
+
}
|
|
143
|
+
this.tryRecomputeSwapPrice();
|
|
144
|
+
if(this.pr!=null) {
|
|
145
|
+
const decoded = bolt11Decode(this.pr);
|
|
146
|
+
if(decoded.timeExpireDate!=null) this.expiry = decoded.timeExpireDate*1000;
|
|
147
|
+
}
|
|
148
|
+
this.logger = getLogger("LnForGas("+this.getId()+"): ");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @inheritDoc
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
protected upgradeVersion() {
|
|
156
|
+
if(this.version == 1) {
|
|
157
|
+
if(this._state===1) this._state = LnForGasSwapState.FINISHED;
|
|
158
|
+
this.version = 2;
|
|
159
|
+
}
|
|
160
|
+
if(this.version == null) {
|
|
161
|
+
//Noop
|
|
162
|
+
this.version = 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @inheritDoc
|
|
168
|
+
* @internal
|
|
169
|
+
*/
|
|
170
|
+
protected tryRecomputeSwapPrice() {
|
|
171
|
+
if(this.swapFeeBtc==null && this.swapFee!=null) {
|
|
172
|
+
this.swapFeeBtc = this.swapFee * this.getInput().rawAmount / this.getOutAmountWithoutFee();
|
|
173
|
+
}
|
|
174
|
+
super.tryRecomputeSwapPrice();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
//////////////////////////////
|
|
179
|
+
//// Getters & utils
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @inheritDoc
|
|
183
|
+
* @internal
|
|
184
|
+
*/
|
|
185
|
+
_getEscrowHash(): string {
|
|
186
|
+
return this.getId();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @inheritDoc
|
|
191
|
+
*/
|
|
192
|
+
getOutputAddress(): string | null {
|
|
193
|
+
return this.recipient;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @inheritDoc
|
|
198
|
+
*/
|
|
199
|
+
getInputAddress(): string | null {
|
|
200
|
+
return this.pr;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @inheritDoc
|
|
205
|
+
*/
|
|
206
|
+
getInputTxId(): string | null {
|
|
207
|
+
return this.getId();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @inheritDoc
|
|
212
|
+
*/
|
|
213
|
+
getOutputTxId(): string | null {
|
|
214
|
+
return this.scTxId ?? null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @inheritDoc
|
|
219
|
+
*/
|
|
220
|
+
getId(): string {
|
|
221
|
+
if(this.pr==null) throw new Error("No payment request assigned to this swap!");
|
|
222
|
+
const decodedPR = bolt11Decode(this.pr);
|
|
223
|
+
if(decodedPR.tagsObject.payment_hash==null) throw new Error("Lightning invoice has no payment hash!");
|
|
224
|
+
return decodedPR.tagsObject.payment_hash;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap
|
|
229
|
+
*/
|
|
230
|
+
getAddress(): string {
|
|
231
|
+
return this.pr;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Returns a string that can be displayed as QR code representation of the lightning invoice (with lightning: prefix)
|
|
236
|
+
*/
|
|
237
|
+
getHyperlink(): string {
|
|
238
|
+
return "lightning:"+this.pr.toUpperCase();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @inheritDoc
|
|
243
|
+
*/
|
|
244
|
+
requiresAction(): boolean {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @inheritDoc
|
|
250
|
+
*/
|
|
251
|
+
isFinished(): boolean {
|
|
252
|
+
return this._state===LnForGasSwapState.FINISHED || this._state===LnForGasSwapState.FAILED || this._state===LnForGasSwapState.EXPIRED;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @inheritDoc
|
|
257
|
+
*/
|
|
258
|
+
isQuoteExpired(): boolean {
|
|
259
|
+
return this._state===LnForGasSwapState.EXPIRED;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* @inheritDoc
|
|
264
|
+
*/
|
|
265
|
+
isQuoteSoftExpired(): boolean {
|
|
266
|
+
return this.expiry<Date.now();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @inheritDoc
|
|
271
|
+
*/
|
|
272
|
+
isFailed(): boolean {
|
|
273
|
+
return this._state===LnForGasSwapState.FAILED;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @inheritDoc
|
|
278
|
+
*/
|
|
279
|
+
isSuccessful(): boolean {
|
|
280
|
+
return this._state===LnForGasSwapState.FINISHED;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @inheritDoc
|
|
285
|
+
*/
|
|
286
|
+
isInProgress(): boolean {
|
|
287
|
+
return (this._state===LnForGasSwapState.PR_CREATED && this.initiated) || this._state===LnForGasSwapState.PR_PAID;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @inheritDoc
|
|
292
|
+
* @internal
|
|
293
|
+
*/
|
|
294
|
+
_verifyQuoteDefinitelyExpired(): Promise<boolean> {
|
|
295
|
+
return Promise.resolve(this.expiry<Date.now());
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @inheritDoc
|
|
300
|
+
* @internal
|
|
301
|
+
*/
|
|
302
|
+
_verifyQuoteValid(): Promise<boolean> {
|
|
303
|
+
return Promise.resolve(this.expiry>Date.now());
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
//////////////////////////////
|
|
307
|
+
//// Amounts & fees
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Returns an output amount in base units without a swap fee included, hence this value
|
|
311
|
+
* is larger than the actual output amount
|
|
312
|
+
*
|
|
313
|
+
* @internal
|
|
314
|
+
*/
|
|
315
|
+
protected getOutAmountWithoutFee(): bigint {
|
|
316
|
+
return this.outputAmount + (this.swapFee ?? 0n);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @inheritDoc
|
|
321
|
+
*/
|
|
322
|
+
getOutputToken(): SCToken<T["ChainId"]> {
|
|
323
|
+
return this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()];
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* @inheritDoc
|
|
328
|
+
*/
|
|
329
|
+
getOutput(): TokenAmount<SCToken<T["ChainId"]>, true> {
|
|
330
|
+
return toTokenAmount(
|
|
331
|
+
this.outputAmount, this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()],
|
|
332
|
+
this.wrapper._prices, this.pricingInfo
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @inheritDoc
|
|
338
|
+
*/
|
|
339
|
+
getInputToken(): BtcToken<true> {
|
|
340
|
+
return BitcoinTokens.BTCLN;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* @inheritDoc
|
|
345
|
+
*/
|
|
346
|
+
getInput(): TokenAmount<BtcToken<true>, true> {
|
|
347
|
+
const parsed = bolt11Decode(this.pr);
|
|
348
|
+
const msats = parsed.millisatoshis;
|
|
349
|
+
if(msats==null) throw new Error("Swap lightning invoice has no msat amount field!");
|
|
350
|
+
const amount = (BigInt(msats) + 999n) / 1000n;
|
|
351
|
+
return toTokenAmount(amount, BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* @inheritDoc
|
|
356
|
+
*/
|
|
357
|
+
getInputWithoutFee(): TokenAmount<BtcToken<true>, true> {
|
|
358
|
+
const parsed = bolt11Decode(this.pr);
|
|
359
|
+
const msats = parsed.millisatoshis;
|
|
360
|
+
if(msats==null) throw new Error("Swap lightning invoice has no msat amount field!");
|
|
361
|
+
const amount = (BigInt(msats) + 999n) / 1000n;
|
|
362
|
+
return toTokenAmount(
|
|
363
|
+
amount - (this.swapFeeBtc ?? 0n), BitcoinTokens.BTCLN,
|
|
364
|
+
this.wrapper._prices, this.pricingInfo
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Returns the swap fee charged by the intermediary (LP) on this swap
|
|
370
|
+
*
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
protected getSwapFee(): Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>> {
|
|
374
|
+
if(this.pricingInfo==null) throw new Error("No pricing info known, cannot estimate swap fee!");
|
|
375
|
+
const feeWithoutBaseFee = this.swapFeeBtc==null ? 0n : this.swapFeeBtc - this.pricingInfo.satsBaseFee;
|
|
376
|
+
const swapFeePPM = feeWithoutBaseFee * 1000000n / this.getInputWithoutFee().rawAmount;
|
|
377
|
+
|
|
378
|
+
const amountInSrcToken = toTokenAmount(this.swapFeeBtc ?? 0n, BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
|
|
379
|
+
return {
|
|
380
|
+
amountInSrcToken,
|
|
381
|
+
amountInDstToken: toTokenAmount(this.swapFee ?? 0n, this.wrapper._tokens[this.wrapper._chain.getNativeCurrencyAddress()], this.wrapper._prices, this.pricingInfo),
|
|
382
|
+
currentUsdValue: amountInSrcToken.currentUsdValue,
|
|
383
|
+
usdValue: amountInSrcToken.usdValue,
|
|
384
|
+
pastUsdValue: amountInSrcToken.pastUsdValue,
|
|
385
|
+
composition: {
|
|
386
|
+
base: toTokenAmount(this.pricingInfo.satsBaseFee, BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo),
|
|
387
|
+
percentage: ppmToPercentage(swapFeePPM)
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @inheritDoc
|
|
394
|
+
*/
|
|
395
|
+
getFee(): Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>> {
|
|
396
|
+
return this.getSwapFee();
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @inheritDoc
|
|
401
|
+
*/
|
|
402
|
+
getFeeBreakdown(): [{type: FeeType.SWAP, fee: Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>>}] {
|
|
403
|
+
return [{
|
|
404
|
+
type: FeeType.SWAP,
|
|
405
|
+
fee: this.getSwapFee()
|
|
406
|
+
}];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
//////////////////////////////
|
|
411
|
+
//// Payment
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* @remarks Not supported
|
|
415
|
+
*/
|
|
416
|
+
async execute(): Promise<boolean> {
|
|
417
|
+
throw new Error("Not supported");
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* @internal
|
|
422
|
+
*/
|
|
423
|
+
protected async _getExecutionStatus() {
|
|
424
|
+
const state = this._state;
|
|
425
|
+
|
|
426
|
+
let lightningPaymentStatus: SwapExecutionStepPayment<"LIGHTNING">["status"] = "inactive";
|
|
427
|
+
let destinationSettlementStatus: SwapExecutionStepSettlement<T["ChainId"]>["status"] = "inactive";
|
|
428
|
+
let buildCurrentAction: () => Promise<
|
|
429
|
+
SwapExecutionActionSendToAddress<true> |
|
|
430
|
+
SwapExecutionActionWait<"LP"> |
|
|
431
|
+
undefined
|
|
432
|
+
> = async () => undefined;
|
|
433
|
+
|
|
434
|
+
switch(state) {
|
|
435
|
+
case LnForGasSwapState.PR_CREATED: {
|
|
436
|
+
const quoteValid = await this._verifyQuoteValid();
|
|
437
|
+
lightningPaymentStatus = quoteValid ? "awaiting" : "soft_expired";
|
|
438
|
+
if(quoteValid) {
|
|
439
|
+
buildCurrentAction = this._buildLightningPaymentAction.bind(this);
|
|
440
|
+
}
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
case LnForGasSwapState.EXPIRED:
|
|
444
|
+
lightningPaymentStatus = "expired";
|
|
445
|
+
break;
|
|
446
|
+
case LnForGasSwapState.PR_PAID:
|
|
447
|
+
lightningPaymentStatus = "received";
|
|
448
|
+
destinationSettlementStatus = "waiting_lp";
|
|
449
|
+
buildCurrentAction = this._buildWaitLpAction.bind(this);
|
|
450
|
+
break;
|
|
451
|
+
case LnForGasSwapState.FAILED:
|
|
452
|
+
lightningPaymentStatus = "expired";
|
|
453
|
+
destinationSettlementStatus = "expired";
|
|
454
|
+
break;
|
|
455
|
+
case LnForGasSwapState.FINISHED:
|
|
456
|
+
lightningPaymentStatus = "confirmed";
|
|
457
|
+
destinationSettlementStatus = "settled";
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return {
|
|
462
|
+
steps: [
|
|
463
|
+
{
|
|
464
|
+
type: "Payment",
|
|
465
|
+
side: "source",
|
|
466
|
+
chain: "LIGHTNING",
|
|
467
|
+
title: "Lightning payment",
|
|
468
|
+
description: "Pay the Lightning network invoice to initiate the swap",
|
|
469
|
+
status: lightningPaymentStatus
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
type: "Settlement",
|
|
473
|
+
side: "destination",
|
|
474
|
+
chain: this.chainIdentifier,
|
|
475
|
+
title: "Destination payout",
|
|
476
|
+
description: "Wait for the intermediary to send the gas tokens on the destination smart chain",
|
|
477
|
+
status: destinationSettlementStatus
|
|
478
|
+
}
|
|
479
|
+
] as [
|
|
480
|
+
SwapExecutionStepPayment<"LIGHTNING">,
|
|
481
|
+
SwapExecutionStepSettlement<T["ChainId"], never>
|
|
482
|
+
],
|
|
483
|
+
buildCurrentAction,
|
|
484
|
+
state
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* @internal
|
|
490
|
+
* @inheritDoc
|
|
491
|
+
*/
|
|
492
|
+
_submitExecutionTransactions(): Promise<string[]> {
|
|
493
|
+
throw new Error("Invalid swap state for transaction submission!");
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* @internal
|
|
498
|
+
*/
|
|
499
|
+
private async _buildLightningPaymentAction(): Promise<SwapExecutionActionSendToAddress<true>> {
|
|
500
|
+
return {
|
|
501
|
+
type: "SendToAddress",
|
|
502
|
+
name: "Deposit on Lightning",
|
|
503
|
+
description: "Pay the lightning network invoice to initiate the swap",
|
|
504
|
+
chain: "LIGHTNING",
|
|
505
|
+
txs: [{
|
|
506
|
+
type: "BOLT11_PAYMENT_REQUEST",
|
|
507
|
+
address: this.pr,
|
|
508
|
+
hyperlink: this.getHyperlink(),
|
|
509
|
+
amount: this.getInput()
|
|
510
|
+
}],
|
|
511
|
+
waitForTransactions: async (
|
|
512
|
+
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal
|
|
513
|
+
) => {
|
|
514
|
+
const abortController = extendAbortController(
|
|
515
|
+
abortSignal, maxWaitTimeSeconds, "Timed out waiting for lightning payment"
|
|
516
|
+
);
|
|
517
|
+
let lightningTxId: string | undefined;
|
|
518
|
+
try {
|
|
519
|
+
const success = await this.waitForPayment(
|
|
520
|
+
pollIntervalSeconds, abortController.signal,
|
|
521
|
+
(txId: string) => {
|
|
522
|
+
lightningTxId = txId;
|
|
523
|
+
abortController.abort();
|
|
524
|
+
}
|
|
525
|
+
);
|
|
526
|
+
if(!success) throw new Error("Quote expired while waiting for lightning payment");
|
|
527
|
+
} catch (e) {
|
|
528
|
+
if(lightningTxId!=null) return lightningTxId;
|
|
529
|
+
throw e;
|
|
530
|
+
}
|
|
531
|
+
return this.getInputTxId()!;
|
|
532
|
+
}
|
|
533
|
+
} as SwapExecutionActionSendToAddress<true>;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* @internal
|
|
538
|
+
*/
|
|
539
|
+
private async _buildWaitLpAction(): Promise<SwapExecutionActionWait<"LP">> {
|
|
540
|
+
return {
|
|
541
|
+
type: "Wait",
|
|
542
|
+
name: "Awaiting LP payout",
|
|
543
|
+
description: "Wait for the intermediary to send the gas tokens on the destination smart chain",
|
|
544
|
+
pollTimeSeconds: 5,
|
|
545
|
+
expectedTimeSeconds: 10,
|
|
546
|
+
wait: async (
|
|
547
|
+
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal
|
|
548
|
+
) => {
|
|
549
|
+
const abortController = extendAbortController(
|
|
550
|
+
abortSignal, maxWaitTimeSeconds, "Timed out waiting for LP payout"
|
|
551
|
+
);
|
|
552
|
+
await this.waitForPayment(pollIntervalSeconds, abortController.signal);
|
|
553
|
+
}
|
|
554
|
+
} as SwapExecutionActionWait<"LP">;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* @inheritDoc
|
|
559
|
+
*/
|
|
560
|
+
async getExecutionAction(): Promise<
|
|
561
|
+
SwapExecutionActionSendToAddress<true> |
|
|
562
|
+
SwapExecutionActionWait<"LP"> |
|
|
563
|
+
undefined
|
|
564
|
+
> {
|
|
565
|
+
const executionStatus = await this._getExecutionStatus();
|
|
566
|
+
return executionStatus.buildCurrentAction();
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* @inheritDoc
|
|
571
|
+
*/
|
|
572
|
+
async getExecutionStatus(options?: {skipBuildingAction?: boolean}): Promise<{
|
|
573
|
+
steps: [
|
|
574
|
+
SwapExecutionStepPayment<"LIGHTNING">,
|
|
575
|
+
SwapExecutionStepSettlement<T["ChainId"], never>
|
|
576
|
+
],
|
|
577
|
+
currentAction:
|
|
578
|
+
SwapExecutionActionSendToAddress<true> |
|
|
579
|
+
SwapExecutionActionWait<"LP"> |
|
|
580
|
+
undefined,
|
|
581
|
+
stateInfo: SwapStateInfo<LnForGasSwapState>
|
|
582
|
+
}> {
|
|
583
|
+
const executionStatus = await this._getExecutionStatus();
|
|
584
|
+
return {
|
|
585
|
+
steps: executionStatus.steps,
|
|
586
|
+
currentAction: options?.skipBuildingAction ? undefined : await executionStatus.buildCurrentAction(),
|
|
587
|
+
stateInfo: this._getStateInfo(executionStatus.state)
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* @inheritDoc
|
|
593
|
+
*/
|
|
594
|
+
async getExecutionSteps(): Promise<[
|
|
595
|
+
SwapExecutionStepPayment<"LIGHTNING">,
|
|
596
|
+
SwapExecutionStepSettlement<T["ChainId"], never>
|
|
597
|
+
]> {
|
|
598
|
+
return (await this._getExecutionStatus()).steps;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Queries the intermediary (LP) node for the state of the swap
|
|
603
|
+
*
|
|
604
|
+
* @param save Whether the save the result or not
|
|
605
|
+
*
|
|
606
|
+
* @returns Whether the swap was successful as `boolean` or `null` if the swap is still pending
|
|
607
|
+
* @internal
|
|
608
|
+
*/
|
|
609
|
+
protected async checkInvoicePaid(save: boolean = true): Promise<boolean | null> {
|
|
610
|
+
if(this._state===LnForGasSwapState.FAILED || this._state===LnForGasSwapState.EXPIRED) return false;
|
|
611
|
+
if(this._state===LnForGasSwapState.FINISHED) return true;
|
|
612
|
+
if(this.url==null) return false;
|
|
613
|
+
|
|
614
|
+
const decodedPR = bolt11Decode(this.pr);
|
|
615
|
+
const paymentHash = decodedPR.tagsObject.payment_hash;
|
|
616
|
+
if(paymentHash==null) throw new Error("Invalid swap invoice, payment hash not found!");
|
|
617
|
+
|
|
618
|
+
const response = await this.wrapper._lpApi.getTrustedInvoiceStatus(
|
|
619
|
+
this.url, paymentHash, this.wrapper._options.getRequestTimeout
|
|
620
|
+
);
|
|
621
|
+
this.logger.debug("checkInvoicePaid(): LP response: ", response);
|
|
622
|
+
switch(response.code) {
|
|
623
|
+
case TrustedInvoiceStatusResponseCodes.PAID:
|
|
624
|
+
this.scTxId = response.data.txId;
|
|
625
|
+
const txStatus = await this.wrapper._chain.getTxIdStatus(this.scTxId);
|
|
626
|
+
if(txStatus==="success") {
|
|
627
|
+
this._state = LnForGasSwapState.FINISHED;
|
|
628
|
+
if(save) await this._saveAndEmit();
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
return null;
|
|
632
|
+
case TrustedInvoiceStatusResponseCodes.EXPIRED:
|
|
633
|
+
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
634
|
+
this._state = LnForGasSwapState.EXPIRED;
|
|
635
|
+
} else {
|
|
636
|
+
this._state = LnForGasSwapState.FAILED;
|
|
637
|
+
}
|
|
638
|
+
if(save) await this._saveAndEmit();
|
|
639
|
+
return false;
|
|
640
|
+
case TrustedInvoiceStatusResponseCodes.TX_SENT:
|
|
641
|
+
this.scTxId = response.data.txId;
|
|
642
|
+
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
643
|
+
this._state = LnForGasSwapState.PR_PAID;
|
|
644
|
+
if(save) await this._saveAndEmit();
|
|
645
|
+
}
|
|
646
|
+
return null;
|
|
647
|
+
case TrustedInvoiceStatusResponseCodes.PENDING:
|
|
648
|
+
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
649
|
+
this._state = LnForGasSwapState.PR_PAID;
|
|
650
|
+
if(save) await this._saveAndEmit();
|
|
651
|
+
}
|
|
652
|
+
return null;
|
|
653
|
+
case TrustedInvoiceStatusResponseCodes.AWAIT_PAYMENT:
|
|
654
|
+
return null;
|
|
655
|
+
default:
|
|
656
|
+
this._state = LnForGasSwapState.FAILED;
|
|
657
|
+
if(save) await this._saveAndEmit();
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* A blocking promise resolving when payment was received by the intermediary and client can continue,
|
|
664
|
+
* rejecting in case of failure. The swap must be in {@link LnForGasSwapState.PR_CREATED} or
|
|
665
|
+
* {@link LnForGasSwapState.PR_PAID} state!
|
|
666
|
+
*
|
|
667
|
+
* @param checkIntervalSeconds How often to poll the intermediary for answer (default 5 seconds)
|
|
668
|
+
* @param abortSignal Abort signal
|
|
669
|
+
* @param onPaymentReceived Callback as for when the LP reports having received the ln payment
|
|
670
|
+
* @throws {Error} When in invalid state (not PR_CREATED)
|
|
671
|
+
*/
|
|
672
|
+
async waitForPayment(checkIntervalSeconds?: number, abortSignal?: AbortSignal, onPaymentReceived?: (txId: string) => void): Promise<boolean> {
|
|
673
|
+
if(this._state!==LnForGasSwapState.PR_CREATED && this._state!==LnForGasSwapState.PR_PAID)
|
|
674
|
+
throw new Error("Must be in PR_CREATED or PR_PAID state!");
|
|
675
|
+
|
|
676
|
+
if(!this.initiated) {
|
|
677
|
+
this.initiated = true;
|
|
678
|
+
await this._saveAndEmit();
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
while(!abortSignal?.aborted && (this._state===LnForGasSwapState.PR_CREATED || this._state===LnForGasSwapState.PR_PAID)) {
|
|
682
|
+
await this.checkInvoicePaid(true);
|
|
683
|
+
if((this._state as LnForGasSwapState)===LnForGasSwapState.PR_PAID) {
|
|
684
|
+
if(onPaymentReceived!=null) {
|
|
685
|
+
onPaymentReceived(this.getInputTxId()!);
|
|
686
|
+
onPaymentReceived = undefined; // Set to null so it only triggers once
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
if(this._state===LnForGasSwapState.PR_CREATED || this._state===LnForGasSwapState.PR_PAID) await timeoutPromise((checkIntervalSeconds ?? 5)*1000, abortSignal);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if(abortSignal!=null) abortSignal.throwIfAborted();
|
|
693
|
+
|
|
694
|
+
if(this.isFailed()) throw new Error("Swap failed");
|
|
695
|
+
return !this.isQuoteExpired();
|
|
696
|
+
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
//////////////////////////////
|
|
701
|
+
//// Storage
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* @inheritDoc
|
|
705
|
+
*/
|
|
706
|
+
serialize(): any{
|
|
707
|
+
return {
|
|
708
|
+
...super.serialize(),
|
|
709
|
+
pr: this.pr,
|
|
710
|
+
outputAmount: this.outputAmount==null ? null : this.outputAmount.toString(10),
|
|
711
|
+
recipient: this.recipient,
|
|
712
|
+
token: this.token,
|
|
713
|
+
scTxId: this.scTxId
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* @inheritDoc
|
|
719
|
+
* @internal
|
|
720
|
+
*/
|
|
721
|
+
_getInitiator(): string {
|
|
722
|
+
return this.recipient;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
//////////////////////////////
|
|
727
|
+
//// Swap ticks & sync
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* @inheritDoc
|
|
731
|
+
* @internal
|
|
732
|
+
*/
|
|
733
|
+
async _sync(save?: boolean): Promise<boolean> {
|
|
734
|
+
if(this._state===LnForGasSwapState.PR_CREATED) {
|
|
735
|
+
//Check if it's maybe already paid
|
|
736
|
+
const res = await this.checkInvoicePaid(false);
|
|
737
|
+
if(res!==null) {
|
|
738
|
+
if(save) await this._saveAndEmit();
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* @inheritDoc
|
|
747
|
+
* @internal
|
|
748
|
+
*/
|
|
749
|
+
_tick(save?: boolean): Promise<boolean> {
|
|
750
|
+
return Promise.resolve(false);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
}
|