diff --git a/packages/web/components/bridge/amount-screen.tsx b/packages/web/components/bridge/amount-screen.tsx index 6ca8ec9e86..06456c7681 100644 --- a/packages/web/components/bridge/amount-screen.tsx +++ b/packages/web/components/bridge/amount-screen.tsx @@ -688,6 +688,11 @@ export const AmountScreen = observer( isInsufficientBal={Boolean(isInsufficientBal)} isInsufficientFee={Boolean(isInsufficientFee)} transferGasCost={selectedQuote?.gasCost} + /** Wait for all quotes to resolve before modifying input amount. + * This helps reduce thrash while the best quote is being determined. + * Only once we get the best quote, we can modify the input amount + * to account for gas then restart the quote search process. */ + canSetMax={!quote.isLoadingAnyBridgeQuote} setFiatAmount={setFiatAmount} setCryptoAmount={setCryptoAmount} setInputUnit={setInputUnit} diff --git a/packages/web/components/bridge/crypto-fiat-input.tsx b/packages/web/components/bridge/crypto-fiat-input.tsx index b4084684ce..f6373a7452 100644 --- a/packages/web/components/bridge/crypto-fiat-input.tsx +++ b/packages/web/components/bridge/crypto-fiat-input.tsx @@ -37,6 +37,7 @@ export const CryptoFiatInput: FunctionComponent<{ isInsufficientFee: boolean; fromChain: BridgeChainWithDisplayInfo; transferGasCost: CoinPretty | undefined; + canSetMax?: boolean; setFiatAmount: (amount: string) => void; setCryptoAmount: (amount: string) => void; setInputUnit: (unit: "fiat" | "crypto") => void; @@ -50,6 +51,7 @@ export const CryptoFiatInput: FunctionComponent<{ isInsufficientBal, isInsufficientFee, transferGasCost, + canSetMax = true, setFiatAmount: setFiatAmountProp, setCryptoAmount: setCryptoAmountProp, setInputUnit, @@ -152,7 +154,7 @@ export const CryptoFiatInput: FunctionComponent<{ // Subtract gas cost and adjust input when selecting max amount useEffect(() => { - if (isMax && transferGasCost) { + if (isMax && transferGasCost && canSetMax) { let maxTransferAmount = new Dec(0); const gasFeeMatchesInputDenom = @@ -175,14 +177,14 @@ export const CryptoFiatInput: FunctionComponent<{ onInput("crypto")(trimPlaceholderZeros(maxTransferAmount.toString())); } } - }, [isMax, transferGasCost, asset.amount, inputCoin, onInput]); + }, [isMax, canSetMax, transferGasCost, asset.amount, inputCoin, onInput]); // Apply max amount if asset changes useEffect(() => { - if (isMax) { + if (isMax && canSetMax) { onInput("crypto")(trimPlaceholderZeros(asset.amount.toDec().toString())); } - }, [asset, isMax, onInput]); + }, [asset, isMax, canSetMax, onInput]); const fiatCurrentValue = `${assetPrice.symbol}${fiatInputRaw}`; const fiatInputFontSize = calcTextSizeClass( diff --git a/packages/web/components/bridge/use-bridge-quotes.ts b/packages/web/components/bridge/use-bridge-quotes.ts index 460dfd053a..f1d28b3054 100644 --- a/packages/web/components/bridge/use-bridge-quotes.ts +++ b/packages/web/components/bridge/use-bridge-quotes.ts @@ -287,8 +287,8 @@ export const useBridgeQuotes = ({ const numSucceeded = successfulQuotes.length; const isOneSuccessful = Boolean(numSucceeded); - const amountOfErrors = erroredQuotes.length; - const isOneErrored = Boolean(amountOfErrors); + const isAllSuccessful = numSucceeded === bridges.length; + const isOneErrored = Boolean(erroredQuotes.length); // if none have returned a resulting quote, find some error const someError = useMemo( @@ -653,17 +653,25 @@ export const useBridgeQuotes = ({ (!isOneSuccessful || quoteResults.every((quoteResult) => quoteResult.isLoading)) && quoteResults.some((quoteResult) => quoteResult.fetchStatus !== "idle"); + const isLoadingAnyBridgeQuote = quoteResults.some( + (quoteResult) => quoteResult.isLoading && quoteResult.fetchStatus !== "idle" + ); const isLoadingBridgeTransaction = bridgeTransaction.isLoading && bridgeTransaction.fetchStatus !== "idle"; - const isWithdrawReady = isWithdraw && !isTxPending; - const isWalletConnected = + const isWithdrawReady = + isWithdraw && !isTxPending && !isLoadingBridgeTransaction; + const isFromWalletConnected = fromChain?.chainType === "evm" ? isEvmWalletConnected : fromChain?.chainType === "cosmos" ? accountStore.getWallet(fromChain.chainId)?.isWalletConnected ?? false : false; const isDepositReady = - isDeposit && isWalletConnected && !isLoadingBridgeQuote && !isTxPending; + isDeposit && + isFromWalletConnected && + !isLoadingBridgeQuote && + !isTxPending && + !isLoadingBridgeTransaction; const userCanAdvance = (isDepositReady || isWithdrawReady) && !isInsufficientFee && @@ -711,6 +719,7 @@ export const useBridgeQuotes = ({ warnUserOfPriceImpact, successfulQuotes, + isAllQuotesSuccessful: isAllSuccessful, selectedBridgeProvider, setSelectedBridgeProvider: onChangeBridgeProvider, @@ -718,6 +727,7 @@ export const useBridgeQuotes = ({ selectedQuoteUpdatedAt: selectedQuoteQuery?.dataUpdatedAt, refetchInterval, isLoadingBridgeQuote, + isLoadingAnyBridgeQuote, isLoadingBridgeTransaction, isRefetchingQuote: selectedQuoteQuery?.isRefetching ?? false, };