diff --git a/src/app/components/speedUpTransaction/btc.tsx b/src/app/components/speedUpTransaction/btc.tsx index 5ae91c0a9..1504438dd 100644 --- a/src/app/components/speedUpTransaction/btc.tsx +++ b/src/app/components/speedUpTransaction/btc.tsx @@ -54,6 +54,7 @@ interface Props { handleClickFeeButton: (e: React.MouseEvent) => void; handleClickSubmit: () => void; getEstimatedCompletionTime: (feeRate?: number) => string; + isBroadcasting: boolean; } function SpeedUpBtcTransaction({ @@ -67,6 +68,7 @@ function SpeedUpBtcTransaction({ handleClickFeeButton, handleClickSubmit, getEstimatedCompletionTime, + isBroadcasting, }: Props) { const { t } = useTranslation('translation', { keyPrefix: 'SPEED_UP_TRANSACTION' }); const { btcFiatRate, fiatCurrency } = useWalletSelector(); @@ -215,6 +217,7 @@ function SpeedUpBtcTransaction({ diff --git a/src/app/components/speedUpTransaction/stx.tsx b/src/app/components/speedUpTransaction/stx.tsx index 7994127fe..7c7b62ceb 100644 --- a/src/app/components/speedUpTransaction/stx.tsx +++ b/src/app/components/speedUpTransaction/stx.tsx @@ -54,6 +54,7 @@ interface Props { handleClickFeeButton: (e: React.MouseEvent) => void; handleClickSubmit: () => void; getEstimatedCompletionTime: (feeRate?: number) => string; + isBroadcasting: boolean; } function SpeedUpStxTransaction({ @@ -67,6 +68,7 @@ function SpeedUpStxTransaction({ handleClickFeeButton, handleClickSubmit, getEstimatedCompletionTime, + isBroadcasting, }: Props) { const { t } = useTranslation('translation', { keyPrefix: 'SPEED_UP_TRANSACTION' }); const { btcFiatRate, stxBtcRate, fiatCurrency } = useWalletSelector(); @@ -194,6 +196,7 @@ function SpeedUpStxTransaction({ text={t('SUBMIT')} disabled={!selectedOption} onPress={handleClickSubmit} + processing={isBroadcasting} /> diff --git a/src/app/hooks/useRbfTransactionData.ts b/src/app/hooks/useRbfTransactionData.ts index df3c1688b..01d95782b 100644 --- a/src/app/hooks/useRbfTransactionData.ts +++ b/src/app/hooks/useRbfTransactionData.ts @@ -13,6 +13,9 @@ import { isLedgerAccount } from '@utils/helper'; import axios from 'axios'; import BigNumber from 'bignumber.js'; import { useCallback, useEffect, useState } from 'react'; +import toast from 'react-hot-toast'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; import useBtcClient from './useBtcClient'; import useNetworkSelector from './useNetwork'; import useSeedVault from './useSeedVault'; @@ -83,25 +86,9 @@ const constructRecommendedFees = ( higherName: keyof RbfRecommendedFees, higherFeeRate: number, stxAvailableBalance: string, - thresholdHighStacksFee?: number, ): RbfRecommendedFees => { - let lowerFee = lowerFeeRate; - let higherFee = higherFeeRate; - - if (thresholdHighStacksFee) { - // adding a fee cap - - if (higherFee > thresholdHighStacksFee) { - higherFee = thresholdHighStacksFee; - } - - if (lowerFee > thresholdHighStacksFee) { - lowerFee = thresholdHighStacksFee * 0.75; - } - } - - const bigNumLowerFee = BigNumber(lowerFee); - const bigNumHigherFee = BigNumber(higherFee); + const bigNumLowerFee = BigNumber(lowerFeeRate); + const bigNumHigherFee = BigNumber(higherFeeRate); return { [lowerName]: { @@ -133,6 +120,8 @@ const useRbfTransactionData = (transaction?: BtcTransactionData | StxTransaction const seedVault = useSeedVault(); const btcClient = useBtcClient(); const selectedNetwork = useNetworkSelector(); + const { t } = useTranslation('translation', { keyPrefix: 'SPEED_UP_TRANSACTION' }); + const navigate = useNavigate(); // TODO: move the STX RBF calculations to xverse-core and add unit tests const fetchStxData = useCallback(async () => { @@ -153,18 +142,26 @@ const useRbfTransactionData = (transaction?: BtcTransactionData | StxTransaction selectedNetwork, ); + let feePresets: RbfRecommendedFees = {}; + let mediumFee = medium.fee; + let highFee = high.fee; + const higherFee = fee.multipliedBy(1.25).toNumber(); + const highestFee = fee.multipliedBy(1.5).toNumber(); + + if (feeMultipliers?.thresholdHighStacksFee) { + if (high.fee > feeMultipliers.thresholdHighStacksFee) { + // adding a fee cap + highFee = feeMultipliers.thresholdHighStacksFee * 1.5; + mediumFee = feeMultipliers.thresholdHighStacksFee; + } + } + let minimumFee = fee.multipliedBy(1.25).toNumber(); if (!Number.isSafeInteger(minimumFee)) { // round up the fee to the nearest integer minimumFee = Math.ceil(minimumFee); } - let feePresets: RbfRecommendedFees = {}; - const mediumFee = medium.fee; - const highFee = high.fee; - let higherFee = highFee * 1.25; - const highestFee = fee.multipliedBy(1.5).toNumber(); - if (fee.lt(BigNumber(mediumFee))) { feePresets = constructRecommendedFees( 'medium', @@ -172,27 +169,14 @@ const useRbfTransactionData = (transaction?: BtcTransactionData | StxTransaction 'high', highFee, stxAvailableBalance, - feeMultipliers?.thresholdHighStacksFee, - ); - } else if (fee.gt(BigNumber(mediumFee)) && fee.lt(BigNumber(highFee))) { - feePresets = constructRecommendedFees( - 'high', - highFee, - 'higher', - higherFee, - stxAvailableBalance, - feeMultipliers?.thresholdHighStacksFee, ); } else { - higherFee = fee.multipliedBy(1.25).toNumber(); - feePresets = constructRecommendedFees( 'higher', higherFee, 'highest', highestFee, stxAvailableBalance, - feeMultipliers?.thresholdHighStacksFee, ); } @@ -214,11 +198,13 @@ const useRbfTransactionData = (transaction?: BtcTransactionData | StxTransaction }, }); } catch (err: any) { + toast.error(t('SOMETHING_WENT_WRONG')); + navigate(-1); console.error(err); } finally { setIsLoading(false); } - }, [transaction, network, selectedNetwork, feeMultipliers, stxAvailableBalance]); + }, [transaction, network, selectedNetwork, feeMultipliers, stxAvailableBalance, t, navigate]); const fetchRbfData = useCallback(async () => { if (!selectedAccount || !transaction) { @@ -257,11 +243,23 @@ const useRbfTransactionData = (transaction?: BtcTransactionData | StxTransaction mempoolFees, }); } catch (err: any) { + toast.error(t('SOMETHING_WENT_WRONG')); + navigate(-1); console.error(err); } finally { setIsLoading(false); } - }, [selectedAccount, transaction, accountType, network.type, seedVault, btcClient, fetchStxData]); + }, [ + selectedAccount, + transaction, + accountType, + network.type, + seedVault, + btcClient, + fetchStxData, + t, + navigate, + ]); useEffect(() => { fetchRbfData(); diff --git a/src/app/screens/speedUpTransaction/index.tsx b/src/app/screens/speedUpTransaction/index.tsx index ae567f408..a618754fb 100644 --- a/src/app/screens/speedUpTransaction/index.tsx +++ b/src/app/screens/speedUpTransaction/index.tsx @@ -71,6 +71,7 @@ function SpeedUpTransactionScreen() { const { getSeed } = useSeedVault(); const selectedStacksNetwork = useNetworkSelector(); const isBtc = isBtcTransaction(stxTransaction || btcTransaction); + const [isBroadcasting, setIsBroadcasting] = useState(false); const handleClickFeeButton = (e: React.MouseEvent) => { if (e.currentTarget.value === 'custom') { @@ -144,6 +145,7 @@ function SpeedUpTransactionScreen() { } try { + setIsBroadcasting(true); const fee = stxToMicrostacks(BigNumber(feeRateInput)).toString(); const txRaw: string = await getRawTransaction(stxTransaction.txid, network); const unsignedTx: StacksTransaction = deserializeTransaction(txRaw); @@ -187,6 +189,8 @@ function SpeedUpTransactionScreen() { return; } catch (err: any) { console.error(err); + } finally { + setIsBroadcasting(false); } }; @@ -204,6 +208,7 @@ function SpeedUpTransactionScreen() { } try { + setIsBroadcasting(true); const signedTx = await rbfTransaction.getReplacementTransaction({ feeRate: Number(feeRateInput), ledgerTransport: transport, @@ -221,6 +226,8 @@ function SpeedUpTransactionScreen() { toast.error(t('INSUFFICIENT_FEE')); } } + } finally { + setIsBroadcasting(false); } }; @@ -367,6 +374,7 @@ function SpeedUpTransactionScreen() { handleClickFeeButton={handleClickFeeButton} handleClickSubmit={handleClickSubmit} getEstimatedCompletionTime={getEstimatedCompletionTime} + isBroadcasting={isBroadcasting} /> ) : ( )} diff --git a/src/locales/en.json b/src/locales/en.json index dde66a67e..e5bfdf656 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -830,6 +830,7 @@ "MANUAL_SETTING": "Manual setting", "TX_FEE_UPDATED": "Transaction fee updated", "FEE_TOO_LOW": "The minimum fee is {{minimumFee}}", + "SOMETHING_WENT_WRONG": "Something went wrong", "TIME": { "SEVERAL_HOURS_OR_MORE": "several hours or more", "HOUR": "hour",