MP-2894: withdraw from account (#339)
This commit is contained in:
parent
103c8bed9a
commit
267b968c4a
@ -132,7 +132,7 @@ export default function AccountBalancesTable(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className='text-right text-xs'
|
className='text-right text-xs'
|
||||||
amount={Number(BN(amount).abs().toPrecision(2))}
|
amount={Number(BN(amount).abs())}
|
||||||
options={{ maxDecimals: 2, abbreviated: true }}
|
options={{ maxDecimals: 2, abbreviated: true }}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import DisplayCurrency from 'components/DisplayCurrency'
|
import DisplayCurrency from 'components/DisplayCurrency'
|
||||||
import { FormattedNumber } from 'components/FormattedNumber'
|
import { FormattedNumber } from 'components/FormattedNumber'
|
||||||
@ -13,9 +14,8 @@ import {
|
|||||||
calculateAccountApr,
|
calculateAccountApr,
|
||||||
calculateAccountBalanceValue,
|
calculateAccountBalanceValue,
|
||||||
calculateAccountBorrowRate,
|
calculateAccountBorrowRate,
|
||||||
calculateAccountDebtValue,
|
|
||||||
calculateAccountDepositsValue,
|
|
||||||
calculateAccountPnL,
|
calculateAccountPnL,
|
||||||
|
getAccountPositionValues,
|
||||||
} from 'utils/accounts'
|
} from 'utils/accounts'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -28,24 +28,37 @@ interface ItemProps {
|
|||||||
current: BigNumber
|
current: BigNumber
|
||||||
change: BigNumber
|
change: BigNumber
|
||||||
className?: string
|
className?: string
|
||||||
isBadIncrease?: boolean
|
isDecrease?: boolean
|
||||||
isPercentage?: boolean
|
isPercentage?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AccountComposition(props: Props) {
|
export default function AccountComposition(props: Props) {
|
||||||
|
const { account, change } = props
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const balance = calculateAccountDepositsValue(props.account, prices)
|
|
||||||
const balanceChange = props.change ? calculateAccountDepositsValue(props.change, prices) : BN_ZERO
|
const [depositsBalance, lendsBalance, debtsBalance] = useMemo(
|
||||||
const debtBalance = calculateAccountDebtValue(props.account, prices)
|
() => getAccountPositionValues(account, prices),
|
||||||
const debtBalanceChange = props.change ? calculateAccountDebtValue(props.change, prices) : BN_ZERO
|
[account, prices],
|
||||||
const totalBalance = calculateAccountBalanceValue(props.account, prices)
|
)
|
||||||
const totalBalanceChange = props.change
|
const [depositsBalanceChange, lendsBalanceChange, debtsBalanceChange] = useMemo(
|
||||||
? calculateAccountBalanceValue(props.change, prices)
|
() => (change ? getAccountPositionValues(change, prices) : [BN_ZERO, BN_ZERO, BN_ZERO]),
|
||||||
: BN_ZERO
|
[change, prices],
|
||||||
const apr = calculateAccountApr(props.account, prices)
|
)
|
||||||
const aprChange = props.change ? calculateAccountPnL(props.change, prices) : BN_ZERO
|
const totalBalance = useMemo(
|
||||||
const borrowRate = calculateAccountBorrowRate(props.account, prices)
|
() => calculateAccountBalanceValue(account, prices),
|
||||||
const borrowRateChange = props.change ? calculateAccountPnL(props.change, prices) : BN_ZERO
|
[account, prices],
|
||||||
|
)
|
||||||
|
const totalBalanceChange = useMemo(
|
||||||
|
() => (change ? calculateAccountBalanceValue(change, prices) : BN_ZERO),
|
||||||
|
[change, prices],
|
||||||
|
)
|
||||||
|
|
||||||
|
const balance = depositsBalance.plus(lendsBalance)
|
||||||
|
const balanceChange = depositsBalanceChange.plus(lendsBalanceChange)
|
||||||
|
const apr = calculateAccountApr(account, prices)
|
||||||
|
const aprChange = change ? calculateAccountPnL(change, prices) : BN_ZERO
|
||||||
|
const borrowRate = calculateAccountBorrowRate(account, prices)
|
||||||
|
const borrowRateChange = change ? calculateAccountPnL(change, prices) : BN_ZERO
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex-wrap p-4'>
|
<div className='w-full flex-wrap p-4'>
|
||||||
@ -57,10 +70,10 @@ export default function AccountComposition(props: Props) {
|
|||||||
/>
|
/>
|
||||||
<Item
|
<Item
|
||||||
title='Total Debt'
|
title='Total Debt'
|
||||||
current={debtBalance}
|
current={debtsBalance}
|
||||||
change={debtBalance.plus(debtBalanceChange)}
|
change={debtsBalance.plus(debtsBalanceChange)}
|
||||||
className='pb-3'
|
className='pb-3'
|
||||||
isBadIncrease
|
isDecrease
|
||||||
/>
|
/>
|
||||||
<Item
|
<Item
|
||||||
title='Total Balance'
|
title='Total Balance'
|
||||||
@ -74,16 +87,16 @@ export default function AccountComposition(props: Props) {
|
|||||||
current={borrowRate}
|
current={borrowRate}
|
||||||
change={borrowRate.plus(borrowRateChange)}
|
change={borrowRate.plus(borrowRateChange)}
|
||||||
isPercentage
|
isPercentage
|
||||||
isBadIncrease
|
isDecrease
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Item(props: ItemProps) {
|
function Item(props: ItemProps) {
|
||||||
const increase = props.isBadIncrease
|
const { current, change } = props
|
||||||
? props.current.isGreaterThan(props.change)
|
const increase = props.isDecrease ? current.isGreaterThan(change) : current.isLessThan(change)
|
||||||
: props.current.isLessThan(props.change)
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames('flex w-full flex-nowrap', props.className)}>
|
<div className={classNames('flex w-full flex-nowrap', props.className)}>
|
||||||
<div className='flex flex-shrink items-center'>
|
<div className='flex flex-shrink items-center'>
|
||||||
@ -94,32 +107,32 @@ function Item(props: ItemProps) {
|
|||||||
<div className='flex flex-1 items-center justify-end gap-2'>
|
<div className='flex flex-1 items-center justify-end gap-2'>
|
||||||
{props.isPercentage ? (
|
{props.isPercentage ? (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={props.current.toNumber()}
|
amount={current.toNumber()}
|
||||||
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
||||||
className='text-sm'
|
className='text-sm'
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.current)}
|
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, current)}
|
||||||
className='text-sm'
|
className='text-sm'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!props.current.isEqualTo(props.change) && (
|
{!current.isEqualTo(change) && (
|
||||||
<>
|
<>
|
||||||
<span className={classNames('w-3', increase ? 'text-profit' : 'text-loss')}>
|
<span className={classNames('w-3', increase ? 'text-profit' : 'text-loss')}>
|
||||||
<ArrowRight />
|
<ArrowRight />
|
||||||
</span>
|
</span>
|
||||||
{props.isPercentage ? (
|
{props.isPercentage ? (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
amount={props.change.toNumber()}
|
amount={change.toNumber()}
|
||||||
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
||||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.change)}
|
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, change)}
|
||||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -7,7 +7,7 @@ import FullOverlayContent from 'components/FullOverlayContent'
|
|||||||
import { Plus } from 'components/Icons'
|
import { Plus } from 'components/Icons'
|
||||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||||
import WalletBridges from 'components/Wallet/WalletBridges'
|
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useAccounts from 'hooks/useAccounts'
|
import useAccounts from 'hooks/useAccounts'
|
||||||
@ -16,6 +16,7 @@ import useCurrentAccount from 'hooks/useCurrentAccount'
|
|||||||
import useToggle from 'hooks/useToggle'
|
import useToggle from 'hooks/useToggle'
|
||||||
import useWalletBalances from 'hooks/useWalletBalances'
|
import useWalletBalances from 'hooks/useWalletBalances'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
|
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
@ -30,13 +31,14 @@ export default function AccountFund() {
|
|||||||
const currentAccount = useCurrentAccount()
|
const currentAccount = useCurrentAccount()
|
||||||
const [isFunding, setIsFunding] = useToggle(false)
|
const [isFunding, setIsFunding] = useToggle(false)
|
||||||
const [selectedAccountId, setSelectedAccountId] = useState<null | string>(null)
|
const [selectedAccountId, setSelectedAccountId] = useState<null | string>(null)
|
||||||
const [fundingAssets, setFundingAssets] = useState<Coin[]>([])
|
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
|
||||||
const { data: walletBalances } = useWalletBalances(address)
|
const { data: walletBalances } = useWalletBalances(address)
|
||||||
const baseAsset = getBaseAsset()
|
const baseAsset = getBaseAsset()
|
||||||
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId ?? '0')
|
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId ?? '0')
|
||||||
const hasAssetSelected = fundingAssets.length > 0
|
const hasAssetSelected = fundingAssets.length > 0
|
||||||
const hasFundingAssets = fundingAssets.length > 0 && fundingAssets.every((a) => a.amount !== '0')
|
const hasFundingAssets =
|
||||||
|
fundingAssets.length > 0 && fundingAssets.every((a) => a.toCoin().amount !== '0')
|
||||||
|
|
||||||
const baseBalance = useMemo(
|
const baseBalance = useMemo(
|
||||||
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||||
@ -77,10 +79,9 @@ export default function AccountFund() {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
const newFundingAssets = selectedDenoms.map((denom) => ({
|
const newFundingAssets = selectedDenoms.map((denom) =>
|
||||||
denom,
|
BNCoin.fromDenomAndBigNumber(denom, BN(fundingAssets.find(byDenom(denom))?.amount ?? '0')),
|
||||||
amount: fundingAssets.find((asset) => asset.denom === denom)?.amount ?? '0',
|
)
|
||||||
}))
|
|
||||||
|
|
||||||
setFundingAssets(newFundingAssets)
|
setFundingAssets(newFundingAssets)
|
||||||
}, [selectedDenoms, fundingAssets])
|
}, [selectedDenoms, fundingAssets])
|
||||||
@ -89,7 +90,7 @@ export default function AccountFund() {
|
|||||||
(amount: BigNumber, denom: string) => {
|
(amount: BigNumber, denom: string) => {
|
||||||
const assetToUpdate = fundingAssets.find((asset) => asset.denom === denom)
|
const assetToUpdate = fundingAssets.find((asset) => asset.denom === denom)
|
||||||
if (assetToUpdate) {
|
if (assetToUpdate) {
|
||||||
assetToUpdate.amount = amount.toString()
|
assetToUpdate.amount = amount
|
||||||
setFundingAssets([...fundingAssets.filter((a) => a.denom !== denom), assetToUpdate])
|
setFundingAssets([...fundingAssets.filter((a) => a.denom !== denom), assetToUpdate])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -14,7 +14,7 @@ import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
|||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
import { calculateAccountValue } from 'utils/accounts'
|
||||||
import { getPage, getRoute } from 'utils/route'
|
import { getPage, getRoute } from 'utils/route'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -54,7 +54,7 @@ export default function AccountList(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className='flex w-full flex-wrap p-4'>
|
<div className='flex w-full flex-wrap p-4'>
|
||||||
{props.accounts.map((account) => {
|
{props.accounts.map((account) => {
|
||||||
const positionBalance = calculateAccountDepositsValue(account, prices)
|
const positionBalance = calculateAccountValue('deposits', account, prices)
|
||||||
const isActive = accountId === account.id
|
const isActive = accountId === account.id
|
||||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { ORACLE_DENOM } from 'constants/oracle'
|
|||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
import { calculateAccountValue } from 'utils/accounts'
|
||||||
import { formatHealth } from 'utils/formatters'
|
import { formatHealth } from 'utils/formatters'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ interface Props {
|
|||||||
|
|
||||||
export default function AccountStats(props: Props) {
|
export default function AccountStats(props: Props) {
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const positionBalance = calculateAccountDepositsValue(props.account, prices)
|
const positionBalance = calculateAccountValue('deposits', props.account, prices)
|
||||||
const { health } = useHealthComputer(props.account)
|
const { health } = useHealthComputer(props.account)
|
||||||
const healthFactor = BN(100).minus(formatHealth(health)).toNumber()
|
const healthFactor = BN(100).minus(formatHealth(health)).toNumber()
|
||||||
return (
|
return (
|
||||||
|
@ -13,7 +13,7 @@ import useIsOpenArray from 'hooks/useIsOpenArray'
|
|||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
import { calculateAccountValue } from 'utils/accounts'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account?: Account
|
account?: Account
|
||||||
@ -24,7 +24,7 @@ export default function AccountSummary(props: Props) {
|
|||||||
const [isOpen, toggleOpen] = useIsOpenArray(2, true)
|
const [isOpen, toggleOpen] = useIsOpenArray(2, true)
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
const accountBalance = props.account
|
const accountBalance = props.account
|
||||||
? calculateAccountDepositsValue(props.account, prices)
|
? calculateAccountValue('deposits', props.account, prices)
|
||||||
: BN_ZERO
|
: BN_ZERO
|
||||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
||||||
useBorrowMarketAssetsTableData()
|
useBorrowMarketAssetsTableData()
|
||||||
|
@ -8,10 +8,10 @@ import Divider from 'components/Divider'
|
|||||||
import { ArrowRight } from 'components/Icons'
|
import { ArrowRight } from 'components/Icons'
|
||||||
import Modal from 'components/Modal'
|
import Modal from 'components/Modal'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
asset: Asset
|
asset: Asset
|
||||||
|
@ -24,15 +24,12 @@ interface Props {
|
|||||||
export default function AssetSelectTable(props: Props) {
|
export default function AssetSelectTable(props: Props) {
|
||||||
const defaultSelected = useMemo(() => {
|
const defaultSelected = useMemo(() => {
|
||||||
const assets = props.assets as BorrowAsset[]
|
const assets = props.assets as BorrowAsset[]
|
||||||
return assets.reduce(
|
return assets.reduce((acc, asset, index) => {
|
||||||
(acc, asset, index) => {
|
if (props.selectedDenoms?.includes(asset.denom)) {
|
||||||
if (props.selectedDenoms?.includes(asset.denom)) {
|
acc[index] = true
|
||||||
acc[index] = true
|
}
|
||||||
}
|
return acc
|
||||||
return acc
|
}, {} as { [key: number]: boolean })
|
||||||
},
|
|
||||||
{} as { [key: number]: boolean },
|
|
||||||
)
|
|
||||||
}, [props.selectedDenoms, props.assets])
|
}, [props.selectedDenoms, props.assets])
|
||||||
const [sorting, setSorting] = useState<SortingState>([{ id: 'symbol', desc: false }])
|
const [sorting, setSorting] = useState<SortingState>([{ id: 'symbol', desc: false }])
|
||||||
const [selected, setSelected] = useState<RowSelectionState>(defaultSelected)
|
const [selected, setSelected] = useState<RowSelectionState>(defaultSelected)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import AccountSummary from 'components/Account/AccountSummary'
|
import AccountSummary from 'components/Account/AccountSummary'
|
||||||
import AssetImage from 'components/AssetImage'
|
import AssetImage from 'components/AssetImage'
|
||||||
@ -11,17 +11,17 @@ import Modal from 'components/Modal'
|
|||||||
import Switch from 'components/Switch'
|
import Switch from 'components/Switch'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||||
import { ASSETS } from 'constants/assets'
|
import { ASSETS } from 'constants/assets'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
import useToggle from 'hooks/useToggle'
|
import useToggle from 'hooks/useToggle'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
import { formatPercent, formatValue } from 'utils/formatters'
|
import { formatPercent, formatValue } from 'utils/formatters'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
function getDebtAmount(modal: BorrowModal | null) {
|
function getDebtAmount(modal: BorrowModal | null) {
|
||||||
return BN((modal?.marketData as BorrowMarketTableData)?.debt ?? 0).toString()
|
return BN((modal?.marketData as BorrowMarketTableData)?.debt ?? 0).toString()
|
||||||
|
88
src/components/Modals/FundWithdraw/FundAccount.tsx
Normal file
88
src/components/Modals/FundWithdraw/FundAccount.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import BigNumber from 'bignumber.js'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import { ArrowRight } from 'components/Icons'
|
||||||
|
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||||
|
import { ASSETS } from 'constants/assets'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useToggle from 'hooks/useToggle'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { getAmount } from 'utils/accounts'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
import { hardcodedFee } from 'utils/constants'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
account: Account
|
||||||
|
setChange: (change: AccountChange | undefined) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FundAccount(props: Props) {
|
||||||
|
const { account, setChange } = props
|
||||||
|
const deposit = useStore((s) => s.deposit)
|
||||||
|
const balances = useStore((s) => s.balances)
|
||||||
|
const defaultAsset = ASSETS.find(byDenom(balances[0].denom)) ?? ASSETS[0]
|
||||||
|
const [isConfirming, setIsConfirming] = useToggle()
|
||||||
|
const [currentAsset, setCurrentAsset] = useState(defaultAsset)
|
||||||
|
const [amount, setAmount] = useState(BN_ZERO)
|
||||||
|
const depositAmount = BN_ZERO.plus(amount)
|
||||||
|
const max = getAmount(currentAsset.denom, balances ?? [])
|
||||||
|
|
||||||
|
function onChangeAmount(val: BigNumber) {
|
||||||
|
setAmount(val)
|
||||||
|
setChange({
|
||||||
|
deposits: [
|
||||||
|
{
|
||||||
|
amount: depositAmount.toString(),
|
||||||
|
denom: currentAsset.denom,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetState() {
|
||||||
|
setCurrentAsset(defaultAsset)
|
||||||
|
setAmount(BN_ZERO)
|
||||||
|
setChange(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onConfirm() {
|
||||||
|
setIsConfirming(true)
|
||||||
|
const result = await deposit({
|
||||||
|
fee: hardcodedFee,
|
||||||
|
accountId: account.id,
|
||||||
|
coins: [BNCoin.fromDenomAndBigNumber(currentAsset.denom, amount)],
|
||||||
|
})
|
||||||
|
|
||||||
|
setIsConfirming(false)
|
||||||
|
if (result) {
|
||||||
|
resetState()
|
||||||
|
useStore.setState({ fundAndWithdrawModal: null })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TokenInputWithSlider
|
||||||
|
asset={currentAsset}
|
||||||
|
onChange={onChangeAmount}
|
||||||
|
onChangeAsset={setCurrentAsset}
|
||||||
|
amount={amount}
|
||||||
|
max={max}
|
||||||
|
className='w-full'
|
||||||
|
balances={balances}
|
||||||
|
hasSelect
|
||||||
|
maxText='Max'
|
||||||
|
disabled={isConfirming}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={onConfirm}
|
||||||
|
showProgressIndicator={isConfirming}
|
||||||
|
className='w-full'
|
||||||
|
text={'Fund'}
|
||||||
|
rightIcon={<ArrowRight />}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -1,17 +1,9 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import AccountSummary from 'components/Account/AccountSummary'
|
import AccountSummary from 'components/Account/AccountSummary'
|
||||||
import Button from 'components/Button'
|
|
||||||
import Card from 'components/Card'
|
import Card from 'components/Card'
|
||||||
import Divider from 'components/Divider'
|
import FundAccount from 'components/Modals/FundWithdraw/FundAccount'
|
||||||
import { ArrowRight } from 'components/Icons'
|
import WithdrawFromAccount from 'components/Modals/FundWithdraw/WithdrawFromAccount'
|
||||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
|
||||||
import useToggle from 'hooks/useToggle'
|
|
||||||
import useStore from 'store'
|
|
||||||
import { getAmount } from 'utils/accounts'
|
|
||||||
import { hardcodedFee } from 'utils/constants'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account: Account
|
account: Account
|
||||||
@ -19,103 +11,22 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function FundWithdrawModalContent(props: Props) {
|
export default function FundWithdrawModalContent(props: Props) {
|
||||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
const { account, isFunding } = props
|
||||||
const withdraw = useStore((s) => s.withdraw)
|
|
||||||
const deposit = useStore((s) => s.deposit)
|
|
||||||
const balances = useStore((s) => s.balances)
|
|
||||||
const [isConfirming, setIsConfirming] = useToggle()
|
|
||||||
const [currentAsset, setCurrentAsset] = useState(baseCurrency)
|
|
||||||
const [amount, setAmount] = useState(BN_ZERO)
|
|
||||||
const [change, setChange] = useState<AccountChange | undefined>()
|
const [change, setChange] = useState<AccountChange | undefined>()
|
||||||
|
|
||||||
const max = props.isFunding
|
|
||||||
? getAmount(currentAsset.denom, balances ?? [])
|
|
||||||
: props.account
|
|
||||||
? getAmount(currentAsset.denom, props.account.deposits)
|
|
||||||
: BN_ZERO
|
|
||||||
|
|
||||||
function onChangeAmount(val: BigNumber) {
|
|
||||||
setAmount(val)
|
|
||||||
setChange({
|
|
||||||
deposits: [
|
|
||||||
{
|
|
||||||
amount: props.isFunding
|
|
||||||
? BN_ZERO.plus(amount).toString()
|
|
||||||
: BN_ZERO.minus(amount).toString(),
|
|
||||||
denom: currentAsset.denom,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetState() {
|
|
||||||
setCurrentAsset(baseCurrency)
|
|
||||||
setAmount(BN_ZERO)
|
|
||||||
setChange(undefined)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onConfirm() {
|
|
||||||
setIsConfirming(true)
|
|
||||||
let result
|
|
||||||
if (props.isFunding) {
|
|
||||||
result = await deposit({
|
|
||||||
fee: hardcodedFee,
|
|
||||||
accountId: props.account.id,
|
|
||||||
coins: [
|
|
||||||
{
|
|
||||||
denom: currentAsset.denom,
|
|
||||||
amount: amount.toString(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
result = await withdraw({
|
|
||||||
fee: hardcodedFee,
|
|
||||||
accountId: props.account.id,
|
|
||||||
coins: [
|
|
||||||
{
|
|
||||||
denom: currentAsset.denom,
|
|
||||||
amount: amount.toString(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsConfirming(false)
|
|
||||||
if (result) {
|
|
||||||
resetState()
|
|
||||||
useStore.setState({ fundAndWithdrawModal: null })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-1 items-start gap-6 p-6'>
|
<div className='flex flex-1 items-start gap-6 p-6'>
|
||||||
<Card
|
<Card
|
||||||
className='flex flex-1 bg-white/5 p-4'
|
className='flex flex-1 bg-white/5 p-4'
|
||||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
contentClassName='gap-6 flex flex-col justify-between h-full min-h-[380px] '
|
||||||
>
|
>
|
||||||
<TokenInputWithSlider
|
{isFunding ? (
|
||||||
asset={currentAsset}
|
<FundAccount account={account} setChange={setChange} />
|
||||||
onChange={onChangeAmount}
|
) : (
|
||||||
onChangeAsset={setCurrentAsset}
|
<WithdrawFromAccount account={account} setChange={setChange} />
|
||||||
amount={amount}
|
)}
|
||||||
max={max}
|
|
||||||
balances={props.isFunding ? balances : props.account.deposits}
|
|
||||||
accountId={!props.isFunding ? props.account.id : undefined}
|
|
||||||
hasSelect
|
|
||||||
maxText='Max'
|
|
||||||
disabled={isConfirming}
|
|
||||||
/>
|
|
||||||
<Divider />
|
|
||||||
<Button
|
|
||||||
onClick={onConfirm}
|
|
||||||
showProgressIndicator={isConfirming}
|
|
||||||
className='w-full'
|
|
||||||
text={props.isFunding ? 'Fund' : 'Withdraw'}
|
|
||||||
rightIcon={<ArrowRight />}
|
|
||||||
/>
|
|
||||||
</Card>
|
</Card>
|
||||||
<AccountSummary account={props.account} change={change} />
|
<AccountSummary account={account} change={change} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
129
src/components/Modals/FundWithdraw/WithdrawFromAccount.tsx
Normal file
129
src/components/Modals/FundWithdraw/WithdrawFromAccount.tsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import BigNumber from 'bignumber.js'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import Divider from 'components/Divider'
|
||||||
|
import { ArrowRight } from 'components/Icons'
|
||||||
|
import Switch from 'components/Switch'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||||
|
import { ASSETS } from 'constants/assets'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
|
import useToggle from 'hooks/useToggle'
|
||||||
|
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||||
|
import useStore from 'store'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
import { hardcodedFee } from 'utils/constants'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
account: Account
|
||||||
|
setChange: (change: AccountChange | undefined) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function WithdrawFromAccount(props: Props) {
|
||||||
|
const { account, setChange } = props
|
||||||
|
const defaultAsset = ASSETS.find(byDenom(account.deposits[0].denom)) ?? ASSETS[0]
|
||||||
|
const withdraw = useStore((s) => s.withdraw)
|
||||||
|
const [withdrawWithBorrowing, setWithdrawWithBorrowing] = useToggle()
|
||||||
|
const [isConfirming, setIsConfirming] = useToggle()
|
||||||
|
const [currentAsset, setCurrentAsset] = useState(defaultAsset)
|
||||||
|
const [amount, setAmount] = useState(BN_ZERO)
|
||||||
|
const { updatedAccount, removeDepositByDenom } = useUpdatedAccount(account)
|
||||||
|
const { computeMaxWithdrawAmount } = useHealthComputer(account)
|
||||||
|
const { computeMaxBorrowAmount } = useHealthComputer(updatedAccount)
|
||||||
|
const maxWithdrawAmount = computeMaxWithdrawAmount(currentAsset.denom)
|
||||||
|
const maxWithdrawWithBorrowAmount = computeMaxBorrowAmount(currentAsset.denom, 'wallet').plus(
|
||||||
|
maxWithdrawAmount,
|
||||||
|
)
|
||||||
|
const isWithinBalance = amount.isLessThan(maxWithdrawAmount)
|
||||||
|
const depositAmount = BN_ZERO.minus(isWithinBalance ? amount : maxWithdrawAmount)
|
||||||
|
const debtAmount = isWithinBalance ? BN_ZERO : amount.minus(maxWithdrawAmount)
|
||||||
|
const max = withdrawWithBorrowing ? maxWithdrawWithBorrowAmount : maxWithdrawAmount
|
||||||
|
|
||||||
|
function onChangeAmount(val: BigNumber) {
|
||||||
|
setAmount(val)
|
||||||
|
setChange({
|
||||||
|
deposits: [
|
||||||
|
{
|
||||||
|
amount: depositAmount.toString(),
|
||||||
|
denom: currentAsset.denom,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
debts: [{ amount: debtAmount.toString(), denom: currentAsset.denom }],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetState() {
|
||||||
|
setCurrentAsset(defaultAsset)
|
||||||
|
setAmount(BN_ZERO)
|
||||||
|
setChange(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onConfirm() {
|
||||||
|
setIsConfirming(true)
|
||||||
|
const result = await withdraw({
|
||||||
|
fee: hardcodedFee,
|
||||||
|
accountId: account.id,
|
||||||
|
coins: [BNCoin.fromDenomAndBigNumber(currentAsset.denom, amount)],
|
||||||
|
borrow: debtAmount.isZero()
|
||||||
|
? []
|
||||||
|
: [BNCoin.fromDenomAndBigNumber(currentAsset.denom, debtAmount)],
|
||||||
|
})
|
||||||
|
|
||||||
|
setIsConfirming(false)
|
||||||
|
if (result) {
|
||||||
|
resetState()
|
||||||
|
useStore.setState({ fundAndWithdrawModal: null })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
removeDepositByDenom(currentAsset.denom)
|
||||||
|
}, [currentAsset.denom, removeDepositByDenom])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className='flex w-full flex-wrap'>
|
||||||
|
<TokenInputWithSlider
|
||||||
|
asset={currentAsset}
|
||||||
|
onChange={onChangeAmount}
|
||||||
|
onChangeAsset={setCurrentAsset}
|
||||||
|
amount={amount}
|
||||||
|
max={max}
|
||||||
|
className='w-full'
|
||||||
|
balances={account.deposits}
|
||||||
|
accountId={account.id}
|
||||||
|
hasSelect={account.deposits.length > 1}
|
||||||
|
maxText='Max'
|
||||||
|
disabled={isConfirming}
|
||||||
|
/>
|
||||||
|
<Divider className='my-6' />
|
||||||
|
<div className='flex w-full flex-wrap'>
|
||||||
|
<div className='flex flex-1 flex-wrap'>
|
||||||
|
<Text className='mb-1 w-full'>Withdraw with borrowing</Text>
|
||||||
|
<Text size='xs' className='text-white/50'>
|
||||||
|
Borrow assets from your credit account to withdraw to your wallet
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-wrap items-center justify-end'>
|
||||||
|
<Switch
|
||||||
|
name='borrow-to-wallet'
|
||||||
|
checked={withdrawWithBorrowing}
|
||||||
|
onChange={setWithdrawWithBorrowing}
|
||||||
|
disabled={isConfirming}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
onClick={onConfirm}
|
||||||
|
showProgressIndicator={isConfirming}
|
||||||
|
className='w-full'
|
||||||
|
text={'Withdraw'}
|
||||||
|
rightIcon={<ArrowRight />}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -157,8 +157,9 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
|
|||||||
<div className='flex flex-1 flex-col gap-4 p-4'>
|
<div className='flex flex-1 flex-col gap-4 p-4'>
|
||||||
{props.borrowings.map((coin) => {
|
{props.borrowings.map((coin) => {
|
||||||
const asset = getAssetByDenom(coin.denom)
|
const asset = getAssetByDenom(coin.denom)
|
||||||
const maxAmount = maxBorrowAmounts.find((maxAmount) => maxAmount.denom === coin.denom)
|
const maxAmount = maxBorrowAmounts.find(
|
||||||
?.amount
|
(maxAmount) => maxAmount.denom === coin.denom,
|
||||||
|
)?.amount
|
||||||
if (!asset || !maxAmount)
|
if (!asset || !maxAmount)
|
||||||
return <React.Fragment key={`input-${coin.denom}`}></React.Fragment>
|
return <React.Fragment key={`input-${coin.denom}`}></React.Fragment>
|
||||||
return (
|
return (
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
import Accordion from 'components/Accordion'
|
import Accordion from 'components/Accordion'
|
||||||
@ -7,10 +6,10 @@ import VaultBorrowings from 'components/Modals/Vault/VaultBorrowings'
|
|||||||
import VaultBorrowingsSubTitle from 'components/Modals/Vault/VaultBorrowingsSubTitle'
|
import VaultBorrowingsSubTitle from 'components/Modals/Vault/VaultBorrowingsSubTitle'
|
||||||
import VaultDeposit from 'components/Modals/Vault/VaultDeposits'
|
import VaultDeposit from 'components/Modals/Vault/VaultDeposits'
|
||||||
import VaultDepositSubTitle from 'components/Modals/Vault/VaultDepositsSubTitle'
|
import VaultDepositSubTitle from 'components/Modals/Vault/VaultDepositsSubTitle'
|
||||||
import useIsOpenArray from 'hooks/useIsOpenArray'
|
|
||||||
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
|
||||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||||
|
import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||||
|
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
vault: Vault | DepositedVault
|
vault: Vault | DepositedVault
|
||||||
|
@ -75,9 +75,10 @@ export default function Option(props: Props) {
|
|||||||
<Text size='sm' className='col-span-2 text-white/50'>
|
<Text size='sm' className='col-span-2 text-white/50'>
|
||||||
{formatValue(5, { maxDecimals: 2, minDecimals: 0, prefix: 'APY ', suffix: '%' })}
|
{formatValue(5, { maxDecimals: 2, minDecimals: 0, prefix: 'APY ', suffix: '%' })}
|
||||||
</Text>
|
</Text>
|
||||||
<Text size='sm' className='col-span-2 text-right text-white/50'>
|
<DisplayCurrency
|
||||||
<DisplayCurrency coin={new BNCoin({ denom: asset.denom, amount: balance })} />
|
className='col-span-2 text-right text-sm text-white/50'
|
||||||
</Text>
|
coin={new BNCoin({ denom: asset.denom, amount: balance })}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ export default function Slider(props: Props) {
|
|||||||
{(showTooltip || isDragging) && (
|
{(showTooltip || isDragging) && (
|
||||||
<div className='absolute -top-8 left-1/2 -translate-x-1/2 rounded-xs bg-martian-red px-2 py-[2px] text-xs'>
|
<div className='absolute -top-8 left-1/2 -translate-x-1/2 rounded-xs bg-martian-red px-2 py-[2px] text-xs'>
|
||||||
<OverlayMark className='absolute -bottom-2 left-1/2 -z-1 h-2 -translate-x-1/2 text-martian-red' />
|
<OverlayMark className='absolute -bottom-2 left-1/2 -z-1 h-2 -translate-x-1/2 text-martian-red' />
|
||||||
{props.value}%
|
{props.value.toFixed(0)}%
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import Slider from 'components/Slider'
|
import Slider from 'components/Slider'
|
||||||
import TokenInput from 'components/TokenInput'
|
import TokenInput from 'components/TokenInput'
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
amount: BigNumber
|
amount: BigNumber
|
||||||
@ -44,6 +44,13 @@ export default function TokenInputWithSlider(props: Props) {
|
|||||||
props.onChangeAsset(newAsset)
|
props.onChangeAsset(newAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const newAmount = props.amount.isLessThan(props.max) ? props.amount : props.max
|
||||||
|
const newPercentage = newAmount.dividedBy(props.max).multipliedBy(100).toNumber()
|
||||||
|
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
|
||||||
|
if (percentage !== newPercentage) setPercentage(newPercentage)
|
||||||
|
}, [props.max, props.amount, amount, percentage])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={props.className}>
|
<div className={props.className}>
|
||||||
<TokenInput
|
<TokenInput
|
@ -43,66 +43,57 @@ export default function useHealthComputer(account?: Account) {
|
|||||||
|
|
||||||
const vaultPositionValues = useMemo(() => {
|
const vaultPositionValues = useMemo(() => {
|
||||||
if (!account?.vaults) return null
|
if (!account?.vaults) return null
|
||||||
return account.vaults.reduce(
|
return account.vaults.reduce((prev, curr) => {
|
||||||
(prev, curr) => {
|
const baseCoinPrice = prices.find((price) => price.denom === curr.denoms.lp)?.amount || 0
|
||||||
const baseCoinPrice = prices.find((price) => price.denom === curr.denoms.lp)?.amount || 0
|
prev[curr.address] = {
|
||||||
prev[curr.address] = {
|
base_coin: {
|
||||||
base_coin: {
|
amount: '0', // Not used by healthcomputer
|
||||||
amount: '0', // Not used by healthcomputer
|
denom: curr.denoms.lp,
|
||||||
denom: curr.denoms.lp,
|
value: curr.amounts.unlocking.times(baseCoinPrice).integerValue().toString(),
|
||||||
value: curr.amounts.unlocking.times(baseCoinPrice).integerValue().toString(),
|
},
|
||||||
},
|
vault_coin: {
|
||||||
vault_coin: {
|
amount: '0', // Not used by healthcomputer
|
||||||
amount: '0', // Not used by healthcomputer
|
denom: curr.denoms.vault,
|
||||||
denom: curr.denoms.vault,
|
value: curr.values.primary
|
||||||
value: curr.values.primary
|
.div(baseCurrencyPrice)
|
||||||
.div(baseCurrencyPrice)
|
.plus(curr.values.secondary.div(baseCurrencyPrice))
|
||||||
.plus(curr.values.secondary.div(baseCurrencyPrice))
|
.integerValue()
|
||||||
.integerValue()
|
.toString(),
|
||||||
.toString(),
|
},
|
||||||
},
|
}
|
||||||
}
|
return prev
|
||||||
return prev
|
}, {} as { [key: string]: VaultPositionValue })
|
||||||
},
|
|
||||||
{} as { [key: string]: VaultPositionValue },
|
|
||||||
)
|
|
||||||
}, [account?.vaults, prices, baseCurrencyPrice])
|
}, [account?.vaults, prices, baseCurrencyPrice])
|
||||||
|
|
||||||
const priceData = useMemo(() => {
|
const priceData = useMemo(() => {
|
||||||
const baseCurrencyPrice =
|
const baseCurrencyPrice =
|
||||||
prices.find((price) => price.denom === baseCurrency.denom)?.amount || 0
|
prices.find((price) => price.denom === baseCurrency.denom)?.amount || 0
|
||||||
|
|
||||||
return prices.reduce(
|
return prices.reduce((prev, curr) => {
|
||||||
(prev, curr) => {
|
prev[curr.denom] = curr.amount.div(baseCurrencyPrice).decimalPlaces(18).toString()
|
||||||
prev[curr.denom] = curr.amount.div(baseCurrencyPrice).decimalPlaces(18).toString()
|
return prev
|
||||||
return prev
|
}, {} as { [key: string]: string })
|
||||||
},
|
|
||||||
{} as { [key: string]: string },
|
|
||||||
)
|
|
||||||
}, [prices, baseCurrency.denom])
|
}, [prices, baseCurrency.denom])
|
||||||
|
|
||||||
const denomsData = useMemo(
|
const denomsData = useMemo(
|
||||||
() =>
|
() =>
|
||||||
assetParams.reduce(
|
assetParams.reduce((prev, curr) => {
|
||||||
(prev, curr) => {
|
const params: AssetParamsBaseForAddr = {
|
||||||
const params: AssetParamsBaseForAddr = {
|
...curr,
|
||||||
...curr,
|
// The following overrides are required as testnet is 'broken' and new contracts are not updated yet
|
||||||
// The following overrides are required as testnet is 'broken' and new contracts are not updated yet
|
// These overrides are not used by the healthcomputer internally, so they're not important anyways.
|
||||||
// These overrides are not used by the healthcomputer internally, so they're not important anyways.
|
protocol_liquidation_fee: '1',
|
||||||
protocol_liquidation_fee: '1',
|
liquidation_bonus: {
|
||||||
liquidation_bonus: {
|
max_lb: '1',
|
||||||
max_lb: '1',
|
min_lb: '1',
|
||||||
min_lb: '1',
|
slope: '1',
|
||||||
slope: '1',
|
starting_lb: '1',
|
||||||
starting_lb: '1',
|
},
|
||||||
},
|
}
|
||||||
}
|
prev[params.denom] = params
|
||||||
prev[params.denom] = params
|
|
||||||
|
|
||||||
return prev
|
return prev
|
||||||
},
|
}, {} as { [key: string]: AssetParamsBaseForAddr }),
|
||||||
{} as { [key: string]: AssetParamsBaseForAddr },
|
|
||||||
),
|
|
||||||
[assetParams],
|
[assetParams],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -112,13 +103,10 @@ export default function useHealthComputer(account?: Account) {
|
|||||||
const vaultPositionDenoms = positions.vaults.map((vault) => vault.vault.address)
|
const vaultPositionDenoms = positions.vaults.map((vault) => vault.vault.address)
|
||||||
return vaultConfigs
|
return vaultConfigs
|
||||||
.filter((config) => vaultPositionDenoms.includes(config.addr))
|
.filter((config) => vaultPositionDenoms.includes(config.addr))
|
||||||
.reduce(
|
.reduce((prev, curr) => {
|
||||||
(prev, curr) => {
|
prev[curr.addr] = curr
|
||||||
prev[curr.addr] = curr
|
return prev
|
||||||
return prev
|
}, {} as { [key: string]: VaultConfigBaseForString })
|
||||||
},
|
|
||||||
{} as { [key: string]: VaultConfigBaseForString },
|
|
||||||
)
|
|
||||||
}, [vaultConfigs, positions])
|
}, [vaultConfigs, positions])
|
||||||
|
|
||||||
const healthComputer: HealthComputer | null = useMemo(() => {
|
const healthComputer: HealthComputer | null = useMemo(() => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
|
||||||
import { addCoins, addValueToVaults, removeCoins } from 'hooks/useUpdatedAccount/functions'
|
import { addCoins, addValueToVaults, removeCoins } from 'hooks/useUpdatedAccount/functions'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { cloneAccount } from 'utils/accounts'
|
import { cloneAccount } from 'utils/accounts'
|
||||||
|
|
||||||
export interface VaultValue {
|
export interface VaultValue {
|
||||||
@ -17,6 +17,16 @@ export function useUpdatedAccount(account: Account) {
|
|||||||
const [removedDebt, removeDebt] = useState<BNCoin[]>([])
|
const [removedDebt, removeDebt] = useState<BNCoin[]>([])
|
||||||
const [addedVaultValues, addVaultValues] = useState<VaultValue[]>([])
|
const [addedVaultValues, addVaultValues] = useState<VaultValue[]>([])
|
||||||
|
|
||||||
|
const removeDepositByDenom = useCallback(
|
||||||
|
(denom: string) => {
|
||||||
|
const deposit = account.deposits.find((deposit) => deposit.denom === denom)
|
||||||
|
if (deposit) {
|
||||||
|
removeDeposits([...removedDeposits, deposit])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[account, removedDeposits],
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function updateAccount() {
|
async function updateAccount() {
|
||||||
const accountCopy = cloneAccount(account)
|
const accountCopy = cloneAccount(account)
|
||||||
@ -35,6 +45,7 @@ export function useUpdatedAccount(account: Account) {
|
|||||||
updatedAccount,
|
updatedAccount,
|
||||||
addDeposits,
|
addDeposits,
|
||||||
removeDeposits,
|
removeDeposits,
|
||||||
|
removeDepositByDenom,
|
||||||
addDebt,
|
addDebt,
|
||||||
removeDebt,
|
removeDebt,
|
||||||
addVaultValues,
|
addVaultValues,
|
||||||
|
@ -147,24 +147,26 @@ export default function createBroadcastSlice(
|
|||||||
|
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
deposit: async (options: { fee: StdFee; accountId: string; coins: Coin[] }) => {
|
deposit: async (options: { fee: StdFee; accountId: string; coins: BNCoin[] }) => {
|
||||||
const msg: CreditManagerExecuteMsg = {
|
const msg: CreditManagerExecuteMsg = {
|
||||||
update_credit_account: {
|
update_credit_account: {
|
||||||
account_id: options.accountId,
|
account_id: options.accountId,
|
||||||
actions: options.coins.map((coin) => ({
|
actions: options.coins.map((coin) => ({
|
||||||
deposit: coin,
|
deposit: coin.toCoin(),
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const funds = options.coins.map((coin) => coin.toCoin())
|
||||||
|
|
||||||
const response = await get().executeMsg({
|
const response = await get().executeMsg({
|
||||||
messages: [
|
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, funds)],
|
||||||
generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, options.coins),
|
|
||||||
],
|
|
||||||
fee: options.fee,
|
fee: options.fee,
|
||||||
})
|
})
|
||||||
|
|
||||||
const depositString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
const depositString = options.coins
|
||||||
|
.map((coin) => formatAmountWithSymbol(coin.toCoin()))
|
||||||
|
.join('and ')
|
||||||
handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`)
|
handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`)
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
@ -247,13 +249,23 @@ export default function createBroadcastSlice(
|
|||||||
handleResponseMessages(response, `Deposited into vault`)
|
handleResponseMessages(response, `Deposited into vault`)
|
||||||
return !!response.result
|
return !!response.result
|
||||||
},
|
},
|
||||||
withdraw: async (options: { fee: StdFee; accountId: string; coins: Coin[] }) => {
|
withdraw: async (options: {
|
||||||
|
fee: StdFee
|
||||||
|
accountId: string
|
||||||
|
coins: BNCoin[]
|
||||||
|
borrow: BNCoin[]
|
||||||
|
}) => {
|
||||||
|
const withdrawActions = options.coins.map((coin) => ({
|
||||||
|
withdraw: coin.toCoin(),
|
||||||
|
}))
|
||||||
|
const borrowActions = options.borrow.map((coin) => ({
|
||||||
|
borrow: coin.toCoin(),
|
||||||
|
}))
|
||||||
|
|
||||||
const msg: CreditManagerExecuteMsg = {
|
const msg: CreditManagerExecuteMsg = {
|
||||||
update_credit_account: {
|
update_credit_account: {
|
||||||
account_id: options.accountId,
|
account_id: options.accountId,
|
||||||
actions: options.coins.map((coin) => ({
|
actions: [...borrowActions, ...withdrawActions],
|
||||||
withdraw: coin,
|
|
||||||
})),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +274,9 @@ export default function createBroadcastSlice(
|
|||||||
fee: options.fee,
|
fee: options.fee,
|
||||||
})
|
})
|
||||||
|
|
||||||
const withdrawString = options.coins.map((coin) => formatAmountWithSymbol(coin)).join('and ')
|
const withdrawString = options.coins
|
||||||
|
.map((coin) => formatAmountWithSymbol(coin.toCoin()))
|
||||||
|
.join('and ')
|
||||||
handleResponseMessages(
|
handleResponseMessages(
|
||||||
response,
|
response,
|
||||||
`Withdrew ${withdrawString} from Account ${options.accountId}`,
|
`Withdrew ${withdrawString} from Account ${options.accountId}`,
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Inter;
|
font-family: Inter;
|
||||||
src:
|
src: url('../fonts/Inter-ExtraLight.woff2') format('woff2'),
|
||||||
url('../fonts/Inter-ExtraLight.woff2') format('woff2'),
|
|
||||||
url('../fonts/Inter-ExtraLight.woff') format('woff');
|
url('../fonts/Inter-ExtraLight.woff') format('woff');
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@ -14,8 +13,7 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Inter;
|
font-family: Inter;
|
||||||
src:
|
src: url('../fonts/Inter-Regular.woff2') format('woff2'),
|
||||||
url('../fonts/Inter-Regular.woff2') format('woff2'),
|
|
||||||
url('../fonts/Inter-Regular.woff') format('woff');
|
url('../fonts/Inter-Regular.woff') format('woff');
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@ -24,8 +22,7 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Inter;
|
font-family: Inter;
|
||||||
src:
|
src: url('../fonts/Inter-SemiBold.woff2') format('woff2'),
|
||||||
url('../fonts/Inter-SemiBold.woff2') format('woff2'),
|
|
||||||
url('../fonts/Inter-SemiBold.woff') format('woff');
|
url('../fonts/Inter-SemiBold.woff') format('woff');
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
9
src/types/interfaces/store/broadcast.d.ts
vendored
9
src/types/interfaces/store/broadcast.d.ts
vendored
@ -16,7 +16,7 @@ interface BroadcastSlice {
|
|||||||
}) => Promise<boolean>
|
}) => Promise<boolean>
|
||||||
createAccount: (options: { fee: StdFee }) => Promise<string | null>
|
createAccount: (options: { fee: StdFee }) => Promise<string | null>
|
||||||
deleteAccount: (options: { fee: StdFee; accountId: string; lends: BNCoin[] }) => Promise<boolean>
|
deleteAccount: (options: { fee: StdFee; accountId: string; lends: BNCoin[] }) => Promise<boolean>
|
||||||
deposit: (options: { fee: StdFee; accountId: string; coins: Coin[] }) => Promise<boolean>
|
deposit: (options: { fee: StdFee; accountId: string; coins: BNCoin[] }) => Promise<boolean>
|
||||||
unlock: (options: {
|
unlock: (options: {
|
||||||
fee: StdFee
|
fee: StdFee
|
||||||
accountId: string
|
accountId: string
|
||||||
@ -33,7 +33,12 @@ interface BroadcastSlice {
|
|||||||
accountId: string
|
accountId: string
|
||||||
actions: Action[]
|
actions: Action[]
|
||||||
}) => Promise<boolean>
|
}) => Promise<boolean>
|
||||||
withdraw: (options: { fee: StdFee; accountId: string; coins: Coin[] }) => Promise<boolean>
|
withdraw: (options: {
|
||||||
|
fee: StdFee
|
||||||
|
accountId: string
|
||||||
|
coins: BNCoin[]
|
||||||
|
borrow: BNCoin[]
|
||||||
|
}) => Promise<boolean>
|
||||||
lend: (options: {
|
lend: (options: {
|
||||||
fee: StdFee
|
fee: StdFee
|
||||||
accountId: string
|
accountId: string
|
||||||
|
@ -13,39 +13,34 @@ export const calculateAccountBalanceValue = (
|
|||||||
account: Account | AccountChange,
|
account: Account | AccountChange,
|
||||||
prices: BNCoin[],
|
prices: BNCoin[],
|
||||||
): BigNumber => {
|
): BigNumber => {
|
||||||
const totalDepositValue = calculateAccountDepositsValue(account, prices)
|
const depositsValue = calculateAccountValue('deposits', account, prices)
|
||||||
const totalDebtValue = calculateAccountDebtValue(account, prices)
|
const lendsValue = calculateAccountValue('lends', account, prices)
|
||||||
|
const debtsValue = calculateAccountValue('debts', account, prices)
|
||||||
|
|
||||||
return totalDepositValue.minus(totalDebtValue)
|
return depositsValue.plus(lendsValue).minus(debtsValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const calculateAccountDepositsValue = (
|
export const getAccountPositionValues = (account: Account | AccountChange, prices: BNCoin[]) => {
|
||||||
|
const deposits = calculateAccountValue('deposits', account, prices)
|
||||||
|
const lends = calculateAccountValue('lends', account, prices)
|
||||||
|
const debts = calculateAccountValue('debts', account, prices)
|
||||||
|
|
||||||
|
return [deposits, lends, debts]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calculateAccountValue = (
|
||||||
|
type: 'deposits' | 'lends' | 'debts',
|
||||||
account: Account | AccountChange,
|
account: Account | AccountChange,
|
||||||
prices: BNCoin[],
|
prices: BNCoin[],
|
||||||
): BigNumber => {
|
): BigNumber => {
|
||||||
if (!account.deposits) return BN_ZERO
|
if (!account[type]) return BN_ZERO
|
||||||
return account.deposits.reduce((acc, deposit) => {
|
return account[type]?.reduce((acc, position) => {
|
||||||
const asset = getAssetByDenom(deposit.denom)
|
const asset = getAssetByDenom(position.denom)
|
||||||
if (!asset) return acc
|
if (!asset) return acc
|
||||||
const price = prices.find((price) => price.denom === deposit.denom)?.amount ?? 0
|
const price = prices.find((price) => price.denom === position.denom)?.amount ?? 0
|
||||||
const amount = BN(deposit.amount).shiftedBy(-asset.decimals)
|
const amount = BN(position.amount).shiftedBy(-asset.decimals)
|
||||||
const depositValue = amount.multipliedBy(price)
|
const positionValue = amount.multipliedBy(price)
|
||||||
return acc.plus(depositValue)
|
return acc.plus(positionValue)
|
||||||
}, BN_ZERO)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const calculateAccountDebtValue = (
|
|
||||||
account: Account | AccountChange,
|
|
||||||
prices: BNCoin[],
|
|
||||||
): BigNumber => {
|
|
||||||
if (!account.debts) return BN_ZERO
|
|
||||||
return account.debts.reduce((acc, debt) => {
|
|
||||||
const asset = getAssetByDenom(debt.denom)
|
|
||||||
if (!asset) return acc
|
|
||||||
const price = prices.find((price) => price.denom === debt.denom)?.amount ?? 0
|
|
||||||
const debtAmount = BN(debt.amount).shiftedBy(-asset.decimals)
|
|
||||||
const debtValue = debtAmount.multipliedBy(price)
|
|
||||||
return acc.plus(debtValue)
|
|
||||||
}, BN_ZERO)
|
}, BN_ZERO)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +100,7 @@ export function convertAccountToPositions(account: Account): Positions {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}) as VaultPosition,
|
} as VaultPosition),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user