diff --git a/ui/hooks/bridge/useLatestBalance.tsx b/ui/hooks/bridge/useLatestBalance.tsx new file mode 100644 index 000000000000..ead4a3405f6d --- /dev/null +++ b/ui/hooks/bridge/useLatestBalance.tsx @@ -0,0 +1,59 @@ +import { useSelector } from 'react-redux'; +import { zeroAddress } from 'ethereumjs-util'; +import { Web3Provider } from '@ethersproject/providers'; +import { Hex } from '@metamask/utils'; +import { Numeric } from '../../../shared/modules/Numeric'; +import { DEFAULT_PRECISION } from '../useCurrencyDisplay'; +import { fetchTokenBalance } from '../../../shared/lib/token-util'; +import { + getCurrentChainId, + getSelectedInternalAccount, + SwapsEthToken, +} from '../../selectors'; +import { SwapsTokenObject } from '../../../shared/constants/swaps'; +import { useAsyncResult } from '../useAsyncResult'; + +/** + * Custom hook to fetch and format the latest balance of a given token or native asset. + * + * @param token - The token object for which the balance is to be fetched. Can be null. + * @param chainId - The chain ID to be used for fetching the balance. Optional. + * @returns An object containing the formatted balance as a string. + */ +const useLatestBalance = ( + token: SwapsTokenObject | SwapsEthToken | null, + chainId?: Hex, +) => { + const { address: selectedAddress } = useSelector(getSelectedInternalAccount); + const currentChainId = useSelector(getCurrentChainId); + + const { value: latestBalance } = useAsyncResult(async () => { + if (token && chainId && currentChainId === chainId) { + if (!token.address || token.address === zeroAddress()) { + const ethersProvider = new Web3Provider(global.ethereumProvider); + return (await ethersProvider.getBalance(selectedAddress)).toString(); + } + return ( + await fetchTokenBalance( + token.address, + selectedAddress, + global.ethereumProvider, + ) + ).toString(); + } + // TODO implement fetching balance on non-active chain + return; + }, [token, selectedAddress, global.ethereumProvider]); + + return { + formattedBalance: + token && latestBalance + ? new Numeric(latestBalance, 10) + .shiftedBy(Number(token?.decimals) ?? 18) + .round(DEFAULT_PRECISION) + .toString() + : undefined, + }; +}; + +export default useLatestBalance; diff --git a/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap b/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap index 9343ecf99701..03af05d50d09 100644 --- a/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap +++ b/ui/pages/bridge/prepare/__snapshots__/prepare-bridge-page.test.tsx.snap @@ -99,9 +99,7 @@ exports[`PrepareBridgePage should render the component 1`] = `

- Balance - : - "0" +

- Balance - : - "0" +

@@ -132,7 +136,7 @@ export const BridgeInputGroup = ({ - {t('balance')}: {JSON.stringify(latestBalance)} + {formattedBalance ? `${t('balance')}: ${formattedBalance}` : ' '} { + beforeAll(() => { + const { provider } = createTestProviderTools({ + networkId: 'Ethereum', + chainId: CHAIN_IDS.MAINNET, + }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + global.ethereumProvider = provider as any; + }); + it('should render the component', () => { const mockStore = createBridgeMockStore( {