From 3e8ff5fc6c1dd28193fa72020d9a6ac004fa897c Mon Sep 17 00:00:00 2001 From: woodenfurniture <125113430+woodenfurniture@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:37:13 +1100 Subject: [PATCH 1/2] fix: add a loading state to the asset dropdown --- .../components/AssetChainDropdown.tsx | 3 ++- .../components/AssetSelection.tsx | 11 +++++++++-- .../components/TradeInput/TradeInput.tsx | 6 ++++-- .../Pool/components/Borrow/BorrowInput.tsx | 14 +++++++++++--- .../Pool/components/Repay/RepayInput.tsx | 19 ++++++++++++++++--- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/components/MultiHopTrade/components/AssetChainDropdown.tsx b/src/components/MultiHopTrade/components/AssetChainDropdown.tsx index a00ce9238dd..d1d3ae96463 100644 --- a/src/components/MultiHopTrade/components/AssetChainDropdown.tsx +++ b/src/components/MultiHopTrade/components/AssetChainDropdown.tsx @@ -94,7 +94,8 @@ export const AssetChainDropdown: React.FC = ({ borderRadius='full' color='text.base' isDisabled - variant='ghost' + isLoading={isLoading} + variant={!isLoading ? 'ghost' : undefined} _disabled={disabled} _hover={hover} {...buttonProps} diff --git a/src/components/MultiHopTrade/components/AssetSelection.tsx b/src/components/MultiHopTrade/components/AssetSelection.tsx index c1e7304bef5..e052d0f61ed 100644 --- a/src/components/MultiHopTrade/components/AssetSelection.tsx +++ b/src/components/MultiHopTrade/components/AssetSelection.tsx @@ -31,6 +31,7 @@ const TradeAssetAwaitingAsset = () => { type TradeAssetSelectProps = { assetId?: AssetId isReadOnly?: boolean + isLoading: boolean onAssetClick?: () => void onAssetChange: (asset: Asset) => void } @@ -40,11 +41,16 @@ export const TradeAssetSelectWithAsset: React.FC = ({ onAssetChange, assetId, isReadOnly, + isLoading, }) => { const assets = useAppSelector(selectAssets) const asset = useAppSelector(state => selectAssetById(state, assetId ?? '')) - const { data, isLoading, isError } = useGetRelatedAssetIdsQuery(assetId ?? '') + const { + data, + isLoading: isRelatedAssetsLoading, + isError, + } = useGetRelatedAssetIdsQuery(assetId ?? '') const handleAssetChange = useCallback( (assetId: AssetId) => { @@ -80,6 +86,7 @@ export const TradeAssetSelectWithAsset: React.FC = ({ isDisabled={isReadOnly} _disabled={disabledStyle} rightIcon={rightIcon} + isLoading={isLoading || isRelatedAssetsLoading} > {icon} {asset?.symbol} @@ -89,7 +96,7 @@ export const TradeAssetSelectWithAsset: React.FC = ({ assetIds={data} assetId={assetId} onClick={handleAssetChange} - isLoading={isLoading} + isLoading={isLoading || isRelatedAssetsLoading} isError={isError} /> diff --git a/src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx b/src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx index 7a8c9956bd8..0c54b7ddb8b 100644 --- a/src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx +++ b/src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx @@ -557,9 +557,10 @@ export const TradeInput = memo(() => { assetId={sellAsset.assetId} onAssetClick={handleSellAssetClick} onAssetChange={setSellAsset} + isLoading={isSupportedAssetsLoading} /> ), - [handleSellAssetClick, sellAsset.assetId, setSellAsset], + [handleSellAssetClick, isSupportedAssetsLoading, sellAsset.assetId, setSellAsset], ) const buyTradeAssetSelect = useMemo( @@ -568,9 +569,10 @@ export const TradeInput = memo(() => { assetId={buyAsset.assetId} onAssetClick={handleBuyAssetClick} onAssetChange={setBuyAsset} + isLoading={isSupportedAssetsLoading} /> ), - [buyAsset.assetId, handleBuyAssetClick, setBuyAsset], + [buyAsset.assetId, handleBuyAssetClick, isSupportedAssetsLoading, setBuyAsset], ) return ( diff --git a/src/pages/Lending/Pool/components/Borrow/BorrowInput.tsx b/src/pages/Lending/Pool/components/Borrow/BorrowInput.tsx index 8ac7cd8ee33..5c0fc45f219 100644 --- a/src/pages/Lending/Pool/components/Borrow/BorrowInput.tsx +++ b/src/pages/Lending/Pool/components/Borrow/BorrowInput.tsx @@ -95,7 +95,8 @@ export const BorrowInput = ({ const translate = useTranslate() const history = useHistory() - const { data: borrowAssets } = useLendingSupportedAssets({ type: 'borrow' }) + const { data: borrowAssets, isLoading: isLendingSupportedAssetsLoading } = + useLendingSupportedAssets({ type: 'borrow' }) const collateralAsset = useAppSelector(state => selectAssetById(state, collateralAssetId)) @@ -346,9 +347,10 @@ export const BorrowInput = ({ onAssetClick={noop} onAssetChange={handleAssetChange} isReadOnly + isLoading={isLendingSupportedAssetsLoading} /> ) - }, [collateralAssetId, handleAssetChange]) + }, [collateralAssetId, handleAssetChange, isLendingSupportedAssetsLoading]) const borrowAssetSelectComponent = useMemo(() => { return ( @@ -356,9 +358,15 @@ export const BorrowInput = ({ assetId={borrowAsset?.assetId ?? ''} onAssetClick={handleBorrowAssetClick} onAssetChange={handleAssetChange} + isLoading={isLendingSupportedAssetsLoading} /> ) - }, [borrowAsset?.assetId, handleAssetChange, handleBorrowAssetClick]) + }, [ + borrowAsset?.assetId, + handleAssetChange, + handleBorrowAssetClick, + isLendingSupportedAssetsLoading, + ]) const quoteErrorTranslation = useMemo(() => { if (_isSmartContractAddress) return 'trade.errors.smartContractWalletNotSupported' diff --git a/src/pages/Lending/Pool/components/Repay/RepayInput.tsx b/src/pages/Lending/Pool/components/Repay/RepayInput.tsx index a088fc2e023..36cde195c0c 100644 --- a/src/pages/Lending/Pool/components/Repay/RepayInput.tsx +++ b/src/pages/Lending/Pool/components/Repay/RepayInput.tsx @@ -126,7 +126,8 @@ export const RepayInput = ({ const swapIcon = useMemo(() => , []) - const { data: lendingSupportedAssets } = useLendingSupportedAssets({ type: 'borrow' }) + const { data: lendingSupportedAssets, isLoading: isLendingSupportedAssetsLoading } = + useLendingSupportedAssets({ type: 'borrow' }) useEffect(() => { if (!(lendingSupportedAssets && collateralAsset)) return @@ -159,9 +160,15 @@ export const RepayInput = ({ // Users have the possibility to repay in any supported asset, not only their collateral/borrowed asset // https://docs.thorchain.org/thorchain-finance/lending#loan-repayment-closeflow isReadOnly={false} + isLoading={isLendingSupportedAssetsLoading} /> ) - }, [handleAssetChange, handleRepaymentAssetClick, repaymentAsset?.assetId]) + }, [ + handleAssetChange, + handleRepaymentAssetClick, + isLendingSupportedAssetsLoading, + repaymentAsset?.assetId, + ]) const collateralAssetSelectComponent = useMemo(() => { return ( @@ -170,9 +177,15 @@ export const RepayInput = ({ onAssetClick={handleRepaymentAssetClick} onAssetChange={handleAssetChange} isReadOnly + isLoading={isLendingSupportedAssetsLoading} /> ) - }, [collateralAssetId, handleAssetChange, handleRepaymentAssetClick]) + }, [ + collateralAssetId, + handleAssetChange, + handleRepaymentAssetClick, + isLendingSupportedAssetsLoading, + ]) const handleSeenNotice = useCallback(() => setSeenNotice(true), []) From 80902978647ed9af48c7cc51513899d2ef2a7667 Mon Sep 17 00:00:00 2001 From: woodenfurniture <125113430+woodenfurniture@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:58:41 +1100 Subject: [PATCH 2/2] fix: unable to trade on non-evm assets on multi-hop ui --- .../MultiHopTradeConfirm/hooks/useAllowance.tsx | 12 ++++++++++-- .../MultiHopTradeConfirm/hooks/useBlockNumber.tsx | 4 ++-- .../hooks/useIsApprovalNeeded.tsx | 5 +++++ .../hooks/useAllowanceApproval/helpers.ts | 6 ++---- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useAllowance.tsx b/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useAllowance.tsx index 728d69c61d2..43db67c83c2 100644 --- a/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useAllowance.tsx +++ b/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useAllowance.tsx @@ -1,4 +1,6 @@ import type { AccountId } from '@shapeshiftoss/caip' +import type { EvmChainId } from '@shapeshiftoss/chain-adapters' +import { evmChainIds } from '@shapeshiftoss/chain-adapters' import type { TradeQuoteStep } from '@shapeshiftoss/swapper' import { Err, type Result } from '@sniptt/monads' import type { QueryFunction } from '@tanstack/react-query' @@ -11,7 +13,7 @@ import { } from 'components/MultiHopTrade/hooks/useAllowanceApproval/helpers' import { useWallet } from 'hooks/useWallet/useWallet' -import { useBlockNumber } from './useBlockNumber' +import { useEvmBlockNumber } from './useBlockNumber' type QueryKeyArgs = Partial> & { blockNumber: bigint | undefined } @@ -86,7 +88,13 @@ export function useAllowance( [wallet], ) - const blockNumber = useBlockNumber(chainId, watch) + const maybeEvmChainId = useMemo(() => { + const isEvmChainId = chainId && evmChainIds.includes(chainId as EvmChainId) + if (!isEvmChainId) return + return chainId as EvmChainId + }, [chainId]) + + const blockNumber = useEvmBlockNumber(maybeEvmChainId, watch) const allowanceQuery = useQuery({ queryKey: queryKey({ diff --git a/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useBlockNumber.tsx b/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useBlockNumber.tsx index 04b6467d746..39d3e55b595 100644 --- a/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useBlockNumber.tsx +++ b/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useBlockNumber.tsx @@ -1,8 +1,8 @@ -import type { ChainId } from '@shapeshiftoss/caip' +import type { EvmChainId } from '@shapeshiftoss/chain-adapters' import { useEffect, useState } from 'react' import { assertGetViemClient } from 'lib/viem-client' -export const useBlockNumber = (chainId: ChainId | undefined, enabled: boolean) => { +export const useEvmBlockNumber = (chainId: EvmChainId | undefined, enabled: boolean) => { const [blockNumber, setBlockNumber] = useState() useEffect(() => { diff --git a/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useIsApprovalNeeded.tsx b/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useIsApprovalNeeded.tsx index cf931c799ff..e2b3cf3583d 100644 --- a/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useIsApprovalNeeded.tsx +++ b/src/components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useIsApprovalNeeded.tsx @@ -1,4 +1,5 @@ import type { AccountId } from '@shapeshiftoss/caip' +import { type EvmChainId, evmChainIds } from '@shapeshiftoss/chain-adapters' import type { TradeQuoteStep } from '@shapeshiftoss/swapper' import { useMemo } from 'react' import { useAllowance } from 'components/MultiHopTrade/components/MultiHopTradeConfirm/hooks/useAllowance' @@ -17,6 +18,10 @@ export const useIsApprovalNeeded = ( const isApprovalNeeded = useMemo(() => { if (tradeQuoteStep === undefined) return undefined + const isEvmChainId = evmChainIds.includes(tradeQuoteStep.sellAsset.chainId as EvmChainId) + + if (!isEvmChainId) return false + if (data?.isErr()) { const error = data.unwrapErr() // the error type is a GetAllowanceErr enum so we can handle all cases with exhaustiveness diff --git a/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts b/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts index a0c71a78c23..f37f1aae6b7 100644 --- a/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts +++ b/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts @@ -7,9 +7,9 @@ import { isLedger } from '@shapeshiftoss/hdwallet-ledger' import type { TradeQuote } from '@shapeshiftoss/swapper' import type { Result } from '@sniptt/monads' import { Err, Ok } from '@sniptt/monads' -import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton' import { bn } from 'lib/bignumber/bignumber' import { MAX_ALLOWANCE } from 'lib/swapper/swappers/utils/constants' +import { assertGetChainAdapter } from 'lib/utils' import { getApproveContractData, getErc20Allowance, getFees } from 'lib/utils/evm' export type GetAllowanceArgs = { @@ -35,10 +35,8 @@ export const getAllowance = async ({ wallet, accountId, }: GetAllowanceArgs): Promise> => { - const adapterManager = getChainAdapterManager() - const adapter = adapterManager.get(chainId) + const adapter = assertGetChainAdapter(chainId) - if (!adapter) throw Error(`no chain adapter found for chain Id: ${chainId}`) if (!wallet) throw new Error('no wallet available') // No approval needed for selling a non-EVM asset