Mp 3330 compare accounts via use updated account for vaults (#415)
* feat: added simulateTrade * MP-3330: added vault positions to the useUpdated Account * tidy: format * tidy: refactor * Health indicator change preview (#410) * fix: adjusted the AccountDetail width * feat: added health indicator updates * Update src/components/Account/AccountDetails.tsx Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com> * fix: created a function for the back- and foregroundColors * fix: updated tailwind conf * fix: fixed the useHealthColorAndLabel function --------- Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com> Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com> * fix: added updatedAccount to AccountSummary (#414) Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com> * fix: added a new way of calulating values to vaults * fix: refactored the displayCurrency * fix: fixed the subtitles, to not nest <p> tags * MP-3330: added comparison to the vault mechanics * fix: fixed tests * fix: updated the borrow slider percentage on vaults * fix: addressed change request * update displayValue stuff * fixed wrong display conversions * fix: fixed the display price and renamed getDepositsAndLendsAfterCoinSpent * fix test and update DisplayCurrency * tidy: refactor * tidy: rename method --------- Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com> Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
This commit is contained in:
parent
b7019023f0
commit
f1ee4bd7f3
@ -59,6 +59,7 @@ describe('<VaultBorrowings />', () => {
|
||||
onChangeBorrowings: jest.fn(),
|
||||
depositActions: [],
|
||||
depositCapReachedCoins: [],
|
||||
displayCurrency: 'uosmo',
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
@ -80,7 +81,7 @@ describe('<VaultBorrowings />', () => {
|
||||
it('should render DisplayCurrency correctly', () => {
|
||||
expect(mockedDisplayCurrency).toHaveBeenCalledTimes(1)
|
||||
expect(mockedDisplayCurrency).toHaveBeenCalledWith(
|
||||
{ coin: new BNCoin({ denom: 'uosmo', amount: '0' }) },
|
||||
{ coin: new BNCoin({ denom: 'usd', amount: '0' }) },
|
||||
expect.anything(),
|
||||
)
|
||||
})
|
||||
|
@ -32,9 +32,7 @@ export default function AccordionContent(props: Props) {
|
||||
>
|
||||
<div>
|
||||
<Text>{title}</Text>
|
||||
<Text size='xs' className='mt-1 text-white/60'>
|
||||
{renderSubTitle()}
|
||||
</Text>
|
||||
{renderSubTitle()}
|
||||
</div>
|
||||
<div className='block pr-1 group-[[open]]:hidden'>
|
||||
{isOpen ? <ChevronDown className='h-1.5' /> : <ChevronRight className='w-1.5' />}
|
||||
|
@ -17,20 +17,20 @@ import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import { SortAsc, SortDesc, SortNone } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
import { convertLiquidityRateToAPR, convertToDisplayAmount, demagnify } from 'utils/formatters'
|
||||
import { convertLiquidityRateToAPR, demagnify, getCoinValue } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { convertAprToApy } from 'utils/parsers'
|
||||
import { getPage, getRoute } from 'utils/route'
|
||||
|
||||
import { ORACLE_DENOM } from '../../constants/oracle'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
lendingData: LendingMarketTableData[]
|
||||
@ -38,11 +38,20 @@ interface Props {
|
||||
tableBodyClassName?: string
|
||||
}
|
||||
|
||||
interface PositionValue {
|
||||
type: 'deposits' | 'borrowing' | 'lending'
|
||||
symbol: string
|
||||
size: number
|
||||
value: string
|
||||
denom: string
|
||||
amount: BigNumber
|
||||
apy: number
|
||||
}
|
||||
|
||||
function calculatePositionValues(
|
||||
type: 'deposits' | 'borrowing' | 'lending',
|
||||
asset: Asset,
|
||||
prices: BNCoin[],
|
||||
displayCurrencyDenom: string,
|
||||
position: BNCoin,
|
||||
apy: number,
|
||||
) {
|
||||
@ -51,22 +60,29 @@ function calculatePositionValues(
|
||||
type,
|
||||
symbol: asset.symbol,
|
||||
size: demagnify(amount, asset),
|
||||
value: convertToDisplayAmount(
|
||||
BNCoin.fromDenomAndBigNumber(denom, amount),
|
||||
displayCurrencyDenom,
|
||||
prices,
|
||||
).toString(),
|
||||
value: getCoinValue(BNCoin.fromDenomAndBigNumber(denom, amount), prices).toString(),
|
||||
denom,
|
||||
amount: type === 'borrowing' ? amount.negated() : amount,
|
||||
apy,
|
||||
}
|
||||
}
|
||||
|
||||
function calculateVaultValues(vault: DepositedVault, apy: number) {
|
||||
const { name } = vault
|
||||
const totalValue = vault.values.primary.plus(vault.values.secondary)
|
||||
|
||||
return {
|
||||
type: 'vault',
|
||||
symbol: name,
|
||||
size: 0,
|
||||
value: totalValue.toString(),
|
||||
denom: vault.denoms.lp,
|
||||
amount: BN_ZERO,
|
||||
apy,
|
||||
}
|
||||
}
|
||||
|
||||
export default function AccountBalancesTable(props: Props) {
|
||||
const [displayCurrency] = useLocalStorage<string>(
|
||||
DISPLAY_CURRENCY_KEY,
|
||||
DEFAULT_SETTINGS.displayCurrency,
|
||||
)
|
||||
const { data: prices } = usePrices()
|
||||
const currentAccount = useCurrentAccount()
|
||||
const navigate = useNavigate()
|
||||
@ -77,31 +93,38 @@ export default function AccountBalancesTable(props: Props) {
|
||||
const accountDeposits = props.account?.deposits ?? []
|
||||
const accountLends = props.account?.lends ?? []
|
||||
const accountDebts = props.account?.debts ?? []
|
||||
const accountVaults = props.account?.vaults ?? []
|
||||
|
||||
const deposits = accountDeposits.map((deposit) => {
|
||||
const asset = ASSETS.find((asset) => asset.denom === deposit.denom) ?? ASSETS[0]
|
||||
const deposits: PositionValue[] = []
|
||||
accountDeposits.forEach((deposit) => {
|
||||
const asset = ASSETS.find(byDenom(deposit.denom))
|
||||
if (!asset) return
|
||||
const apy = 0
|
||||
return calculatePositionValues('deposits', asset, prices, displayCurrency, deposit, apy)
|
||||
deposits.push(calculatePositionValues('deposits', asset, prices, deposit, apy))
|
||||
})
|
||||
|
||||
const lends = accountLends.map((lending) => {
|
||||
const asset = ASSETS.find((asset) => asset.denom === lending.denom) ?? ASSETS[0]
|
||||
const asset = ASSETS.find(byDenom(lending.denom)) ?? ASSETS[0]
|
||||
const apr = convertLiquidityRateToAPR(
|
||||
props.lendingData.find((market) => market.asset.denom === lending.denom)
|
||||
?.marketLiquidityRate ?? 0,
|
||||
)
|
||||
const apy = convertAprToApy(apr, 365)
|
||||
return calculatePositionValues('lending', asset, prices, displayCurrency, lending, apy)
|
||||
return calculatePositionValues('lending', asset, prices, lending, apy)
|
||||
})
|
||||
|
||||
const vaults = accountVaults.map((vault) => {
|
||||
const apy = (vault.apy ?? 0) * 100
|
||||
return calculateVaultValues(vault, apy)
|
||||
})
|
||||
const debts = accountDebts.map((debt) => {
|
||||
const asset = ASSETS.find(byDenom(debt.denom)) ?? ASSETS[0]
|
||||
const apy =
|
||||
props.borrowingData.find((market) => market.asset.denom === debt.denom)?.borrowRate ?? 0
|
||||
return calculatePositionValues('borrowing', asset, prices, displayCurrency, debt, apy * -100)
|
||||
return calculatePositionValues('borrowing', asset, prices, debt, apy * -100)
|
||||
})
|
||||
|
||||
return [...deposits, ...lends, ...debts]
|
||||
}, [displayCurrency, prices, props.account, props.borrowingData, props.lendingData])
|
||||
return [...deposits, ...lends, ...vaults, ...debts]
|
||||
}, [prices, props.account, props.borrowingData, props.lendingData])
|
||||
|
||||
const columns = React.useMemo<ColumnDef<AccountBalanceRow>[]>(
|
||||
() => [
|
||||
@ -114,6 +137,7 @@ export default function AccountBalancesTable(props: Props) {
|
||||
<Text size='xs'>
|
||||
{row.original.symbol}
|
||||
{row.original.type === 'lending' && <span className='ml-1 text-profit'>(lent)</span>}
|
||||
{row.original.type === 'vault' && <span className='ml-1 text-profit'>(farm)</span>}
|
||||
</Text>
|
||||
)
|
||||
},
|
||||
@ -124,8 +148,8 @@ export default function AccountBalancesTable(props: Props) {
|
||||
id: 'value',
|
||||
cell: ({ row }) => {
|
||||
const coin = new BNCoin({
|
||||
denom: row.original.denom,
|
||||
amount: row.original.amount.toString(),
|
||||
denom: ORACLE_DENOM,
|
||||
amount: row.original.value.toString(),
|
||||
})
|
||||
return <DisplayCurrency coin={coin} className='text-xs text-right' />
|
||||
},
|
||||
@ -135,6 +159,8 @@ export default function AccountBalancesTable(props: Props) {
|
||||
accessorKey: 'size',
|
||||
header: 'Size',
|
||||
cell: ({ row }) => {
|
||||
if (row.original.amount.isEqualTo(BN_ZERO))
|
||||
return <span className='w-full text-xs text-center'>–</span>
|
||||
const amount = demagnify(
|
||||
row.original.amount,
|
||||
getAssetByDenom(row.original.denom) ?? ASSETS[0],
|
||||
@ -154,7 +180,7 @@ export default function AccountBalancesTable(props: Props) {
|
||||
accessorKey: 'apy',
|
||||
header: 'APY',
|
||||
cell: ({ row }) => {
|
||||
if (row.original.apy === 0)
|
||||
if (row.original.type === 'deposit')
|
||||
return <span className='w-full text-xs text-center'>–</span>
|
||||
return (
|
||||
<FormattedNumber
|
||||
@ -210,7 +236,7 @@ export default function AccountBalancesTable(props: Props) {
|
||||
<thead className='border-b border-white/5'>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header, index) => {
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
@ -262,7 +288,7 @@ export default function AccountBalancesTable(props: Props) {
|
||||
<td
|
||||
key={cell.id}
|
||||
className={classNames(
|
||||
cell.column.id === 'symbol' ? `border-l ${borderClass}` : 'pl-4 text-right',
|
||||
cell.column.id === 'symbol' ? `border-l ${borderClass}` : 'text-right',
|
||||
'p-2',
|
||||
)}
|
||||
>
|
||||
|
@ -51,12 +51,12 @@ function AccountDetails(props: Props) {
|
||||
const { health: updatedHealth } = useHealthComputer(updatedAccount || account)
|
||||
const { data: prices } = usePrices()
|
||||
const accountBalanceValue = useMemo(
|
||||
() => calculateAccountBalanceValue(updatedAccount ? updatedAccount : account, prices),
|
||||
() => calculateAccountBalanceValue(updatedAccount ?? account, prices),
|
||||
[updatedAccount, account, prices],
|
||||
)
|
||||
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalanceValue)
|
||||
const leverage = useMemo(
|
||||
() => calculateAccountLeverage(updatedAccount ? updatedAccount : account, prices),
|
||||
() => calculateAccountLeverage(updatedAccount ?? account, prices),
|
||||
[account, updatedAccount, prices],
|
||||
)
|
||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
||||
|
@ -8,7 +8,9 @@ import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { getDisplayCurrencies } from 'utils/assets'
|
||||
import { convertToDisplayAmount } from 'utils/formatters'
|
||||
import { getCoinValue } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
|
||||
interface Props {
|
||||
coin: BNCoin
|
||||
@ -39,13 +41,27 @@ export default function DisplayCurrency(props: Props) {
|
||||
? ''
|
||||
: ` ${displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : ''}`
|
||||
|
||||
const amount = useMemo(() => {
|
||||
const coinValue = getCoinValue(props.coin, prices)
|
||||
|
||||
if (displayCurrency === ORACLE_DENOM) return coinValue.toNumber()
|
||||
|
||||
const displayDecimals = displayCurrencyAsset.decimals
|
||||
const displayPrice = getCoinValue(
|
||||
BNCoin.fromDenomAndBigNumber(displayCurrency, BN(1).shiftedBy(displayDecimals)),
|
||||
prices,
|
||||
)
|
||||
|
||||
return coinValue.div(displayPrice).toNumber()
|
||||
}, [displayCurrency, displayCurrencyAsset.decimals, prices, props.coin])
|
||||
|
||||
return (
|
||||
<FormattedNumber
|
||||
className={classNames(
|
||||
props.className,
|
||||
props.parentheses && 'before:content-["("] after:content-[")"]',
|
||||
)}
|
||||
amount={convertToDisplayAmount(props.coin, displayCurrency, prices).toNumber()}
|
||||
amount={amount}
|
||||
options={{
|
||||
minDecimals: isUSD ? 2 : 0,
|
||||
maxDecimals: 2,
|
||||
|
@ -6,7 +6,7 @@ import useVaults from 'hooks/useVaults'
|
||||
|
||||
function Content() {
|
||||
const { data: vaults } = useVaults()
|
||||
|
||||
if (!vaults) return null
|
||||
const featuredVaults = vaults.filter((vault) => vault.isFeatured)
|
||||
|
||||
if (!featuredVaults.length) return null
|
||||
@ -14,7 +14,7 @@ function Content() {
|
||||
return (
|
||||
<Card
|
||||
title='Featured vaults'
|
||||
className='mb-4 h-fit w-full bg-white/5'
|
||||
className='w-full mb-4 h-fit bg-white/5'
|
||||
contentClassName='grid grid-cols-3'
|
||||
>
|
||||
{featuredVaults.map((vault) => (
|
||||
|
@ -5,11 +5,11 @@ import Card from 'components/Card'
|
||||
import { VaultTable } from 'components/Earn/Farm/VaultTable'
|
||||
import VaultUnlockBanner from 'components/Earn/Farm/VaultUnlockBanner'
|
||||
import { IS_TESTNET } from 'constants/env'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
|
||||
import useDepositedVaults from 'hooks/useDepositedVaults'
|
||||
import useVaults from 'hooks/useVaults'
|
||||
import { VaultStatus } from 'types/enums/vault'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
|
||||
interface Props {
|
||||
type: 'available' | 'deposited'
|
||||
@ -26,6 +26,7 @@ function Content(props: Props) {
|
||||
const { deposited, available } = useMemo(() => {
|
||||
return vaultsMetaData.reduce(
|
||||
(prev: { deposited: DepositedVault[]; available: Vault[] }, curr) => {
|
||||
if (!vaults) return prev
|
||||
const vault = vaults.find((vault) => vault.address === curr.address)
|
||||
const depositedVault = depositedVaults?.find((vault) => vault.address === curr.address)
|
||||
|
||||
@ -59,7 +60,7 @@ function Content(props: Props) {
|
||||
<>
|
||||
{!isAvailable && <VaultUnlockBanner vaults={unlockedVaults} />}
|
||||
<Card
|
||||
className='h-fit w-full bg-white/5'
|
||||
className='w-full h-fit bg-white/5'
|
||||
title={isAvailable ? 'Available vaults' : 'Deposited'}
|
||||
>
|
||||
<VaultTable data={vaultsToDisplay} />
|
||||
@ -85,7 +86,7 @@ function Fallback() {
|
||||
}))
|
||||
|
||||
return (
|
||||
<Card className='h-fit w-full bg-white/5' title='Available vaults'>
|
||||
<Card className='w-full h-fit bg-white/5' title='Available vaults'>
|
||||
<VaultTable data={mockVaults} isLoading />
|
||||
</Card>
|
||||
)
|
||||
|
@ -9,10 +9,12 @@ import AssetListTable from 'components/MarketAssetTable'
|
||||
import MarketAssetTableRow from 'components/MarketAssetTable/MarketAssetTableRow'
|
||||
import MarketDetails from 'components/MarketAssetTable/MarketDetails'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import useDisplayCurrencyPrice from 'hooks/useDisplayCurrencyPrice'
|
||||
import { convertLiquidityRateToAPR, demagnify } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
import { BN_ZERO } from '../../../constants/math'
|
||||
import AmountAndValue from '../../AmountAndValue'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
data: LendingMarketTableData[]
|
||||
@ -20,7 +22,6 @@ interface Props {
|
||||
|
||||
export default function LendingMarketsTable(props: Props) {
|
||||
const { title, data } = props
|
||||
const { symbol: displayCurrencySymbol } = useDisplayCurrencyPrice()
|
||||
const shouldShowAccountDeposit = !!data[0]?.accountLentValue
|
||||
|
||||
const rowRenderer = useCallback(
|
||||
@ -49,12 +50,12 @@ export default function LendingMarketsTable(props: Props) {
|
||||
const asset = row.original.asset
|
||||
|
||||
return (
|
||||
<div className='flex flex-1 items-center gap-3'>
|
||||
<div className='flex items-center flex-1 gap-3'>
|
||||
<AssetImage asset={asset} size={32} />
|
||||
<TitleAndSubCell
|
||||
title={asset.symbol}
|
||||
sub={asset.name}
|
||||
className='min-w-15 text-left'
|
||||
className='text-left min-w-15'
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
@ -66,14 +67,12 @@ export default function LendingMarketsTable(props: Props) {
|
||||
accessorKey: 'accountDepositValue',
|
||||
header: 'Deposited',
|
||||
cell: ({ row }) => {
|
||||
const accountDepositValue = row.original.accountLentValue as BigNumber
|
||||
const amount = row.original.accountLentAmount
|
||||
|
||||
return (
|
||||
<FormattedNumber
|
||||
className='text-xs'
|
||||
animate
|
||||
amount={accountDepositValue.toNumber()}
|
||||
options={{ suffix: ` ${displayCurrencySymbol}` }}
|
||||
<AmountAndValue
|
||||
asset={row.original.asset}
|
||||
amount={amount ? BN(amount) : BN_ZERO}
|
||||
/>
|
||||
)
|
||||
},
|
||||
@ -135,7 +134,7 @@ export default function LendingMarketsTable(props: Props) {
|
||||
),
|
||||
},
|
||||
],
|
||||
[displayCurrencySymbol, shouldShowAccountDeposit],
|
||||
[shouldShowAccountDeposit],
|
||||
)
|
||||
|
||||
return <AssetListTable title={title} rowRenderer={rowRenderer} columns={columns} data={data} />
|
||||
|
@ -12,6 +12,7 @@ interface Props {
|
||||
options?: FormatOptions
|
||||
className?: string
|
||||
animate?: boolean
|
||||
parentheses?: boolean
|
||||
}
|
||||
|
||||
export const FormattedNumber = React.memo(
|
||||
@ -39,13 +40,25 @@ export const FormattedNumber = React.memo(
|
||||
reduceMotion
|
||||
)
|
||||
return (
|
||||
<p className={classNames('number', props.className)}>
|
||||
<p
|
||||
className={classNames(
|
||||
'number',
|
||||
props.parentheses && 'before:content-["("] after:content-[")"]',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
{formatValue(props.amount.toString(), props.options)}
|
||||
</p>
|
||||
)
|
||||
|
||||
return (
|
||||
<animated.p className={classNames('number', props.className)}>
|
||||
<animated.p
|
||||
className={classNames(
|
||||
'number',
|
||||
props.parentheses && 'before:content-["("] after:content-[")"]',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
{springAmount.number.to((num) => formatValue(num, props.options))}
|
||||
</animated.p>
|
||||
)
|
||||
|
@ -133,7 +133,7 @@ export default function AssetSelectTable(props: Props) {
|
||||
<td
|
||||
key={cell.id}
|
||||
className={classNames(
|
||||
cell.column.id === 'select' ? `` : 'pl-4 text-right',
|
||||
cell.column.id === 'select' ? `` : 'text-right',
|
||||
'px-4 py-3',
|
||||
)}
|
||||
>
|
||||
|
@ -20,7 +20,7 @@ import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import { getDepositsAndLendsAfterCoinSpent } from 'hooks/useUpdatedAccount/functions'
|
||||
import { getDepositAndLendCoinsToSpend } from 'hooks/useUpdatedAccount/functions'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
@ -77,7 +77,7 @@ function BorrowModal(props: Props) {
|
||||
if (!asset) return
|
||||
setIsConfirming(true)
|
||||
let result
|
||||
const { lends } = getDepositsAndLendsAfterCoinSpent(
|
||||
const { lend } = getDepositAndLendCoinsToSpend(
|
||||
BNCoin.fromDenomAndBigNumber(asset.denom, amount),
|
||||
account,
|
||||
)
|
||||
@ -85,8 +85,8 @@ function BorrowModal(props: Props) {
|
||||
result = await repay({
|
||||
accountId: account.id,
|
||||
coin: BNCoin.fromDenomAndBigNumber(asset.denom, amount),
|
||||
accountBalance: max.isEqualTo(amount),
|
||||
lends,
|
||||
accountBalance: percentage === 100,
|
||||
lend,
|
||||
})
|
||||
} else {
|
||||
result = await borrow({
|
||||
|
@ -14,7 +14,7 @@ import useToggle from 'hooks/useToggle'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { cloneAccount, getMergedBalances, removeDepositsAndLends } from 'utils/accounts'
|
||||
import { cloneAccount, getMergedBalancesForAsset, removeDepositsAndLends } from 'utils/accounts'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
|
||||
@ -36,7 +36,7 @@ export default function WithdrawFromAccount(props: Props) {
|
||||
const accountClone = cloneAccount(account)
|
||||
const borrowAccount = removeDepositsAndLends(accountClone, currentAsset.denom)
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(borrowAccount)
|
||||
const balances = getMergedBalances(account, getEnabledMarketAssets())
|
||||
const balances = getMergedBalancesForAsset(account, getEnabledMarketAssets())
|
||||
const maxWithdrawAmount = computeMaxWithdrawAmount(currentAsset.denom)
|
||||
const maxWithdrawWithBorrowAmount = computeMaxBorrowAmount(currentAsset.denom, 'wallet').plus(
|
||||
maxWithdrawAmount,
|
||||
|
@ -19,6 +19,8 @@ import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.ty
|
||||
import { byDenom } from 'utils/array'
|
||||
import { findCoinByDenom, getAssetByDenom } from 'utils/assets'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { getValueFromBNCoins, mergeBNCoinArrays } from 'utils/helpers'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
|
||||
export interface VaultBorrowingsProps {
|
||||
borrowings: BNCoin[]
|
||||
@ -28,18 +30,29 @@ export interface VaultBorrowingsProps {
|
||||
vault: Vault
|
||||
depositActions: Action[]
|
||||
onChangeBorrowings: (borrowings: BNCoin[]) => void
|
||||
displayCurrency: string
|
||||
depositCapReachedCoins: BNCoin[]
|
||||
}
|
||||
|
||||
export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
const { data: marketAssets } = useMarketAssets()
|
||||
const { data: prices } = usePrices()
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const vaultModal = useStore((s) => s.vaultModal)
|
||||
const depositIntoVault = useStore((s) => s.depositIntoVault)
|
||||
const [isConfirming, setIsConfirming] = useState(false)
|
||||
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||
const { computeMaxBorrowAmount } = useHealthComputer(updatedAccount)
|
||||
const [percentage, setPercentage] = useState<number>(0)
|
||||
|
||||
const calculateSliderPercentage = (maxBorrowAmounts: BNCoin[], borrowings: BNCoin[]) => {
|
||||
if (borrowings.length === 1) {
|
||||
const amount = borrowings[0].amount
|
||||
if (amount.isZero()) return 0
|
||||
const max = maxBorrowAmounts.find(byDenom(borrowings[0].denom))?.amount || BN_ZERO
|
||||
return amount.times(100).dividedBy(max).toNumber()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
const maxBorrowAmounts: BNCoin[] = useMemo(() => {
|
||||
return props.borrowings.map((borrowing) => {
|
||||
@ -53,25 +66,10 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
})
|
||||
}, [props.borrowings, computeMaxBorrowAmount, props.vault.address])
|
||||
|
||||
const borrowingValue = useMemo(() => {
|
||||
return props.borrowings.reduce((prev, curr) => {
|
||||
const price = prices.find((price) => price.denom === curr.denom)?.amount
|
||||
if (!price) return prev
|
||||
|
||||
return prev.plus(curr.amount.multipliedBy(price))
|
||||
}, BN_ZERO as BigNumber)
|
||||
}, [props.borrowings, prices])
|
||||
|
||||
const totalValue = useMemo(() => {
|
||||
const depositValue = props.deposits.reduce((prev, curr) => {
|
||||
const price = prices.find((price) => price.denom === curr.denom)?.amount
|
||||
if (!price) return prev
|
||||
const value = curr.amount.multipliedBy(price)
|
||||
return prev.plus(value)
|
||||
}, BN_ZERO as BigNumber)
|
||||
|
||||
return depositValue.plus(borrowingValue)
|
||||
}, [props.deposits, borrowingValue, prices])
|
||||
const totalValue = useMemo(
|
||||
() => getValueFromBNCoins(mergeBNCoinArrays(props.deposits, props.borrowings), prices),
|
||||
[props.borrowings, props.deposits, prices],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const selectedBorrowDenoms = vaultModal?.selectedBorrowDenoms || []
|
||||
@ -81,25 +79,24 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const updatedBorrowings = selectedBorrowDenoms.map((denom) => {
|
||||
const amount = findCoinByDenom(denom, props.borrowings)?.amount || BN_ZERO
|
||||
|
||||
return new BNCoin({
|
||||
denom,
|
||||
amount: amount.toString(),
|
||||
})
|
||||
})
|
||||
props.onChangeBorrowings(updatedBorrowings)
|
||||
}, [vaultModal, props])
|
||||
|
||||
const [percentage, setPercentage] = useState<number>(0)
|
||||
setPercentage(calculateSliderPercentage(maxBorrowAmounts, updatedBorrowings))
|
||||
}, [vaultModal, props, maxBorrowAmounts])
|
||||
|
||||
function onChangeSlider(value: number) {
|
||||
if (props.borrowings.length !== 1) return
|
||||
|
||||
const denom = props.borrowings[0].denom
|
||||
const currentAmount = props.borrowings[0].amount
|
||||
const maxAmount = maxBorrowAmounts.find((coin) => coin.denom === denom)?.amount ?? BN_ZERO
|
||||
const maxAmount = maxBorrowAmounts.find(byDenom(denom))?.amount ?? BN_ZERO
|
||||
const newBorrowings: BNCoin[] = [
|
||||
new BNCoin({
|
||||
denom,
|
||||
@ -123,7 +120,8 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
function onDelete(denom: string) {
|
||||
const index = props.borrowings.findIndex((coin) => coin.denom === denom)
|
||||
props.borrowings.splice(index, 1)
|
||||
props.onChangeBorrowings([...props.borrowings])
|
||||
const newBorrowings = [...props.borrowings]
|
||||
props.onChangeBorrowings(newBorrowings)
|
||||
if (!vaultModal) return
|
||||
|
||||
useStore.setState({
|
||||
@ -132,6 +130,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
selectedBorrowDenoms: props.borrowings.map((coin) => coin.denom),
|
||||
},
|
||||
})
|
||||
setPercentage(calculateSliderPercentage(maxBorrowAmounts, newBorrowings))
|
||||
}
|
||||
|
||||
function addAsset() {
|
||||
@ -140,6 +139,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
selectedDenoms: props.borrowings.map((coin) => coin.denom),
|
||||
},
|
||||
})
|
||||
setPercentage(calculateSliderPercentage(maxBorrowAmounts, props.borrowings))
|
||||
}
|
||||
|
||||
async function onConfirm() {
|
||||
@ -209,7 +209,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
||||
<div className='flex justify-between'>
|
||||
<Text className='text-white/50'>{`${props.primaryAsset.symbol}-${props.secondaryAsset.symbol} Position Value`}</Text>
|
||||
<DisplayCurrency
|
||||
coin={new BNCoin({ denom: baseCurrency.denom, amount: totalValue.toString() })}
|
||||
coin={new BNCoin({ denom: ORACLE_DENOM, amount: totalValue.toString() })}
|
||||
/>
|
||||
</div>
|
||||
{props.borrowings.map((coin) => {
|
||||
|
@ -1,47 +1,60 @@
|
||||
import classNames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatAmountWithSymbol } from 'utils/formatters'
|
||||
import Text from 'components/Text'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatAmountWithSymbol, getCoinValue } from 'utils/formatters'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
|
||||
interface Props {
|
||||
borrowings: BNCoin[]
|
||||
displayCurrency: string
|
||||
}
|
||||
|
||||
export default function VaultDepositSubTitle(props: Props) {
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
export default function VaultBorrowingsSubTitle(props: Props) {
|
||||
const { data: prices } = usePrices()
|
||||
|
||||
const [borrowingTexts, borrowingValue] = useMemo(() => {
|
||||
const texts: string[] = []
|
||||
const borrowingValue = useMemo(() => {
|
||||
let borrowingValue = BN_ZERO
|
||||
props.borrowings.map((coin) => {
|
||||
const price = prices.find((p) => p.denom === coin.denom)?.amount
|
||||
if (!price || coin.amount.isZero()) return
|
||||
borrowingValue = borrowingValue.plus(coin.amount.multipliedBy(price))
|
||||
texts.push(
|
||||
formatAmountWithSymbol({
|
||||
denom: coin.denom,
|
||||
amount: coin.amount.toString(),
|
||||
}),
|
||||
)
|
||||
borrowingValue = getCoinValue(coin, prices)
|
||||
})
|
||||
return [texts, borrowingValue]
|
||||
return borrowingValue
|
||||
}, [props.borrowings, prices])
|
||||
|
||||
const borrowingTexts = useMemo(
|
||||
() =>
|
||||
props.borrowings.map((borrowing, index) => (
|
||||
<Text
|
||||
key={index}
|
||||
size='xs'
|
||||
className={classNames(
|
||||
'inline mt-1 text-white/60',
|
||||
index !== 0 && 'ml-1 before:pr-1 before:content-["+"]',
|
||||
)}
|
||||
>
|
||||
{formatAmountWithSymbol(borrowing.toCoin())}
|
||||
</Text>
|
||||
)),
|
||||
[props.borrowings],
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
{borrowingTexts.join(' + ')}
|
||||
{borrowingTexts.length > 0 && (
|
||||
<>
|
||||
{` = `}
|
||||
<DisplayCurrency
|
||||
coin={new BNCoin({ denom: baseCurrency.denom, amount: borrowingValue.toString() })}
|
||||
/>
|
||||
</>
|
||||
{props.borrowings.length > 0 && borrowingTexts}
|
||||
{props.borrowings.length > 0 && (
|
||||
<DisplayCurrency
|
||||
className={classNames(
|
||||
'text-xs mt-1 text-white/60 ml-1 inline',
|
||||
'before:content-["="] before:pr-1',
|
||||
)}
|
||||
coin={new BNCoin({ denom: ORACLE_DENOM, amount: borrowingValue.toString() })}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
@ -1,8 +1,9 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import Button from 'components/Button'
|
||||
import DepositCapMessage from 'components/DepositCapMessage'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import Divider from 'components/Divider'
|
||||
import { Gauge } from 'components/Gauge'
|
||||
import { ArrowRight, ExclamationMarkCircled } from 'components/Icons'
|
||||
@ -10,14 +11,14 @@ import Slider from 'components/Slider'
|
||||
import Switch from 'components/Switch'
|
||||
import Text from 'components/Text'
|
||||
import TokenInput from 'components/TokenInput'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import usePrice from 'hooks/usePrice'
|
||||
import { useMemo, useState } from 'react'
|
||||
import useStore from 'store'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { accumulateAmounts } from 'utils/accounts'
|
||||
import { findCoinByDenom } from 'utils/assets'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { BN, getValueFromBNCoins } from 'utils/helpers'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
|
||||
interface Props {
|
||||
deposits: BNCoin[]
|
||||
@ -28,13 +29,14 @@ interface Props {
|
||||
onChangeDeposits: (deposits: BNCoin[]) => void
|
||||
onChangeIsCustomRatio: (isCustomRatio: boolean) => void
|
||||
toggleOpen: (index: number) => void
|
||||
displayCurrency: string
|
||||
depositCapReachedCoins: BNCoin[]
|
||||
}
|
||||
|
||||
export default function VaultDeposit(props: Props) {
|
||||
const { deposits, primaryAsset, secondaryAsset, account, onChangeDeposits } = props
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
|
||||
const { deposits, primaryAsset, secondaryAsset, account, onChangeDeposits, displayCurrency } =
|
||||
props
|
||||
const displayCurrencyAsset = ASSETS.find(byDenom(displayCurrency)) ?? ASSETS[0]
|
||||
const [availablePrimaryAmount, availableSecondaryAmount] = useMemo(
|
||||
() => [
|
||||
accumulateAmounts(primaryAsset.denom, [...account.deposits, ...account.lends]),
|
||||
@ -42,37 +44,35 @@ export default function VaultDeposit(props: Props) {
|
||||
],
|
||||
[account.deposits, account.lends, primaryAsset.denom, secondaryAsset.denom],
|
||||
)
|
||||
|
||||
const primaryPrice = usePrice(primaryAsset.denom)
|
||||
const secondaryPrice = usePrice(secondaryAsset.denom)
|
||||
const { data: prices } = usePrices()
|
||||
const primaryPrice = prices.find(byDenom(primaryAsset.denom))?.amount ?? BN_ZERO
|
||||
const secondaryPrice = prices.find(byDenom(secondaryAsset.denom))?.amount ?? BN_ZERO
|
||||
|
||||
const primaryCoin = useMemo(() => {
|
||||
const amount = findCoinByDenom(primaryAsset.denom, deposits)?.amount.toString() || '0'
|
||||
return new BNCoin({ denom: primaryAsset.denom, amount })
|
||||
const amount = deposits.find(byDenom(primaryAsset.denom))?.amount ?? BN_ZERO
|
||||
return new BNCoin({ denom: primaryAsset.denom, amount: amount.toString() })
|
||||
}, [deposits, primaryAsset.denom])
|
||||
|
||||
const secondaryCoin = useMemo(() => {
|
||||
const amount = findCoinByDenom(secondaryAsset.denom, deposits)?.amount.toString() || '0'
|
||||
return new BNCoin({ denom: secondaryAsset.denom, amount })
|
||||
const amount = deposits.find(byDenom(secondaryAsset.denom))?.amount ?? BN_ZERO
|
||||
return new BNCoin({ denom: secondaryAsset.denom, amount: amount.toString() })
|
||||
}, [deposits, secondaryAsset.denom])
|
||||
|
||||
const primaryValue = useMemo(
|
||||
() => primaryCoin.amount.multipliedBy(primaryPrice),
|
||||
[primaryCoin, primaryPrice],
|
||||
)
|
||||
const secondaryValue = useMemo(
|
||||
() => secondaryCoin.amount.multipliedBy(secondaryPrice),
|
||||
[secondaryCoin, secondaryPrice],
|
||||
() => getValueFromBNCoins([primaryCoin], prices),
|
||||
[primaryCoin, prices],
|
||||
)
|
||||
|
||||
const totalValue = useMemo(
|
||||
() => primaryValue.plus(secondaryValue),
|
||||
[primaryValue, secondaryValue],
|
||||
() => getValueFromBNCoins([primaryCoin, secondaryCoin], prices),
|
||||
[primaryCoin, secondaryCoin, prices],
|
||||
)
|
||||
|
||||
const primaryValuePercentage = useMemo(() => {
|
||||
const value = primaryValue.dividedBy(totalValue).multipliedBy(100).decimalPlaces(2).toNumber()
|
||||
return isNaN(value) ? 50 : value
|
||||
}, [primaryValue, totalValue])
|
||||
|
||||
const secondaryValuePercentage = useMemo(
|
||||
() => new BigNumber(100).minus(primaryValuePercentage).integerValue(2).toNumber() ?? 50,
|
||||
[primaryValuePercentage],
|
||||
@ -237,9 +237,7 @@ export default function VaultDeposit(props: Props) {
|
||||
</div>
|
||||
<div className='flex justify-between'>
|
||||
<Text className='text-white/50'>{`${primaryAsset.symbol}-${secondaryAsset.symbol} Deposit Value`}</Text>
|
||||
<DisplayCurrency
|
||||
coin={new BNCoin({ denom: baseCurrency.denom, amount: totalValue.toString() })}
|
||||
/>
|
||||
<DisplayCurrency coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, totalValue)} />
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => props.toggleOpen(1)}
|
||||
@ -250,4 +248,4 @@ export default function VaultDeposit(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,56 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import classNames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import usePrice from 'hooks/usePrice'
|
||||
import useStore from 'store'
|
||||
import Text from 'components/Text'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { formatAmountWithSymbol } from 'utils/formatters'
|
||||
import { getValueFromBNCoins } from 'utils/helpers'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
|
||||
interface Props {
|
||||
primaryAmount: BigNumber
|
||||
secondaryAmount: BigNumber
|
||||
primaryAsset: Asset
|
||||
secondaryAsset: Asset
|
||||
displayCurrency: string
|
||||
}
|
||||
|
||||
export default function VaultDepositSubTitle(props: Props) {
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const primaryPrice = usePrice(props.primaryAsset.denom)
|
||||
const secondaryPrice = usePrice(props.secondaryAsset.denom)
|
||||
const primaryText = formatAmountWithSymbol({
|
||||
denom: props.primaryAsset.denom,
|
||||
amount: props.primaryAmount.toString(),
|
||||
})
|
||||
const secondaryText = formatAmountWithSymbol({
|
||||
denom: props.secondaryAsset.denom,
|
||||
amount: props.secondaryAmount.toString(),
|
||||
})
|
||||
const { data: prices } = usePrices()
|
||||
const primaryText = useMemo(
|
||||
() => (
|
||||
<Text size='xs' className='inline mt-1 text-white/60'>
|
||||
{formatAmountWithSymbol({
|
||||
denom: props.primaryAsset.denom,
|
||||
amount: props.primaryAmount.toString(),
|
||||
})}
|
||||
</Text>
|
||||
),
|
||||
[props.primaryAmount, props.primaryAsset.denom],
|
||||
)
|
||||
|
||||
const positionValue = props.primaryAmount
|
||||
.multipliedBy(primaryPrice)
|
||||
.plus(props.secondaryAmount.multipliedBy(secondaryPrice))
|
||||
.toNumber()
|
||||
const secondaryText = useMemo(
|
||||
() => (
|
||||
<Text size='xs' className='inline mt-1 text-white/60 ml-1 before:pr-1 before:content-["+"]'>
|
||||
{formatAmountWithSymbol({
|
||||
denom: props.secondaryAsset.denom,
|
||||
amount: props.secondaryAmount.toString(),
|
||||
})}
|
||||
</Text>
|
||||
),
|
||||
[props.secondaryAmount, props.secondaryAsset.denom],
|
||||
)
|
||||
|
||||
const positionValue = getValueFromBNCoins(
|
||||
[
|
||||
BNCoin.fromDenomAndBigNumber(props.primaryAsset.denom, props.primaryAmount),
|
||||
BNCoin.fromDenomAndBigNumber(props.secondaryAsset.denom, props.secondaryAmount),
|
||||
],
|
||||
prices,
|
||||
)
|
||||
|
||||
const showPrimaryText = !props.primaryAmount.isZero()
|
||||
const showSecondaryText = !props.secondaryAmount.isZero()
|
||||
@ -37,15 +58,15 @@ export default function VaultDepositSubTitle(props: Props) {
|
||||
return (
|
||||
<>
|
||||
{showPrimaryText && primaryText}
|
||||
{showPrimaryText && showSecondaryText && ' + '}
|
||||
{showSecondaryText && secondaryText}
|
||||
{(showPrimaryText || showSecondaryText) && (
|
||||
<>
|
||||
{` = `}
|
||||
<DisplayCurrency
|
||||
coin={new BNCoin({ denom: baseCurrency.denom, amount: positionValue.toString() })}
|
||||
/>
|
||||
</>
|
||||
<DisplayCurrency
|
||||
className={classNames(
|
||||
'text-xs mt-1 text-white/60 ml-1 inline',
|
||||
'before:content-["="] before:pr-1',
|
||||
)}
|
||||
coin={new BNCoin({ denom: ORACLE_DENOM, amount: positionValue.toString() })}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
@ -6,16 +6,20 @@ import VaultBorrowings from 'components/Modals/Vault/VaultBorrowings'
|
||||
import VaultBorrowingsSubTitle from 'components/Modals/Vault/VaultBorrowingsSubTitle'
|
||||
import VaultDeposit from 'components/Modals/Vault/VaultDeposits'
|
||||
import VaultDepositSubTitle from 'components/Modals/Vault/VaultDepositsSubTitle'
|
||||
import Text from 'components/Text'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||
import useDisplayAsset from 'hooks/useDisplayAsset'
|
||||
import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { convertToDisplayAmount, magnify } from 'utils/formatters'
|
||||
import { getCoinValue, magnify } from 'utils/formatters'
|
||||
import { getCapLeftWithBuffer } from 'utils/generic'
|
||||
import { mergeBNCoinArrays } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
vault: Vault | DepositedVault
|
||||
@ -26,17 +30,14 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function VaultModalContent(props: Props) {
|
||||
const {
|
||||
addDebts,
|
||||
removeDeposits,
|
||||
addedDebts,
|
||||
removedDeposits,
|
||||
removedLends,
|
||||
removeLends,
|
||||
addVaultValues,
|
||||
} = useUpdatedAccount(props.account)
|
||||
const { addDebts, addedDebts, removedDeposits, removedLends, simulateVaultDeposit } =
|
||||
useUpdatedAccount(props.account)
|
||||
|
||||
const { data: prices } = usePrices()
|
||||
const [displayCurrency] = useLocalStorage<string>(
|
||||
DISPLAY_CURRENCY_KEY,
|
||||
DEFAULT_SETTINGS.displayCurrency,
|
||||
)
|
||||
const [isOpen, toggleOpen] = useIsOpenArray(2, false)
|
||||
const [isCustomRatio, setIsCustomRatio] = useState(false)
|
||||
const [selectedCoins, setSelectedCoins] = useState<BNCoin[]>([])
|
||||
@ -53,9 +54,8 @@ export default function VaultModalContent(props: Props) {
|
||||
|
||||
if (totalValue.isGreaterThan(capLeft)) {
|
||||
const amount = magnify(
|
||||
convertToDisplayAmount(
|
||||
getCoinValue(
|
||||
BNCoin.fromDenomAndBigNumber(props.vault.cap.denom, capLeft),
|
||||
displayAsset.denom,
|
||||
prices,
|
||||
).toString(),
|
||||
displayAsset,
|
||||
@ -68,76 +68,58 @@ export default function VaultModalContent(props: Props) {
|
||||
|
||||
const handleDepositSelect = useCallback(
|
||||
(selectedCoins: BNCoin[]) => {
|
||||
const reclaims: BNCoin[] = []
|
||||
const deposits: BNCoin[] = []
|
||||
|
||||
selectedCoins.forEach((selectedCoin) => {
|
||||
const { denom, amount: selectedAmount } = selectedCoin
|
||||
const accountDepositForSelectedCoin: BigNumber =
|
||||
props.account.deposits.find(byDenom(denom))?.amount ?? BN_ZERO
|
||||
|
||||
if (selectedAmount.gt(accountDepositForSelectedCoin)) {
|
||||
reclaims.push(
|
||||
BNCoin.fromDenomAndBigNumber(
|
||||
denom,
|
||||
selectedAmount.minus(accountDepositForSelectedCoin),
|
||||
),
|
||||
)
|
||||
deposits.push(BNCoin.fromDenomAndBigNumber(denom, accountDepositForSelectedCoin))
|
||||
} else {
|
||||
deposits.push(selectedCoin)
|
||||
}
|
||||
})
|
||||
|
||||
removeLends(reclaims)
|
||||
removeDeposits(deposits)
|
||||
simulateVaultDeposit(props.vault.address, selectedCoins)
|
||||
setSelectedCoins(selectedCoins)
|
||||
},
|
||||
[props.account.deposits, removeDeposits, removeLends],
|
||||
[props.vault.address, simulateVaultDeposit],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
addVaultValues([
|
||||
{
|
||||
address: props.vault.address,
|
||||
value: totalValue,
|
||||
},
|
||||
])
|
||||
}, [totalValue, addVaultValues, props.vault.address])
|
||||
|
||||
const onChangeIsCustomRatio = useCallback(
|
||||
(isCustomRatio: boolean) => setIsCustomRatio(isCustomRatio),
|
||||
[setIsCustomRatio],
|
||||
)
|
||||
|
||||
const deposits = useMemo(
|
||||
() => mergeBNCoinArrays(removedDeposits, removedLends),
|
||||
[removedDeposits, removedLends],
|
||||
)
|
||||
|
||||
function getDepositSubTitle() {
|
||||
if (isOpen[0] && props.isDeposited)
|
||||
return 'The amounts you enter below will be added to your current position.'
|
||||
return (
|
||||
<Text size='xs' className='mt-1 text-white/60'>
|
||||
The amounts you enter below will be added to your current position.
|
||||
</Text>
|
||||
)
|
||||
|
||||
if (isOpen[0]) return null
|
||||
|
||||
return (
|
||||
<VaultDepositSubTitle
|
||||
primaryAmount={
|
||||
removedDeposits.find((coin) => coin.denom === props.primaryAsset.denom)?.amount || BN_ZERO
|
||||
deposits.find((coin) => coin.denom === props.primaryAsset.denom)?.amount || BN_ZERO
|
||||
}
|
||||
secondaryAmount={
|
||||
removedDeposits.find((coin) => coin.denom === props.secondaryAsset.denom)?.amount ||
|
||||
BN_ZERO
|
||||
deposits.find((coin) => coin.denom === props.secondaryAsset.denom)?.amount || BN_ZERO
|
||||
}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
displayCurrency={displayCurrency}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function getBorrowingsSubTitle() {
|
||||
if (isOpen[1] && props.isDeposited)
|
||||
return 'The amounts you enter below will be added to your current position.'
|
||||
return (
|
||||
<Text size='xs' className='mt-1 text-white/60'>
|
||||
The amounts you enter below will be added to your current position.
|
||||
</Text>
|
||||
)
|
||||
|
||||
if (isOpen[1]) return null
|
||||
|
||||
return <VaultBorrowingsSubTitle borrowings={addedDebts} />
|
||||
return <VaultBorrowingsSubTitle borrowings={addedDebts} displayCurrency={displayCurrency} />
|
||||
}
|
||||
|
||||
return (
|
||||
@ -156,6 +138,7 @@ export default function VaultModalContent(props: Props) {
|
||||
toggleOpen={toggleOpen}
|
||||
isCustomRatio={isCustomRatio}
|
||||
onChangeIsCustomRatio={onChangeIsCustomRatio}
|
||||
displayCurrency={displayCurrency}
|
||||
depositCapReachedCoins={depositCapReachedCoins}
|
||||
/>
|
||||
),
|
||||
@ -168,13 +151,14 @@ export default function VaultModalContent(props: Props) {
|
||||
renderContent: () => (
|
||||
<VaultBorrowings
|
||||
borrowings={addedDebts}
|
||||
deposits={removedDeposits}
|
||||
deposits={deposits}
|
||||
primaryAsset={props.primaryAsset}
|
||||
secondaryAsset={props.secondaryAsset}
|
||||
onChangeBorrowings={addDebts}
|
||||
vault={props.vault}
|
||||
depositActions={depositActions}
|
||||
depositCapReachedCoins={depositCapReachedCoins}
|
||||
displayCurrency={displayCurrency}
|
||||
/>
|
||||
),
|
||||
title: 'Borrow',
|
||||
|
@ -4,8 +4,8 @@ import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { PRICE_ORACLE_DECIMALS } from 'constants/query'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
@ -28,7 +28,7 @@ export default function VaultModalContentHeader({ vault }: Props) {
|
||||
}, [vault])
|
||||
|
||||
return (
|
||||
<div className='flex gap-6 border-b border-white/5 px-6 py-4 gradient-header'>
|
||||
<div className='flex gap-6 px-6 py-4 border-b border-white/5 gradient-header'>
|
||||
{vault.apy && (
|
||||
<>
|
||||
<TitleAndSubCell
|
||||
@ -39,14 +39,13 @@ export default function VaultModalContentHeader({ vault }: Props) {
|
||||
options={{ suffix: '%', decimals: -2 }}
|
||||
animate
|
||||
/>
|
||||
(
|
||||
<FormattedNumber
|
||||
className='ml-2 text-xs'
|
||||
amount={vault.apy / 365}
|
||||
options={{ suffix: '%/day', decimals: -2 }}
|
||||
parentheses
|
||||
animate
|
||||
/>
|
||||
)
|
||||
</div>
|
||||
}
|
||||
sub={'Deposit APY'}
|
||||
|
@ -19,7 +19,9 @@ import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { defaultFee } from 'utils/constants'
|
||||
import { convertToDisplayAmount, formatAmountWithSymbol } from 'utils/formatters'
|
||||
import { formatAmountWithSymbol, getCoinValue } from 'utils/formatters'
|
||||
|
||||
import { ORACLE_DENOM } from '../constants/oracle'
|
||||
|
||||
const renderIncentives = (unclaimedRewards: BNCoin[]) => {
|
||||
if (unclaimedRewards.length === 0)
|
||||
@ -58,14 +60,14 @@ export default function RewardsCenter() {
|
||||
const totalRewardsCoin = useMemo(() => {
|
||||
let total = 0
|
||||
unclaimedRewards.forEach((reward) => {
|
||||
total = total + convertToDisplayAmount(reward, displayCurrency, prices).toNumber()
|
||||
total = total + getCoinValue(reward, prices).toNumber()
|
||||
})
|
||||
|
||||
return new BNCoin({
|
||||
denom: displayCurrency,
|
||||
denom: ORACLE_DENOM,
|
||||
amount: total.toString(),
|
||||
})
|
||||
}, [displayCurrency, prices, unclaimedRewards])
|
||||
}, [prices, unclaimedRewards])
|
||||
|
||||
const hasIncentives = unclaimedRewards.length > 0
|
||||
|
||||
|
@ -73,8 +73,6 @@ export default function Slider(props: Props) {
|
||||
setShowTooltip(false)
|
||||
}
|
||||
|
||||
// draggable workaround - to solve node compatibility issues
|
||||
// TODO: find a replacement for react-draggable
|
||||
const DraggableElement: any = Draggable
|
||||
|
||||
return (
|
||||
|
@ -63,7 +63,6 @@ export const MOCK_DEPOSITED_VAULT_POSITION = {
|
||||
unlocking: BN_ZERO,
|
||||
},
|
||||
status: VaultStatus.ACTIVE,
|
||||
apy: null,
|
||||
ltv: {
|
||||
liq: 0,
|
||||
max: 0,
|
||||
|
@ -4,6 +4,7 @@ import { useMemo, useState } from 'react'
|
||||
import getMinLpToReceive from 'api/vaults/getMinLpToReceive'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { SLIPPAGE_KEY } from 'constants/localStore'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
@ -13,7 +14,6 @@ import {
|
||||
getVaultDepositCoinsAndValue,
|
||||
getVaultSwapActions,
|
||||
} from 'utils/vaults'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
|
||||
interface Props {
|
||||
vault: Vault
|
||||
@ -21,6 +21,7 @@ interface Props {
|
||||
deposits: BNCoin[]
|
||||
borrowings: BNCoin[]
|
||||
}
|
||||
|
||||
export default function useDepositVault(props: Props): {
|
||||
actions: Action[]
|
||||
minLpToReceive: string
|
||||
@ -38,12 +39,16 @@ export default function useDepositVault(props: Props): {
|
||||
() => props.deposits.filter((deposit) => deposit.amount.gt(0)),
|
||||
[props.deposits],
|
||||
)
|
||||
const reclaims: BNCoin[] = useMemo(
|
||||
() => props.reclaims.filter((reclaim) => reclaim.amount.gt(0)),
|
||||
[props.reclaims],
|
||||
)
|
||||
|
||||
const debouncedGetMinLpToReceive = useMemo(() => debounce(getMinLpToReceive, 500), [])
|
||||
|
||||
const { primaryCoin, secondaryCoin, totalValue } = useMemo(
|
||||
() => getVaultDepositCoinsAndValue(props.vault, deposits, borrowings, prices),
|
||||
[deposits, borrowings, props.vault, prices],
|
||||
() => getVaultDepositCoinsAndValue(props.vault, deposits, borrowings, reclaims, prices),
|
||||
[reclaims, deposits, borrowings, props.vault, prices],
|
||||
)
|
||||
|
||||
const reclaimActions: Action[] = useMemo(() => {
|
||||
|
@ -177,7 +177,6 @@ export default function useHealthComputer(account?: Account) {
|
||||
},
|
||||
[healthComputer],
|
||||
)
|
||||
|
||||
const health = useMemo(() => {
|
||||
if (healthFactor > 10) return 100
|
||||
if (healthFactor < 0) return 0
|
||||
|
@ -40,6 +40,7 @@ export function removeCoins(coinsToRemove: BNCoin[], currentCoins: BNCoin[]) {
|
||||
export function addValueToVaults(
|
||||
vaultValues: VaultValue[],
|
||||
vaults: DepositedVault[],
|
||||
availableVaults: Vault[],
|
||||
): DepositedVault[] {
|
||||
const currentVaultAddresses = vaults.map((vault) => vault.address)
|
||||
|
||||
@ -55,10 +56,12 @@ export function addValueToVaults(
|
||||
const vaultMetaData = getVaultMetaData(vaultValue.address)
|
||||
|
||||
if (!vaultMetaData) return
|
||||
const apy = availableVaults.find((vault) => vault.address === vaultValue.address)?.apy ?? null
|
||||
|
||||
vaults.push({
|
||||
...vaultMetaData,
|
||||
...MOCK_DEPOSITED_VAULT_POSITION,
|
||||
apy,
|
||||
values: {
|
||||
primary: halfValue,
|
||||
secondary: halfValue,
|
||||
@ -70,10 +73,10 @@ export function addValueToVaults(
|
||||
return vaults
|
||||
}
|
||||
|
||||
export function getDepositsAndLendsAfterCoinSpent(coin: BNCoin, account?: Account) {
|
||||
export function getDepositAndLendCoinsToSpend(coin: BNCoin, account?: Account) {
|
||||
const makeOutput = (depositsAmount: BigNumber, lendsAmount: BigNumber) => ({
|
||||
deposits: BNCoin.fromDenomAndBigNumber(coin.denom, depositsAmount),
|
||||
lends: BNCoin.fromDenomAndBigNumber(coin.denom, lendsAmount),
|
||||
deposit: BNCoin.fromDenomAndBigNumber(coin.denom, depositsAmount),
|
||||
lend: BNCoin.fromDenomAndBigNumber(coin.denom, lendsAmount),
|
||||
})
|
||||
|
||||
if (!account) return makeOutput(BN_ZERO, BN_ZERO)
|
||||
|
@ -1,16 +1,19 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import {
|
||||
addCoins,
|
||||
addValueToVaults,
|
||||
getDepositsAndLendsAfterCoinSpent,
|
||||
getDepositAndLendCoinsToSpend,
|
||||
removeCoins,
|
||||
} from 'hooks/useUpdatedAccount/functions'
|
||||
import useVaults from 'hooks/useVaults'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { cloneAccount } from 'utils/accounts'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { getValueFromBNCoins } from 'utils/helpers'
|
||||
|
||||
export interface VaultValue {
|
||||
address: string
|
||||
@ -18,6 +21,8 @@ export interface VaultValue {
|
||||
}
|
||||
|
||||
export function useUpdatedAccount(account?: Account) {
|
||||
const { data: availableVaults } = useVaults(false)
|
||||
const { data: prices } = usePrices()
|
||||
const [updatedAccount, setUpdatedAccount] = useState<Account | undefined>(
|
||||
account ? cloneAccount(account) : undefined,
|
||||
)
|
||||
@ -84,10 +89,10 @@ export function useUpdatedAccount(account?: Account) {
|
||||
const simulateRepay = useCallback(
|
||||
(coin: BNCoin) => {
|
||||
if (!account) return
|
||||
const { deposits, lends } = getDepositsAndLendsAfterCoinSpent(coin, account)
|
||||
const { deposit, lend } = getDepositAndLendCoinsToSpend(coin, account)
|
||||
removeDebts([coin])
|
||||
removeDeposits([deposits])
|
||||
removeLends([lends])
|
||||
removeDeposits([deposit])
|
||||
removeLends([lend])
|
||||
},
|
||||
[account, removeDebts, removeDeposits, removeLends],
|
||||
)
|
||||
@ -110,10 +115,10 @@ export function useUpdatedAccount(account?: Account) {
|
||||
removeLends([])
|
||||
addDebts([])
|
||||
|
||||
const { deposits, lends } = getDepositsAndLendsAfterCoinSpent(coin, account)
|
||||
const totalBalance = deposits.amount.plus(lends.amount)
|
||||
removeDeposits([deposits])
|
||||
removeLends([lends])
|
||||
const { deposit, lend } = getDepositAndLendCoinsToSpend(coin, account)
|
||||
const totalBalance = deposit.amount.plus(lend.amount)
|
||||
removeDeposits([deposit])
|
||||
removeLends([lend])
|
||||
if (withdrawWithBorrowing) {
|
||||
addDebts([BNCoin.fromDenomAndBigNumber(coin.denom, coin.amount.minus(totalBalance))])
|
||||
}
|
||||
@ -129,10 +134,10 @@ export function useUpdatedAccount(account?: Account) {
|
||||
addDeposits([])
|
||||
addLends([])
|
||||
|
||||
const { deposits, lends } = getDepositsAndLendsAfterCoinSpent(removeCoin, account)
|
||||
const { deposit, lend } = getDepositAndLendCoinsToSpend(removeCoin, account)
|
||||
|
||||
removeDeposits([deposits])
|
||||
removeLends([lends])
|
||||
removeDeposits([deposit])
|
||||
removeLends([lend])
|
||||
if (target === 'deposit') addDeposits([addCoin])
|
||||
if (target === 'lend') addLends([addCoin])
|
||||
|
||||
@ -141,13 +146,38 @@ export function useUpdatedAccount(account?: Account) {
|
||||
[account, addDebts, addDeposits, addLends, removeDeposits, removeLends],
|
||||
)
|
||||
|
||||
const simulateVaultDeposit = useCallback(
|
||||
(address: string, coins: BNCoin[]) => {
|
||||
if (!account) return
|
||||
|
||||
const value = getValueFromBNCoins(coins, prices)
|
||||
const totalDeposits: BNCoin[] = []
|
||||
const totalLends: BNCoin[] = []
|
||||
|
||||
coins.forEach((coin) => {
|
||||
const { deposit, lend } = getDepositAndLendCoinsToSpend(coin, account)
|
||||
totalDeposits.push(deposit)
|
||||
totalLends.push(lend)
|
||||
})
|
||||
|
||||
addVaultValues([{ address, value }])
|
||||
removeDeposits(totalDeposits)
|
||||
removeLends(totalLends)
|
||||
},
|
||||
[account, prices],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!account) return
|
||||
|
||||
const accountCopy = cloneAccount(account)
|
||||
accountCopy.deposits = addCoins(addedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = addCoins(addedDebts, [...accountCopy.debts])
|
||||
accountCopy.vaults = addValueToVaults(addedVaultValues, [...accountCopy.vaults])
|
||||
accountCopy.vaults = addValueToVaults(
|
||||
addedVaultValues,
|
||||
[...accountCopy.vaults],
|
||||
availableVaults ?? [],
|
||||
)
|
||||
accountCopy.deposits = removeCoins(removedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = removeCoins(removedDebts, [...accountCopy.debts])
|
||||
accountCopy.lends = addCoins(addedLends, [...accountCopy.lends])
|
||||
@ -165,6 +195,7 @@ export function useUpdatedAccount(account?: Account) {
|
||||
addedVaultValues,
|
||||
addedLends,
|
||||
removedLends,
|
||||
availableVaults,
|
||||
])
|
||||
|
||||
return {
|
||||
@ -188,6 +219,7 @@ export function useUpdatedAccount(account?: Account) {
|
||||
simulateLending,
|
||||
simulateRepay,
|
||||
simulateTrade,
|
||||
simulateVaultDeposit,
|
||||
simulateWithdraw,
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ import useSWR from 'swr'
|
||||
|
||||
import getVaults from 'api/vaults/getVaults'
|
||||
|
||||
export default function useVaults(address?: string) {
|
||||
export default function useVaults(suspense: boolean = true, address?: string) {
|
||||
return useSWR(`vaults${address}`, () => getVaults(), {
|
||||
suspense: true,
|
||||
suspense,
|
||||
revalidateOnFocus: false,
|
||||
})
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ export default function createBroadcastSlice(
|
||||
accountId: string
|
||||
coin: BNCoin
|
||||
accountBalance?: boolean
|
||||
lends?: BNCoin
|
||||
lend?: BNCoin
|
||||
}) => {
|
||||
const actions: Action[] = [
|
||||
{
|
||||
@ -372,8 +372,8 @@ export default function createBroadcastSlice(
|
||||
},
|
||||
]
|
||||
|
||||
if (options.lends && options.lends.amount.isGreaterThan(0))
|
||||
actions.unshift({ reclaim: options.lends.toActionCoin() })
|
||||
if (options.lend && options.lend.amount.isGreaterThan(0))
|
||||
actions.unshift({ reclaim: options.lend.toActionCoin() })
|
||||
|
||||
const msg: CreditManagerExecuteMsg = {
|
||||
update_credit_account: {
|
||||
|
2
src/types/interfaces/store/broadcast.d.ts
vendored
2
src/types/interfaces/store/broadcast.d.ts
vendored
@ -29,7 +29,7 @@ interface BroadcastSlice {
|
||||
accountId: string
|
||||
coin: BNCoin
|
||||
accountBalance?: boolean
|
||||
lends?: BNCoin
|
||||
lend?: BNCoin
|
||||
}) => Promise<boolean>
|
||||
swap: (options: {
|
||||
accountId: string
|
||||
|
@ -45,7 +45,7 @@ export const calculateAccountValue = (
|
||||
acc.plus(vaultPosition.values.primary).plus(vaultPosition.values.secondary),
|
||||
BN_ZERO,
|
||||
) || BN_ZERO
|
||||
).shiftedBy(-6)
|
||||
)
|
||||
}
|
||||
|
||||
return account[type]?.reduce((acc, position) => {
|
||||
@ -85,13 +85,8 @@ export const calculateAccountApr = (
|
||||
})
|
||||
|
||||
vaults?.forEach((vault) => {
|
||||
const asset = getAssetByDenom(vault.denoms.lp)
|
||||
if (!asset) return BN_ZERO
|
||||
const price = prices.find(byDenom(vault.denoms.lp))?.amount ?? 0
|
||||
const amount = BN(vault.amounts.locked).shiftedBy(-asset.decimals)
|
||||
const positionInterest = amount
|
||||
.multipliedBy(price)
|
||||
.multipliedBy(convertApyToApr(vault?.apy ?? 0, 365))
|
||||
const vaultValue = vault.values.primary.plus(vault.values.secondary)
|
||||
const positionInterest = vaultValue.multipliedBy(convertApyToApr(vault?.apy ?? 0, 365))
|
||||
totalVaultsInterestValue = totalVaultsInterestValue.plus(positionInterest)
|
||||
})
|
||||
|
||||
@ -219,7 +214,7 @@ export function removeDepositsAndLends(account: Account, denom: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMergedBalances(account: Account, assets: Asset[]) {
|
||||
export function getMergedBalancesForAsset(account: Account, assets: Asset[]) {
|
||||
const balances: BNCoin[] = []
|
||||
assets.forEach((asset) => {
|
||||
const balance = accumulateAmounts(asset.denom, [...account.deposits, ...account.lends])
|
||||
|
@ -177,16 +177,14 @@ export function demagnify(amount: number | string | BigNumber, asset: Asset | Ps
|
||||
return value.isZero() ? 0 : value.shiftedBy(-1 * asset.decimals).toNumber()
|
||||
}
|
||||
|
||||
export function convertToDisplayAmount(coin: BNCoin, displayCurrency: string, prices: BNCoin[]) {
|
||||
const price = prices.find((price) => price.denom === coin.denom)
|
||||
export function getCoinValue(coin: BNCoin, prices: BNCoin[]) {
|
||||
const asset = getAllAssets().find((asset) => asset.denom === coin.denom)
|
||||
const displayPrice = prices.find((price) => price.denom === displayCurrency)
|
||||
const coinPrice = prices.find((price) => price.denom === coin.denom)
|
||||
|
||||
if (!price || !displayPrice || !asset) return BN_ZERO
|
||||
if (!coinPrice || !asset) return BN_ZERO
|
||||
|
||||
const decimals = asset.denom === ORACLE_DENOM ? 0 : asset.decimals * -1
|
||||
|
||||
return coin.amount.shiftedBy(decimals).multipliedBy(price.amount).dividedBy(displayPrice.amount)
|
||||
return coin.amount.shiftedBy(decimals).multipliedBy(coinPrice.amount)
|
||||
}
|
||||
|
||||
export function convertLiquidityRateToAPR(rate: number) {
|
||||
|
@ -1,7 +1,12 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import throttle from 'lodash.throttle'
|
||||
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { getCoinValue } from 'utils/formatters'
|
||||
|
||||
BigNumber.config({ EXPONENTIAL_AT: 1e9 })
|
||||
|
||||
export function BN(n: BigNumber.Value) {
|
||||
return new BigNumber(n)
|
||||
}
|
||||
@ -23,3 +28,31 @@ export function asyncThrottle<F extends (...args: any[]) => Promise<any>>(func:
|
||||
throttled(resolve, reject, args)
|
||||
}) as ReturnType<F>
|
||||
}
|
||||
|
||||
export function mergeBNCoinArrays(array1: BNCoin[], array2: BNCoin[]) {
|
||||
const merged: BNCoin[] = []
|
||||
|
||||
array1.forEach((coin) => {
|
||||
merged.push(new BNCoin(coin.toCoin()))
|
||||
})
|
||||
|
||||
array2.forEach((coin) => {
|
||||
const index = merged.findIndex((i) => i.denom === coin.denom)
|
||||
if (index === -1) {
|
||||
merged.push(new BNCoin(coin.toCoin()))
|
||||
} else {
|
||||
merged[index].amount = merged[index].amount.plus(coin.amount)
|
||||
}
|
||||
})
|
||||
return merged
|
||||
}
|
||||
|
||||
export function getValueFromBNCoins(coins: BNCoin[], prices: BNCoin[]): BigNumber {
|
||||
let totalValue = BN_ZERO
|
||||
|
||||
coins.forEach((coin) => {
|
||||
totalValue = totalValue.plus(getCoinValue(coin, prices))
|
||||
})
|
||||
|
||||
return totalValue
|
||||
}
|
||||
|
@ -17,9 +17,8 @@ export const convertAprToApy = (apr: number, numberOfCompoundingPeriods: number)
|
||||
}
|
||||
|
||||
export const convertApyToApr = (apy: number, numberOfCompoundingPeriods: number): number => {
|
||||
return (
|
||||
(Math.pow(1 + apy / 100, numberOfCompoundingPeriods) - 1) * 100 * numberOfCompoundingPeriods
|
||||
)
|
||||
const periodicRate = (1 + apy) ** (1 / numberOfCompoundingPeriods) - 1
|
||||
return periodicRate * numberOfCompoundingPeriods
|
||||
}
|
||||
|
||||
export const combineBNCoins = (coins: BNCoin[]): BNCoin[] => {
|
||||
|
@ -1,10 +1,14 @@
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { IS_TESTNET } from 'constants/env'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { TESTNET_VAULTS_META_DATA, VAULTS_META_DATA } from 'constants/vaults'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
import { getTokenPrice, getTokenValue } from 'utils/tokens'
|
||||
|
||||
import { getValueFromBNCoins, mergeBNCoinArrays } from './helpers'
|
||||
|
||||
export function getVaultsMetaData() {
|
||||
return IS_TESTNET ? TESTNET_VAULTS_META_DATA : VAULTS_META_DATA
|
||||
}
|
||||
@ -18,23 +22,25 @@ export function getVaultDepositCoinsAndValue(
|
||||
vault: Vault,
|
||||
deposits: BNCoin[],
|
||||
borrowings: BNCoin[],
|
||||
reclaims: BNCoin[],
|
||||
prices: BNCoin[],
|
||||
) {
|
||||
const totalValue = [...deposits, ...borrowings].reduce((prev, bnCoin) => {
|
||||
const price = prices.find((coin) => coin.denom === bnCoin.denom)?.amount
|
||||
if (!price) return prev
|
||||
|
||||
return prev.plus(bnCoin.amount.multipliedBy(price))
|
||||
}, BN_ZERO)
|
||||
|
||||
const depositsAndReclaims = mergeBNCoinArrays(deposits, reclaims)
|
||||
const borrowingsAndDepositsAndReclaims = mergeBNCoinArrays(borrowings, depositsAndReclaims)
|
||||
const totalValue = getValueFromBNCoins(borrowingsAndDepositsAndReclaims, prices)
|
||||
const halfValue = totalValue.dividedBy(2)
|
||||
|
||||
const primaryAsset = getAssetByDenom(vault.denoms.primary) ?? ASSETS[0]
|
||||
const secondaryAsset = getAssetByDenom(vault.denoms.secondary) ?? ASSETS[0]
|
||||
|
||||
const primaryDepositAmount = halfValue
|
||||
.dividedBy(getTokenPrice(vault.denoms.primary, prices))
|
||||
.dividedBy(getTokenPrice(primaryAsset.denom, prices))
|
||||
.shiftedBy(primaryAsset.decimals)
|
||||
.integerValue()
|
||||
|
||||
const secondaryDepositAmount = halfValue
|
||||
.dividedBy(getTokenPrice(vault.denoms.secondary, prices))
|
||||
.dividedBy(getTokenPrice(secondaryAsset.denom, prices))
|
||||
.shiftedBy(secondaryAsset.decimals)
|
||||
.integerValue()
|
||||
|
||||
return {
|
||||
@ -46,7 +52,7 @@ export function getVaultDepositCoinsAndValue(
|
||||
denom: vault.denoms.secondary,
|
||||
amount: secondaryDepositAmount.toString(),
|
||||
}),
|
||||
totalValue: totalValue.integerValue(),
|
||||
totalValue: totalValue,
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,12 +121,14 @@ export function getVaultSwapActions(
|
||||
value = value.minus(swapValue)
|
||||
amount = amount.minus(swapAmount)
|
||||
primaryLeftoverValue = primaryLeftoverValue.minus(swapValue)
|
||||
swapActions.push(getSwapAction(bnCoin.denom, vault.denoms.primary, swapAmount, slippage))
|
||||
if (swapAmount.isGreaterThan(BN_ZERO))
|
||||
swapActions.push(getSwapAction(bnCoin.denom, vault.denoms.primary, swapAmount, slippage))
|
||||
}
|
||||
|
||||
if (secondaryLeftoverValue.isGreaterThan(0)) {
|
||||
secondaryLeftoverValue = secondaryLeftoverValue.minus(value)
|
||||
swapActions.push(getSwapAction(bnCoin.denom, vault.denoms.secondary, amount, slippage))
|
||||
if (amount.isGreaterThan(BN_ZERO))
|
||||
swapActions.push(getSwapAction(bnCoin.denom, vault.denoms.secondary, amount, slippage))
|
||||
}
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user