From d8970b02c6a563460918e611b74509cf385af8fe Mon Sep 17 00:00:00 2001 From: saml33 Date: Mon, 30 Jan 2023 15:13:38 +1100 Subject: [PATCH] add hook for banks and balances --- components/BorrowForm.tsx | 29 +---- components/DepositForm.tsx | 21 +--- components/RepayForm.tsx | 27 +---- components/TokenList.tsx | 103 ++++++---------- components/WithdrawForm.tsx | 35 +----- components/account/ActionTokenList.tsx | 35 +++--- components/borrow/AssetsBorrowsTable.tsx | 61 +++------- components/borrow/BorrowPage.tsx | 39 ++---- components/borrow/YourBorrowsTable.tsx | 17 +-- components/modals/UserSetupModal.tsx | 37 ++---- components/shared/BalancesTable.tsx | 114 ++++++++---------- components/stats/TokenStats.tsx | 30 ++--- components/stats/TotalDepositBorrowCharts.tsx | 25 +--- hooks/useBanksWithBalances.ts | 85 +++++++++++++ 14 files changed, 266 insertions(+), 392 deletions(-) create mode 100644 hooks/useBanksWithBalances.ts diff --git a/components/BorrowForm.tsx b/components/BorrowForm.tsx index 3cc7d382..a79c8fc3 100644 --- a/components/BorrowForm.tsx +++ b/components/BorrowForm.tsx @@ -1,4 +1,4 @@ -import { Bank, HealthType } from '@blockworks-foundation/mango-v4' +import { HealthType } from '@blockworks-foundation/mango-v4' import { ArrowLeftIcon, ArrowUpLeftIcon, @@ -42,6 +42,7 @@ import { useEnhancedWallet } from './wallet/EnhancedWalletProvider' import FormatNumericValue from './shared/FormatNumericValue' import { floorToDecimal } from 'utils/numbers' import BankAmountWithValue from './shared/BankAmountWithValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' interface BorrowFormProps { onSuccess: () => void @@ -62,6 +63,7 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) { const { mangoAccount } = useMangoAccount() const { connected, publicKey } = useWallet() const { handleConnect } = useEnhancedWallet() + const banks = useBanksWithBalances('maxBorrow') const bank = useMemo(() => { const group = mangoStore.getState().group @@ -154,28 +156,6 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) { } }, [bank, inputAmount, onSuccess, publicKey]) - const banks = useMemo(() => { - if (mangoAccount) { - return group?.banksMapByName - ? Array.from(group?.banksMapByName, ([key, value]) => { - const bank: Bank = value[0] - const maxAmount = getMaxWithdrawForBank( - group, - bank, - mangoAccount, - true - ).toNumber() - return { - key, - value, - maxAmount, - } - }) - : [] - } - return [] - }, [mangoAccount, group]) - const handleInputChange = (e: NumberFormatValues, info: SourceInfo) => { if (info.source === 'event') { setSizePercentage('') @@ -221,8 +201,7 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) { banks={banks} onSelect={handleSelectToken} showBorrowRates - sortByKey="maxAmount" - valueKey="maxAmount" + valueKey="maxBorrow" /> diff --git a/components/DepositForm.tsx b/components/DepositForm.tsx index acc2a20a..6879b5b1 100644 --- a/components/DepositForm.tsx +++ b/components/DepositForm.tsx @@ -32,13 +32,13 @@ import Tooltip from '@components/shared/Tooltip' import HealthImpactTokenChange from '@components/HealthImpactTokenChange' import SolBalanceWarnings from '@components/shared/SolBalanceWarnings' import useJupiterMints from 'hooks/useJupiterMints' -import useMangoGroup from 'hooks/useMangoGroup' import { useEnhancedWallet } from './wallet/EnhancedWalletProvider' import useSolBalance from 'hooks/useSolBalance' import FormatNumericValue from './shared/FormatNumericValue' import Decimal from 'decimal.js' import { floorToDecimal } from 'utils/numbers' import BankAmountWithValue from './shared/BankAmountWithValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' interface DepositFormProps { onSuccess: () => void @@ -89,7 +89,6 @@ export const useAlphaMax = (inputAmount: string, bank: Bank | undefined) => { function DepositForm({ onSuccess, token }: DepositFormProps) { const { t } = useTranslation('common') - const { group } = useMangoGroup() const [inputAmount, setInputAmount] = useState('') const [submitting, setSubmitting] = useState(false) const [selectedToken, setSelectedToken] = useState( @@ -100,6 +99,7 @@ function DepositForm({ onSuccess, token }: DepositFormProps) { const { mangoTokens } = useJupiterMints() const { handleConnect } = useEnhancedWallet() const { maxSolDeposit } = useSolBalance() + const banks = useBanksWithBalances('walletBalance') const bank = useMemo(() => { const group = mangoStore.getState().group @@ -185,22 +185,6 @@ function DepositForm({ onSuccess, token }: DepositFormProps) { } }, [bank, publicKey, inputAmount]) - // TODO extract into a shared hook for UserSetup.tsx - const banks = useMemo(() => { - const banks = group?.banksMapByName - ? Array.from(group?.banksMapByName, ([key, value]) => { - const walletBalance = walletBalanceForToken(walletTokens, key) - return { - key, - value, - walletBalance: walletBalance.maxAmount, - walletBalanceValue: walletBalance.maxAmount * value[0].uiPrice!, - } - }) - : [] - return banks - }, [group?.banksMapByName, walletTokens]) - const showInsufficientBalance = tokenMax.maxAmount < Number(inputAmount) || (selectedToken === 'SOL' && maxSolDeposit <= 0) @@ -235,7 +219,6 @@ function DepositForm({ onSuccess, token }: DepositFormProps) { banks={banks} onSelect={handleSelectToken} showDepositRates - sortByKey="walletBalanceValue" valueKey="walletBalance" /> diff --git a/components/RepayForm.tsx b/components/RepayForm.tsx index 1d0d2032..05a3e6e9 100644 --- a/components/RepayForm.tsx +++ b/components/RepayForm.tsx @@ -27,13 +27,13 @@ import { useAlphaMax, walletBalanceForToken } from './DepositForm' import SolBalanceWarnings from '@components/shared/SolBalanceWarnings' import useMangoAccount from 'hooks/useMangoAccount' import useJupiterMints from 'hooks/useJupiterMints' -import useMangoGroup from 'hooks/useMangoGroup' import { ACCOUNT_ACTION_MODAL_INNER_HEIGHT, INPUT_TOKEN_DEFAULT, } from 'utils/constants' import ConnectEmptyState from './shared/ConnectEmptyState' import BankAmountWithValue from './shared/BankAmountWithValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' interface RepayFormProps { onSuccess: () => void @@ -42,7 +42,6 @@ interface RepayFormProps { function RepayForm({ onSuccess, token }: RepayFormProps) { const { t } = useTranslation('common') - const { group } = useMangoGroup() const { mangoAccount } = useMangoAccount() const [inputAmount, setInputAmount] = useState('') const [submitting, setSubmitting] = useState(false) @@ -52,6 +51,7 @@ function RepayForm({ onSuccess, token }: RepayFormProps) { const [showTokenList, setShowTokenList] = useState(false) const [sizePercentage, setSizePercentage] = useState('') const { mangoTokens } = useJupiterMints() + const banks = useBanksWithBalances('borrowedAmount') // const { maxSolDeposit } = useSolBalance() const bank = useMemo(() => { @@ -168,27 +168,9 @@ function RepayForm({ onSuccess, token }: RepayFormProps) { [bank, publicKey?.toBase58(), sizePercentage] ) - const banks = useMemo(() => { - const banks = - group?.banksMapByName && mangoAccount - ? Array.from(group?.banksMapByName, ([key, value]) => { - return { - key, - value, - borrowAmount: mangoAccount.getTokenBorrowsUi(value[0]), - borrowAmountValue: - mangoAccount.getTokenBorrowsUi(value[0]) * value[0].uiPrice, - } - }) - .filter((b) => b.borrowAmount > 0) - .sort((a, b) => a.borrowAmount - b.borrowAmount) - : [] - return banks - }, [group?.banksMapByName, mangoAccount]) - useEffect(() => { if (!selectedToken && !token && banks.length) { - setSelectedToken(banks[0].key) + setSelectedToken(banks[0].bank.name) } }, [token, banks, selectedToken]) @@ -220,8 +202,7 @@ function RepayForm({ onSuccess, token }: RepayFormProps) { diff --git a/components/TokenList.tsx b/components/TokenList.tsx index cc9cc454..ea1aa7a1 100644 --- a/components/TokenList.tsx +++ b/components/TokenList.tsx @@ -23,7 +23,6 @@ import { formatTokenSymbol } from 'utils/tokens' import useMangoAccount from 'hooks/useMangoAccount' import useJupiterMints from '../hooks/useJupiterMints' import { Table, Td, Th, TrBody, TrHead } from './shared/TableElements' -import useMangoGroup from 'hooks/useMangoGroup' import DepositWithdrawModal from './modals/DepositWithdrawModal' import BorrowRepayModal from './modals/BorrowRepayModal' import { WRAPPED_SOL_MINT } from '@project-serum/serum/lib/token-instructions' @@ -32,6 +31,9 @@ import { PublicKey } from '@solana/web3.js' import ActionsLinkButton from './account/ActionsLinkButton' import FormatNumericValue from './shared/FormatNumericValue' import BankAmountWithValue from './shared/BankAmountWithValue' +import useBanksWithBalances, { + BankWithBalance, +} from 'hooks/useBanksWithBalances' const TokenList = () => { const { t } = useTranslation(['common', 'token', 'trade']) @@ -39,7 +41,6 @@ const TokenList = () => { const [showZeroBalances, setShowZeroBalances] = useState(true) const { mangoAccount } = useMangoAccount() const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances) - const { group } = useMangoGroup() const { mangoTokens } = useJupiterMints() const totalInterestData = mangoStore( (s) => s.mangoAccount.interestTotals.data @@ -47,40 +48,16 @@ const TokenList = () => { const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const router = useRouter() + const banks = useBanksWithBalances('balance') - const banks = useMemo(() => { - if (group) { - const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({ - key, - value, - })) - const sortedBanks = mangoAccount - ? rawBanks.sort((a, b) => { - const aBalance = Math.abs( - mangoAccount.getTokenBalanceUi(a.value[0]) * a.value[0].uiPrice - ) - const bBalance = Math.abs( - mangoAccount.getTokenBalanceUi(b.value[0]) * b.value[0].uiPrice - ) - if (aBalance > bBalance) return -1 - if (aBalance < bBalance) return 1 - - const aName = a.value[0].name - const bName = b.value[0].name - if (aName > bName) return 1 - if (aName < bName) return -1 - return 1 - }) - : rawBanks.sort((a, b) => a.key.localeCompare(b.key)) - - return mangoAccount && !showZeroBalances - ? sortedBanks.filter( - (b) => mangoAccount?.getTokenBalanceUi(b.value[0]) !== 0 - ) - : sortedBanks + const filteredBanks = useMemo(() => { + if (banks.length) { + return showZeroBalances + ? banks + : banks.filter((b) => Math.abs(b.balance) > 0) } return [] - }, [showZeroBalances, group, mangoAccount]) + }, [banks, showZeroBalances]) useEffect(() => { if (!connected) { @@ -88,8 +65,8 @@ const TokenList = () => { } }, [connected]) - const goToTokenPage = (bank: Bank) => { - router.push(`/token/${bank.name}`, undefined, { shallow: true }) + const goToTokenPage = (symbol: string) => { + router.push(`/token/${symbol}`, undefined, { shallow: true }) } return ( @@ -135,8 +112,8 @@ const TokenList = () => { - {banks.map(({ key, value }) => { - const bank = value[0] + {filteredBanks.map((b) => { + const bank = b.bank let logoURI if (mangoTokens?.length) { @@ -145,9 +122,7 @@ const TokenList = () => { )?.logoURI } - const tokenBalance = mangoAccount - ? mangoAccount.getTokenBalanceUi(bank) - : 0 + const tokenBalance = b.balance const hasInterestEarned = totalInterestData.find( (d) => d.symbol === bank.name @@ -169,7 +144,7 @@ const TokenList = () => { spotBalances[bank.mint.toString()]?.unsettled || 0 return ( - +
@@ -237,7 +212,7 @@ const TokenList = () => {
goToTokenPage(bank)} + onClick={() => goToTokenPage(bank.name)} size="small" > @@ -251,8 +226,8 @@ const TokenList = () => { ) : (
- {banks.map(({ key, value }) => { - return + {filteredBanks.map((b) => { + return })}
)} @@ -262,7 +237,7 @@ const TokenList = () => { export default TokenList -const MobileTokenListItem = ({ bank }: { bank: Bank }) => { +const MobileTokenListItem = ({ bank }: { bank: BankWithBalance }) => { const { t } = useTranslation(['common', 'token']) const [showTokenDetails, setShowTokenDetails] = useState(false) const { mangoTokens } = useJupiterMints() @@ -271,19 +246,19 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => { const totalInterestData = mangoStore( (s) => s.mangoAccount.interestTotals.data ) - const symbol = bank.name + const tokenBank = bank.bank + const mint = tokenBank.mint + const symbol = tokenBank.name const router = useRouter() let logoURI if (mangoTokens?.length) { logoURI = mangoTokens.find( - (t) => t.address === bank.mint.toString() + (t) => t.address === tokenBank.mint.toString() )!.logoURI } - const hasInterestEarned = totalInterestData.find( - (d) => d.symbol === bank.name - ) + const hasInterestEarned = totalInterestData.find((d) => d.symbol === symbol) const interestAmount = hasInterestEarned ? hasInterestEarned.borrow_interest * -1 + @@ -295,14 +270,14 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => { hasInterestEarned.deposit_interest_usd : 0 - const tokenBalance = mangoAccount ? mangoAccount.getTokenBalanceUi(bank) : 0 + const tokenBalance = bank.balance - const inOrders = spotBalances[bank.mint.toString()]?.inOrders || 0 + const inOrders = spotBalances[mint.toString()]?.inOrders || 0 - const unsettled = spotBalances[bank.mint.toString()]?.unsettled || 0 + const unsettled = spotBalances[mint.toString()]?.unsettled || 0 - const goToTokenPage = (bank: Bank) => { - router.push(`/token/${bank.name}`, undefined, { shallow: true }) + const goToTokenPage = (symbol: string) => { + router.push(`/token/${symbol}`, undefined, { shallow: true }) } return ( @@ -317,20 +292,20 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => { )}
-

{bank.name}

+

{symbol}

{t('balance')}:

- + setShowTokenDetails((prev) => !prev)} size="small" @@ -357,17 +332,17 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {

{t('trade:in-orders')}

- +

{t('trade:unsettled')}

- +

{t('interest-earned-paid')}

@@ -376,7 +351,7 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {

% @@ -384,7 +359,7 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => { | @@ -395,7 +370,7 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {

goToTokenPage(bank)} + onClick={() => goToTokenPage(symbol)} > {t('token:token-details')} diff --git a/components/WithdrawForm.tsx b/components/WithdrawForm.tsx index a9cb0b2b..d580be91 100644 --- a/components/WithdrawForm.tsx +++ b/components/WithdrawForm.tsx @@ -1,4 +1,4 @@ -import { Bank, HealthType } from '@blockworks-foundation/mango-v4' +import { HealthType } from '@blockworks-foundation/mango-v4' import { ArrowLeftIcon, ArrowUpTrayIcon, @@ -37,6 +37,7 @@ import { useWallet } from '@solana/wallet-adapter-react' import { useEnhancedWallet } from './wallet/EnhancedWalletProvider' import { floorToDecimal } from 'utils/numbers' import BankAmountWithValue from './shared/BankAmountWithValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' interface WithdrawFormProps { onSuccess: () => void @@ -57,6 +58,7 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) { const { mangoAccount } = useMangoAccount() const { connected } = useWallet() const { handleConnect } = useEnhancedWallet() + const banks = useBanksWithBalances('maxWithdraw') const bank = useMemo(() => { const group = mangoStore.getState().group @@ -140,32 +142,6 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) { setShowTokenList(false) }, []) - const withdrawBanks = useMemo(() => { - if (mangoAccount) { - const banks = group?.banksMapByName - ? Array.from(group?.banksMapByName, ([key, value]) => { - const bank: Bank = value[0] - const accountBalance = getMaxWithdrawForBank( - group, - bank, - mangoAccount - ).toNumber() - return { - key, - value, - accountBalance, - accountBalanceValue: - accountBalance && bank.uiPrice - ? accountBalance * bank.uiPrice - : 0, - } - }) - : [] - return banks - } - return [] - }, [mangoAccount, group]) - const initHealth = useMemo(() => { return group && mangoAccount ? mangoAccount.getHealthRatioUi(group, HealthType.init) @@ -200,10 +176,9 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
diff --git a/components/account/ActionTokenList.tsx b/components/account/ActionTokenList.tsx index 19df10d7..ebf9b75f 100644 --- a/components/account/ActionTokenList.tsx +++ b/components/account/ActionTokenList.tsx @@ -3,31 +3,31 @@ import useMangoAccount from 'hooks/useMangoAccount' import ActionTokenItem from './ActionTokenItem' type BankParams = { - key: string - value: Bank[] - walletBalance?: number - maxAmount?: number - accountBalance?: number + bank: Bank + balance: number + borrowedAmount: number + walletBalance: number + maxBorrow: number + maxWithdraw: number } const ActionTokenList = ({ banks, onSelect, - sortByKey, showBorrowRates, showDepositRates, valueKey, }: { banks: BankParams[] onSelect: (x: string) => void - sortByKey: - | 'maxAmount' - | 'walletBalanceValue' - | 'accountBalanceValue' - | 'borrowAmountValue' showBorrowRates?: boolean showDepositRates?: boolean - valueKey: 'maxAmount' | 'walletBalance' | 'accountBalance' | 'borrowAmount' + valueKey: + | 'balance' + | 'borrowedAmount' + | 'maxBorrow' + | 'maxWithdraw' + | 'walletBalance' }) => { const { mangoAccount } = useMangoAccount() @@ -37,15 +37,14 @@ const ActionTokenList = ({ {banks?.length ? ( banks .filter((b: BankParams) => !!b) - .sort((a: any, b: any) => b[sortByKey] - a[sortByKey]) - .map((bank: any) => { + .map((b: any) => { return ( diff --git a/components/borrow/AssetsBorrowsTable.tsx b/components/borrow/AssetsBorrowsTable.tsx index 1374fffc..7c0de2cf 100644 --- a/components/borrow/AssetsBorrowsTable.tsx +++ b/components/borrow/AssetsBorrowsTable.tsx @@ -4,7 +4,7 @@ import { } from '@heroicons/react/20/solid' import { useTranslation } from 'next-i18next' import Image from 'next/legacy/image' -import { useCallback, useEffect, useMemo, useState } from 'react' +import { useCallback, useEffect, useState } from 'react' import { useViewport } from '../../hooks/useViewport' import { formatNumericValue } from '../../utils/numbers' import { breakpoints } from '../../utils/theme' @@ -14,10 +14,9 @@ import useJupiterMints from 'hooks/useJupiterMints' import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import useMangoGroup from 'hooks/useMangoGroup' import mangoStore from '@store/mangoStore' -import { getMaxWithdrawForBank } from '@components/swap/useTokenMax' -import useMangoAccount from 'hooks/useMangoAccount' import BorrowRepayModal from '@components/modals/BorrowRepayModal' import BankAmountWithValue from '@components/shared/BankAmountWithValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' const AssetsBorrowsTable = () => { const { t } = useTranslation(['common', 'token']) @@ -26,10 +25,10 @@ const AssetsBorrowsTable = () => { const actions = mangoStore.getState().actions const initialStatsLoad = mangoStore((s) => s.tokenStats.initialLoad) const { group } = useMangoGroup() - const { mangoAccount } = useMangoAccount() const { mangoTokens } = useJupiterMints() const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false + const banks = useBanksWithBalances('maxBorrow') const handleShowBorrowModal = useCallback((token: string) => { setSelectedToken(token) @@ -42,17 +41,6 @@ const AssetsBorrowsTable = () => { } }, [group]) - const banks = useMemo(() => { - if (group) { - const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({ - key, - value, - })) - return rawBanks.sort((a, b) => a.key.localeCompare(b.key)) - } - return [] - }, [group]) - return ( <> {showTableView ? ( @@ -75,8 +63,8 @@ const AssetsBorrowsTable = () => { - {banks.map(({ key, value }) => { - const bank = value[0] + {banks.map((b) => { + const bank = b.bank let logoURI if (mangoTokens?.length) { @@ -86,18 +74,8 @@ const AssetsBorrowsTable = () => { } const borrows = bank.uiBorrows() - const available = - group && mangoAccount - ? getMaxWithdrawForBank( - group, - bank, - mangoAccount, - true - ).toNumber() - : 0 - return ( - +
@@ -123,7 +101,7 @@ const AssetsBorrowsTable = () => {
@@ -138,7 +116,7 @@ const AssetsBorrowsTable = () => {
handleShowBorrowModal(bank.name)} size="small" > @@ -154,8 +132,8 @@ const AssetsBorrowsTable = () => { ) : (
- {banks.map(({ key, value }) => { - const bank = value[0] + {banks.map((b) => { + const bank = b.bank let logoURI if (mangoTokens?.length) { logoURI = mangoTokens.find( @@ -163,18 +141,11 @@ const AssetsBorrowsTable = () => { )?.logoURI } - const available = - group && mangoAccount - ? getMaxWithdrawForBank( - group, - bank, - mangoAccount, - true - ).toNumber() - : 0 - return ( -
+
@@ -191,7 +162,7 @@ const AssetsBorrowsTable = () => {

{t('available')}

- +

{t('rate')}

@@ -200,7 +171,7 @@ const AssetsBorrowsTable = () => {

handleShowBorrowModal(bank.name)} size="medium" > diff --git a/components/borrow/BorrowPage.tsx b/components/borrow/BorrowPage.tsx index 135ac41c..475a0b46 100644 --- a/components/borrow/BorrowPage.tsx +++ b/components/borrow/BorrowPage.tsx @@ -21,6 +21,7 @@ import TabButtons from '@components/shared/TabButtons' import { useViewport } from 'hooks/useViewport' import { breakpoints } from 'utils/theme' import FormatNumericValue from '@components/shared/FormatNumericValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' const BorrowPage = () => { const { t } = useTranslation(['common', 'borrow']) @@ -33,6 +34,7 @@ const BorrowPage = () => { const { connected } = useWallet() const { width } = useViewport() const fullWidthTabs = width ? width < breakpoints.sm : false + const banks = useBanksWithBalances('borrowedAmount') const handleBorrowModal = () => { if (!connected || mangoAccount) { @@ -57,35 +59,20 @@ const BorrowPage = () => { } }, [actions, mangoAccountAddress]) - const banks = useMemo(() => { - if (group && mangoAccount) { - const borrowBanks = Array.from(group?.banksMapByName, ([key, value]) => ({ - key, - value, - })).filter((b) => { - const bank = b.value[0] - return mangoAccount.getTokenBalanceUi(bank) < 0 - }) - return borrowBanks - .map((b) => { - return { - balance: mangoAccount.getTokenBalanceUi(b.value[0]), - bank: b.value[0], - } - }) - .sort((a, b) => { - const aBalance = Math.abs(a.balance * a.bank.uiPrice) - const bBalance = Math.abs(b.balance * b.bank.uiPrice) - return aBalance > bBalance ? -1 : 1 - }) + const filteredBanks = useMemo(() => { + if (banks.length) { + return banks.filter((b) => b.borrowedAmount > 0) } return [] - }, [group, mangoAccount]) + }, [banks]) const borrowValue = useMemo(() => { - if (!banks.length) return 0 - return banks.reduce((a, c) => a + Math.abs(c.balance) * c.bank.uiPrice, 0) - }, [banks]) + if (!filteredBanks.length) return 0 + return filteredBanks.reduce( + (a, c) => a + Math.abs(c.borrowedAmount) * c.bank.uiPrice, + 0 + ) + }, [filteredBanks]) useEffect(() => { if (mangoAccountAddress && !borrowValue) { @@ -205,7 +192,7 @@ const BorrowPage = () => { />
{activeTab === 'borrow:your-borrows' ? ( - + ) : ( )} diff --git a/components/borrow/YourBorrowsTable.tsx b/components/borrow/YourBorrowsTable.tsx index a4706e65..de654b9b 100644 --- a/components/borrow/YourBorrowsTable.tsx +++ b/components/borrow/YourBorrowsTable.tsx @@ -23,11 +23,7 @@ import { useCallback, useState } from 'react' import BorrowRepayModal from '@components/modals/BorrowRepayModal' import Tooltip from '@components/shared/Tooltip' import BankAmountWithValue from '@components/shared/BankAmountWithValue' - -interface BankWithBalance { - balance: number - bank: Bank -} +import { BankWithBalance } from 'hooks/useBanksWithBalances' const YourBorrowsTable = ({ banks }: { banks: BankWithBalance[] }) => { const { t } = useTranslation(['common', 'trade']) @@ -82,14 +78,9 @@ const YourBorrowsTable = ({ banks }: { banks: BankWithBalance[] }) => { )?.logoURI } - const available = - group && mangoAccount - ? getMaxWithdrawForBank(group, bank, mangoAccount, true) - : new Decimal(0) + const available = b.maxBorrow - const borrowedAmount = mangoAccount - ? Math.abs(mangoAccount.getTokenBalanceUi(bank)) - : 0 + const borrowedAmount = b.borrowedAmount return ( @@ -141,7 +132,7 @@ const YourBorrowsTable = ({ banks }: { banks: BankWithBalance[] }) => { handleShowActionModals(bank.name, 'borrow') } diff --git a/components/modals/UserSetupModal.tsx b/components/modals/UserSetupModal.tsx index d6ffb879..f2a69aeb 100644 --- a/components/modals/UserSetupModal.tsx +++ b/components/modals/UserSetupModal.tsx @@ -30,7 +30,6 @@ import ButtonGroup from '../forms/ButtonGroup' import Input from '../forms/Input' import Label from '../forms/Label' import WalletIcon from '../icons/WalletIcon' -import { walletBalanceForToken } from '../DepositForm' import ParticlesBackground from '../ParticlesBackground' // import EditNftProfilePic from '../profile/EditNftProfilePic' // import EditProfileForm from '../profile/EditProfileForm' @@ -43,7 +42,8 @@ import { useEnhancedWallet } from '../wallet/EnhancedWalletProvider' import Modal from '../shared/Modal' import NumberFormat, { NumberFormatValues } from 'react-number-format' import { withValueLimit } from '@components/swap/SwapForm' -import FormatNumericValue from '@components/shared/FormatNumericValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' +import BankAmountWithValue from '@components/shared/BankAmountWithValue' const UserSetupModal = ({ isOpen, @@ -65,9 +65,9 @@ const UserSetupModal = ({ const [submitDeposit, setSubmitDeposit] = useState(false) const [sizePercentage, setSizePercentage] = useState('') // const [showEditProfilePic, setShowEditProfilePic] = useState(false) - const walletTokens = mangoStore((s) => s.wallet.tokens) const { handleConnect } = useEnhancedWallet() const { maxSolDeposit } = useSolBalance() + const banks = useBanksWithBalances('walletBalance') useEffect(() => { if (connected) { @@ -157,24 +157,8 @@ const UserSetupModal = ({ } }, [mangoAccount, showSetupStep, onClose]) - const banks = useMemo(() => { - const banks = group?.banksMapByName - ? Array.from(group?.banksMapByName, ([key, value]) => { - const walletBalance = walletBalanceForToken(walletTokens, key) - return { - key, - value, - tokenDecimals: walletBalance.maxDecimals, - walletBalance: walletBalance.maxAmount, - walletBalanceValue: walletBalance.maxAmount * value?.[0].uiPrice, - } - }) - : [] - return banks - }, [group?.banksMapByName, walletTokens]) - const depositBank = useMemo(() => { - return banks.find((b) => b.key === depositToken)?.value[0] + return banks.find((b) => b.bank.name === depositToken)?.bank }, [depositToken, banks]) const exceedsAlphaMax = useMemo(() => { @@ -195,9 +179,9 @@ const UserSetupModal = ({ }, [depositAmount, depositBank, group]) const tokenMax = useMemo(() => { - const bank = banks.find((bank) => bank.key === depositToken) + const bank = banks.find((b) => b.bank.name === depositToken) if (bank) { - return { amount: bank.walletBalance, decimals: bank.tokenDecimals } + return { amount: bank.walletBalance, decimals: bank.bank.mintDecimals } } return { amount: 0, decimals: 0 } }, [banks, depositToken]) @@ -481,7 +465,11 @@ const UserSetupModal = ({

{t('deposit-amount')}

- {depositAmount ? ( + + {/* {depositAmount ? ( <> - )} + )} */}

@@ -566,7 +554,6 @@ const UserSetupModal = ({ banks={banks} onSelect={setDepositToken} showDepositRates - sortByKey="walletBalanceValue" valueKey="walletBalance" />
diff --git a/components/shared/BalancesTable.tsx b/components/shared/BalancesTable.tsx index 1d14f16f..ab05a990 100644 --- a/components/shared/BalancesTable.tsx +++ b/components/shared/BalancesTable.tsx @@ -1,4 +1,4 @@ -import { Bank, Serum3Market } from '@blockworks-foundation/mango-v4' +import { Serum3Market } from '@blockworks-foundation/mango-v4' import useJupiterMints from 'hooks/useJupiterMints' import { NoSymbolIcon, QuestionMarkCircleIcon } from '@heroicons/react/20/solid' import mangoStore from '@store/mangoStore' @@ -18,53 +18,40 @@ import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm' import { LinkButton } from './Button' import { Table, Td, Th, TrBody, TrHead } from './TableElements' import useSelectedMarket from 'hooks/useSelectedMarket' -import useMangoGroup from 'hooks/useMangoGroup' import ConnectEmptyState from './ConnectEmptyState' import { useWallet } from '@solana/wallet-adapter-react' import Decimal from 'decimal.js' import FormatNumericValue from './FormatNumericValue' import BankAmountWithValue from './BankAmountWithValue' +import useBanksWithBalances, { + BankWithBalance, +} from 'hooks/useBanksWithBalances' const BalancesTable = () => { const { t } = useTranslation(['common', 'trade']) const { mangoAccount, mangoAccountAddress } = useMangoAccount() const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances) - const { group } = useMangoGroup() const { mangoTokens } = useJupiterMints() const { width } = useViewport() const { connected } = useWallet() const showTableView = width ? width > breakpoints.md : false + const banks = useBanksWithBalances('balance') - const banks = useMemo(() => { - if (!group || !mangoAccount) return [] + const filteredBanks = useMemo(() => { + if (banks.length) { + return banks.filter((b) => { + return ( + Math.abs(floorToDecimal(b.balance, b.bank.mintDecimals).toNumber()) > + 0 || + spotBalances[b.bank.mint.toString()]?.unsettled > 0 || + spotBalances[b.bank.mint.toString()]?.inOrders > 0 + ) + }) + } + return [] + }, [banks]) - const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({ - key, - value, - balance: mangoAccount.getTokenBalanceUi(value[0]), - })) - const sortedBanks = mangoAccount - ? rawBanks - .sort( - (a, b) => - Math.abs(b.balance * b.value[0].uiPrice) - - Math.abs(a.balance * a.value[0].uiPrice) - ) - .filter((c) => { - return ( - Math.abs( - floorToDecimal(c.balance, c.value[0].mintDecimals).toNumber() - ) > 0 || - spotBalances[c.value[0].mint.toString()]?.unsettled > 0 || - spotBalances[c.value[0].mint.toString()]?.inOrders > 0 - ) - }) - : rawBanks - - return sortedBanks - }, [group, mangoAccount, spotBalances]) - - return banks?.length ? ( + return filteredBanks.length ? ( showTableView ? ( @@ -78,8 +65,8 @@ const BalancesTable = () => { - {banks.map(({ key, value }) => { - const bank = value[0] + {filteredBanks.map((b) => { + const bank = b.bank let logoURI if (mangoTokens.length) { @@ -92,7 +79,7 @@ const BalancesTable = () => { const unsettled = spotBalances[bank.mint.toString()]?.unsettled || 0 return ( - +
@@ -106,14 +93,10 @@ const BalancesTable = () => {
- +

@@ -131,8 +114,8 @@ const BalancesTable = () => {
) : ( <> - {banks.map(({ key, value }) => { - const bank = value[0] + {filteredBanks.map((b) => { + const bank = b.bank let logoURI if (mangoTokens.length) { @@ -147,7 +130,7 @@ const BalancesTable = () => { return (
@@ -161,14 +144,10 @@ const BalancesTable = () => {
- + @@ -213,11 +192,12 @@ const BalancesTable = () => { export default BalancesTable -const Balance = ({ bank }: { bank: Bank }) => { - const { mangoAccount } = useMangoAccount() +const Balance = ({ bank }: { bank: BankWithBalance }) => { const { selectedMarket } = useSelectedMarket() const { asPath } = useRouter() + const tokenBank = bank.bank + const handleTradeFormBalanceClick = useCallback( (balance: number, type: 'base' | 'quote') => { const set = mangoStore.getState().set @@ -279,14 +259,14 @@ const Balance = ({ bank }: { bank: Bank }) => { const set = mangoStore.getState().set if (balance >= 0) { set((s) => { - s.swap.inputBank = bank + s.swap.inputBank = tokenBank s.swap.amountIn = balance.toString() s.swap.amountOut = '' s.swap.swapMode = 'ExactIn' }) } else { set((s) => { - s.swap.outputBank = bank + s.swap.outputBank = tokenBank s.swap.amountIn = '' s.swap.amountOut = Math.abs(balance).toString() s.swap.swapMode = 'ExactOut' @@ -296,21 +276,19 @@ const Balance = ({ bank }: { bank: Bank }) => { [bank] ) - const balance = useMemo(() => { - return mangoAccount ? mangoAccount.getTokenBalanceUi(bank) : 0 - }, [bank, mangoAccount]) + const balance = bank.balance const isBaseOrQuote = useMemo(() => { if (selectedMarket instanceof Serum3Market) { - if (bank.tokenIndex === selectedMarket.baseTokenIndex) { + if (tokenBank.tokenIndex === selectedMarket.baseTokenIndex) { return 'base' - } else if (bank.tokenIndex === selectedMarket.quoteTokenIndex) { + } else if (tokenBank.tokenIndex === selectedMarket.quoteTokenIndex) { return 'quote' } else return '' } - }, [bank, selectedMarket]) + }, [tokenBank, selectedMarket]) - console.log(bank.name, ' balance', new Decimal(balance).toFixed()) + console.log(tokenBank.name, ' balance', new Decimal(balance).toFixed()) if (!balance) return

0

return ( @@ -322,21 +300,27 @@ const Balance = ({ bank }: { bank: Bank }) => { handleTradeFormBalanceClick(Math.abs(balance), isBaseOrQuote) } > - + ) : asPath.includes('/swap') ? ( handleSwapFormBalanceClick( - Number(formatNumericValue(balance, bank.mintDecimals)) + Number(formatNumericValue(balance, tokenBank.mintDecimals)) ) } > - + ) : ( - + )}

) diff --git a/components/stats/TokenStats.tsx b/components/stats/TokenStats.tsx index 57e47218..5dcdea41 100644 --- a/components/stats/TokenStats.tsx +++ b/components/stats/TokenStats.tsx @@ -6,7 +6,7 @@ import { } from '@heroicons/react/20/solid' import { useTranslation } from 'next-i18next' import Image from 'next/legacy/image' -import { Fragment, useEffect, useMemo, useState } from 'react' +import { Fragment, useEffect, useState } from 'react' import { useViewport } from '../../hooks/useViewport' import { breakpoints } from '../../utils/theme' import { IconButton, LinkButton } from '../shared/Button' @@ -20,6 +20,7 @@ import useMangoGroup from 'hooks/useMangoGroup' import mangoStore from '@store/mangoStore' import FormatNumericValue from '@components/shared/FormatNumericValue' import BankAmountWithValue from '@components/shared/BankAmountWithValue' +import useBanksWithBalances from 'hooks/useBanksWithBalances' const TokenStats = () => { const { t } = useTranslation(['common', 'token']) @@ -31,6 +32,7 @@ const TokenStats = () => { const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const router = useRouter() + const banks = useBanksWithBalances() useEffect(() => { if (group && !initialStatsLoad) { @@ -38,17 +40,6 @@ const TokenStats = () => { } }, [group]) - const banks = useMemo(() => { - if (group) { - const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({ - key, - value, - })) - return rawBanks.sort((a, b) => a.key.localeCompare(b.key)) - } - return [] - }, [group]) - const handleShowTokenDetails = (name: string) => { showTokenDetails ? setShowTokenDetails('') : setShowTokenDetails(name) } @@ -100,8 +91,8 @@ const TokenStats = () => { - {banks.map(({ key, value }) => { - const bank: Bank = value[0] + {banks.map((b) => { + const bank: Bank = b.bank let logoURI if (mangoTokens?.length) { @@ -115,7 +106,7 @@ const TokenStats = () => { deposits - deposits * bank.minVaultToDepositsRatio - borrows return ( - +
@@ -213,8 +204,8 @@ const TokenStats = () => { ) : (
- {banks.map(({ key, value }) => { - const bank = value[0] + {banks.map((b) => { + const bank = b.bank let logoURI if (mangoTokens?.length) { logoURI = mangoTokens.find( @@ -227,7 +218,10 @@ const TokenStats = () => { const available = deposits - deposits * bank.minVaultToDepositsRatio - borrows return ( -
+
diff --git a/components/stats/TotalDepositBorrowCharts.tsx b/components/stats/TotalDepositBorrowCharts.tsx index 0f976b1a..a839eabd 100644 --- a/components/stats/TotalDepositBorrowCharts.tsx +++ b/components/stats/TotalDepositBorrowCharts.tsx @@ -1,10 +1,10 @@ import { TokenStatsItem } from '@store/mangoStore' -import useMangoGroup from 'hooks/useMangoGroup' import { useTranslation } from 'next-i18next' import dynamic from 'next/dynamic' import { useMemo, useState } from 'react' import dayjs from 'dayjs' import { formatYAxis } from 'utils/formatting' +import useBanksWithBalances from 'hooks/useBanksWithBalances' const DetailedAreaChart = dynamic( () => import('@components/shared/DetailedAreaChart'), { ssr: false } @@ -26,7 +26,7 @@ const TotalDepositBorrowCharts = ({ const { t } = useTranslation(['common', 'token', 'trade']) const [borrowDaysToShow, setBorrowDaysToShow] = useState('30') const [depositDaysToShow, setDepositDaysToShow] = useState('30') - const { group } = useMangoGroup() + const banks = useBanksWithBalances() const totalDepositBorrowValues = useMemo(() => { if (!tokenStats) return [] @@ -82,28 +82,11 @@ const TotalDepositBorrowCharts = ({ return totalDepositBorrowValues }, [totalDepositBorrowValues, depositDaysToShow]) - const banks = useMemo(() => { - if (group) { - const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({ - key, - value, - })) - return rawBanks - } - return [] - }, [group]) - const [currentTotalDepositValue, currentTotalBorrowValue] = useMemo(() => { if (banks.length) { return [ - banks.reduce( - (a, c) => a + c.value[0].uiPrice * c.value[0].uiDeposits(), - 0 - ), - banks.reduce( - (a, c) => a + c.value[0].uiPrice * c.value[0].uiBorrows(), - 0 - ), + banks.reduce((a, c) => a + c.bank.uiPrice * c.bank.uiDeposits(), 0), + banks.reduce((a, c) => a + c.bank.uiPrice * c.bank.uiBorrows(), 0), ] } return [0, 0] diff --git a/hooks/useBanksWithBalances.ts b/hooks/useBanksWithBalances.ts new file mode 100644 index 00000000..77eee062 --- /dev/null +++ b/hooks/useBanksWithBalances.ts @@ -0,0 +1,85 @@ +import { Bank } from '@blockworks-foundation/mango-v4' +import { walletBalanceForToken } from '@components/DepositForm' +import { getMaxWithdrawForBank } from '@components/swap/useTokenMax' +import mangoStore from '@store/mangoStore' +import { useMemo } from 'react' +import useMangoAccount from './useMangoAccount' +import useMangoGroup from './useMangoGroup' + +export interface BankWithBalance { + balance: number + bank: Bank + borrowedAmount: number + maxBorrow: number + maxWithdraw: number + walletBalance: number +} + +export default function useBanksWithBalances( + sortByKey?: + | 'balance' + | 'borrowedAmount' + | 'maxBorrow' + | 'maxWithdraw' + | 'walletBalance' +) { + const { group } = useMangoGroup() + const { mangoAccount } = useMangoAccount() + const walletTokens = mangoStore((s) => s.wallet.tokens) + + const banks: BankWithBalance[] = useMemo(() => { + if (group) { + const banksWithBalances = Array.from( + group?.banksMapByName, + ([key, value]) => ({ + key, + value, + }) + ).map((b) => { + const bank = b.value[0] + const balance = mangoAccount ? mangoAccount.getTokenBalanceUi(bank) : 0 + const maxBorrow = mangoAccount + ? getMaxWithdrawForBank(group, bank, mangoAccount, true).toNumber() + : 0 + const maxWithdraw = mangoAccount + ? getMaxWithdrawForBank(group, bank, mangoAccount).toNumber() + : 0 + const borrowedAmount = mangoAccount + ? mangoAccount.getTokenBorrowsUi(bank) + : 0 + const walletBalance = + walletBalanceForToken(walletTokens, bank.name)?.maxAmount || 0 + return { + bank, + balance, + borrowedAmount, + maxBorrow, + maxWithdraw, + walletBalance, + } + }) + + const sortedBanks = banksWithBalances.sort((a, b) => { + if (sortByKey) { + const aPrice = a.bank.uiPrice + const bPrice = b.bank.uiPrice + const aValue = Math.abs(a[sortByKey]) * aPrice + const bValue = Math.abs(b[sortByKey]) * bPrice + if (aValue > bValue) return -1 + if (aValue < bValue) return 1 + } + + const aName = a.bank.name + const bName = b.bank.name + if (aName > bName) return 1 + if (aName < bName) return -1 + return 1 + }) + + return sortedBanks + } + return [] + }, [group, mangoAccount]) + + return banks +}