add hook for banks and balances

This commit is contained in:
saml33 2023-01-30 15:13:38 +11:00
parent 52e871e566
commit d8970b02c6
14 changed files with 266 additions and 392 deletions

View File

@ -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"
/>
</EnterBottomExitBottom>
<FadeInFadeOut show={!showTokenList}>

View File

@ -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"
/>
</EnterBottomExitBottom>

View File

@ -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) {
<ActionTokenList
banks={banks}
onSelect={handleSelectToken}
sortByKey="borrowAmountValue"
valueKey="borrowAmount"
valueKey="borrowedAmount"
/>
</EnterBottomExitBottom>
<FadeInFadeOut show={!showTokenList}>

View File

@ -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 = () => {
</TrHead>
</thead>
<tbody>
{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 (
<TrBody className="last:border-y-0" key={key}>
<TrBody className="last:border-y-0" key={bank.name}>
<Td>
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
@ -237,7 +212,7 @@ const TokenList = () => {
<div className="flex justify-end space-x-2">
<ActionsMenu bank={bank} mangoAccount={mangoAccount} />
<IconButton
onClick={() => goToTokenPage(bank)}
onClick={() => goToTokenPage(bank.name)}
size="small"
>
<ChevronRightIcon className="h-5 w-5" />
@ -251,8 +226,8 @@ const TokenList = () => {
</Table>
) : (
<div>
{banks.map(({ key, value }) => {
return <MobileTokenListItem key={key} bank={value[0]} />
{filteredBanks.map((b) => {
return <MobileTokenListItem key={b.bank.name} bank={b} />
})}
</div>
)}
@ -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 }) => {
)}
</div>
<div>
<p className="text-th-fgd-1">{bank.name}</p>
<p className="text-th-fgd-1">{symbol}</p>
<p className="font-mono text-sm text-th-fgd-1">
<span className="mr-1 font-body text-th-fgd-4">
{t('balance')}:
</span>
<FormatNumericValue
value={tokenBalance}
decimals={bank.mintDecimals}
decimals={tokenBank.mintDecimals}
/>
</p>
</div>
</div>
<div className="flex items-center space-x-3">
<ActionsMenu bank={bank} mangoAccount={mangoAccount} />
<ActionsMenu bank={tokenBank} mangoAccount={mangoAccount} />
<IconButton
onClick={() => setShowTokenDetails((prev) => !prev)}
size="small"
@ -357,17 +332,17 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
<div className="mt-4 grid grid-cols-2 gap-4 border-t border-th-bkg-3 pt-4">
<div className="col-span-1">
<p className="text-xs text-th-fgd-3">{t('trade:in-orders')}</p>
<BankAmountWithValue amount={inOrders} bank={bank} />
<BankAmountWithValue amount={inOrders} bank={tokenBank} />
</div>
<div className="col-span-1">
<p className="text-xs text-th-fgd-3">{t('trade:unsettled')}</p>
<BankAmountWithValue amount={unsettled} bank={bank} />
<BankAmountWithValue amount={unsettled} bank={tokenBank} />
</div>
<div className="col-span-1">
<p className="text-xs text-th-fgd-3">{t('interest-earned-paid')}</p>
<BankAmountWithValue
amount={interestAmount}
bank={bank}
bank={tokenBank}
value={interestValue}
/>
</div>
@ -376,7 +351,7 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
<p className="space-x-2 font-mono">
<span className="text-th-up">
<FormatNumericValue
value={bank.getDepositRateUi()}
value={tokenBank.getDepositRateUi()}
decimals={2}
/>
%
@ -384,7 +359,7 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
<span className="font-normal text-th-fgd-4">|</span>
<span className="text-th-down">
<FormatNumericValue
value={bank.getBorrowRateUi()}
value={tokenBank.getBorrowRateUi()}
decimals={2}
roundUp
/>
@ -395,7 +370,7 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {
<div className="col-span-1">
<LinkButton
className="flex items-center"
onClick={() => goToTokenPage(bank)}
onClick={() => goToTokenPage(symbol)}
>
{t('token:token-details')}
<ChevronRightIcon className="ml-1.5 h-5 w-5" />

View File

@ -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) {
</div>
</div>
<ActionTokenList
banks={withdrawBanks}
banks={banks}
onSelect={handleSelectToken}
sortByKey="accountBalanceValue"
valueKey="accountBalance"
valueKey="maxWithdraw"
/>
</EnterBottomExitBottom>
<FadeInFadeOut show={!showTokenList}>

View File

@ -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 (
<ActionTokenItem
bank={bank.value[0]}
customValue={bank[valueKey]}
key={bank.value[0].name}
bank={b.bank}
customValue={b[valueKey]}
key={b.bank.name}
onSelect={onSelect}
roundUp={valueKey === 'borrowAmount'}
roundUp={valueKey === 'borrowedAmount'}
showBorrowRates={showBorrowRates}
showDepositRates={showDepositRates}
/>

View File

@ -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 = () => {
</TrHead>
</thead>
<tbody>
{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 (
<TrBody key={key}>
<TrBody key={bank.name}>
<Td>
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
@ -123,7 +101,7 @@ const AssetsBorrowsTable = () => {
<Td>
<div className="flex flex-col text-right">
<BankAmountWithValue
amount={available}
amount={b.maxBorrow}
bank={bank}
stacked
/>
@ -138,7 +116,7 @@ const AssetsBorrowsTable = () => {
<div className="flex justify-end">
<Tooltip content={`${t('borrow')} ${bank.name}`}>
<IconButton
disabled={available === 0}
disabled={b.maxBorrow === 0}
onClick={() => handleShowBorrowModal(bank.name)}
size="small"
>
@ -154,8 +132,8 @@ const AssetsBorrowsTable = () => {
</Table>
) : (
<div>
{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 (
<div key={key} className="border-b border-th-bkg-3 px-6 py-4">
<div
key={bank.name}
className="border-b border-th-bkg-3 px-6 py-4"
>
<div className="flex items-center justify-between">
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
@ -191,7 +162,7 @@ const AssetsBorrowsTable = () => {
<p className="mb-0.5 text-right text-xs">
{t('available')}
</p>
<BankAmountWithValue amount={available} bank={bank} />
<BankAmountWithValue amount={b.maxBorrow} bank={bank} />
</div>
<div>
<p className="mb-0.5 text-right text-xs">{t('rate')}</p>
@ -200,7 +171,7 @@ const AssetsBorrowsTable = () => {
</p>
</div>
<IconButton
disabled={available === 0}
disabled={b.maxBorrow === 0}
onClick={() => handleShowBorrowModal(bank.name)}
size="medium"
>

View File

@ -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 = () => {
/>
</div>
{activeTab === 'borrow:your-borrows' ? (
<YourBorrowsTable banks={banks} />
<YourBorrowsTable banks={filteredBanks} />
) : (
<AssetsBorrowsTable />
)}

View File

@ -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 (
<TrBody key={bank.name} className="text-sm">
@ -141,7 +132,7 @@ const YourBorrowsTable = ({ banks }: { banks: BankWithBalance[] }) => {
</Tooltip>
<Tooltip content={`${t('borrow')} ${bank.name}`}>
<IconButton
disabled={available.eq(0)}
disabled={available === 0}
onClick={() =>
handleShowActionModals(bank.name, 'borrow')
}

View File

@ -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 = ({
<div className="flex justify-between px-2 py-4">
<p>{t('deposit-amount')}</p>
<p className="font-mono text-th-fgd-2">
{depositAmount ? (
<BankAmountWithValue
amount={depositAmount}
bank={depositBank}
/>
{/* {depositAmount ? (
<>
<FormatNumericValue
value={depositAmount}
@ -506,7 +494,7 @@ const UserSetupModal = ({
($0.00)
</span>
</>
)}
)} */}
</p>
</div>
</div>
@ -566,7 +554,6 @@ const UserSetupModal = ({
banks={banks}
onSelect={setDepositToken}
showDepositRates
sortByKey="walletBalanceValue"
valueKey="walletBalance"
/>
</div>

View File

@ -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 ? (
<Table>
<thead>
@ -78,8 +65,8 @@ const BalancesTable = () => {
</TrHead>
</thead>
<tbody>
{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 (
<TrBody key={key} className="text-sm">
<TrBody key={bank.name} className="text-sm">
<Td>
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
@ -106,14 +93,10 @@ const BalancesTable = () => {
</div>
</Td>
<Td className="text-right">
<Balance bank={bank} />
<Balance bank={b} />
<p className="text-sm text-th-fgd-4">
<FormatNumericValue
value={
mangoAccount
? mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice
: 0
}
value={mangoAccount ? b.balance * bank.uiPrice : 0}
isUsd
/>
</p>
@ -131,8 +114,8 @@ const BalancesTable = () => {
</Table>
) : (
<>
{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 (
<div
className="flex items-center justify-between border-b border-th-bkg-3 p-4"
key={key}
key={bank.name}
>
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
@ -161,14 +144,10 @@ const BalancesTable = () => {
</div>
<div className="text-right">
<div className="mb-0.5 flex justify-end space-x-1.5">
<Balance bank={bank} />
<Balance bank={b} />
<span className="text-sm text-th-fgd-4">
<FormatNumericValue
value={
mangoAccount
? mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice
: 0
}
value={mangoAccount ? b.balance * bank.uiPrice : 0}
isUsd
/>
</span>
@ -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 <p className="flex justify-end">0</p>
return (
@ -322,21 +300,27 @@ const Balance = ({ bank }: { bank: Bank }) => {
handleTradeFormBalanceClick(Math.abs(balance), isBaseOrQuote)
}
>
<FormatNumericValue value={balance} decimals={bank.mintDecimals} />
<FormatNumericValue
value={balance}
decimals={tokenBank.mintDecimals}
/>
</LinkButton>
) : asPath.includes('/swap') ? (
<LinkButton
className="font-normal underline-offset-4"
onClick={() =>
handleSwapFormBalanceClick(
Number(formatNumericValue(balance, bank.mintDecimals))
Number(formatNumericValue(balance, tokenBank.mintDecimals))
)
}
>
<FormatNumericValue value={balance} decimals={bank.mintDecimals} />
<FormatNumericValue
value={balance}
decimals={tokenBank.mintDecimals}
/>
</LinkButton>
) : (
<FormatNumericValue value={balance} decimals={bank.mintDecimals} />
<FormatNumericValue value={balance} decimals={tokenBank.mintDecimals} />
)}
</p>
)

View File

@ -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 = () => {
</TrHead>
</thead>
<tbody>
{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 (
<TrBody key={key}>
<TrBody key={bank.name}>
<Td>
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
@ -213,8 +204,8 @@ const TokenStats = () => {
</Table>
) : (
<div>
{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 (
<div key={key} className="border-b border-th-bkg-3 px-6 py-4">
<div
key={bank.name}
className="border-b border-th-bkg-3 px-6 py-4"
>
<div className="flex items-center justify-between">
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">

View File

@ -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]

View File

@ -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
}