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 (
|
||||
<FormattedNumber
|
||||
className='text-right text-xs'
|
||||
amount={Number(BN(amount).abs().toPrecision(2))}
|
||||
amount={Number(BN(amount).abs())}
|
||||
options={{ maxDecimals: 2, abbreviated: true }}
|
||||
animate
|
||||
/>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import classNames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
@ -13,9 +14,8 @@ import {
|
||||
calculateAccountApr,
|
||||
calculateAccountBalanceValue,
|
||||
calculateAccountBorrowRate,
|
||||
calculateAccountDebtValue,
|
||||
calculateAccountDepositsValue,
|
||||
calculateAccountPnL,
|
||||
getAccountPositionValues,
|
||||
} from 'utils/accounts'
|
||||
|
||||
interface Props {
|
||||
@ -28,24 +28,37 @@ interface ItemProps {
|
||||
current: BigNumber
|
||||
change: BigNumber
|
||||
className?: string
|
||||
isBadIncrease?: boolean
|
||||
isDecrease?: boolean
|
||||
isPercentage?: boolean
|
||||
}
|
||||
|
||||
export default function AccountComposition(props: Props) {
|
||||
const { account, change } = props
|
||||
const { data: prices } = usePrices()
|
||||
const balance = calculateAccountDepositsValue(props.account, prices)
|
||||
const balanceChange = props.change ? calculateAccountDepositsValue(props.change, prices) : BN_ZERO
|
||||
const debtBalance = calculateAccountDebtValue(props.account, prices)
|
||||
const debtBalanceChange = props.change ? calculateAccountDebtValue(props.change, prices) : BN_ZERO
|
||||
const totalBalance = calculateAccountBalanceValue(props.account, prices)
|
||||
const totalBalanceChange = props.change
|
||||
? calculateAccountBalanceValue(props.change, prices)
|
||||
: BN_ZERO
|
||||
const apr = calculateAccountApr(props.account, prices)
|
||||
const aprChange = props.change ? calculateAccountPnL(props.change, prices) : BN_ZERO
|
||||
const borrowRate = calculateAccountBorrowRate(props.account, prices)
|
||||
const borrowRateChange = props.change ? calculateAccountPnL(props.change, prices) : BN_ZERO
|
||||
|
||||
const [depositsBalance, lendsBalance, debtsBalance] = useMemo(
|
||||
() => getAccountPositionValues(account, prices),
|
||||
[account, prices],
|
||||
)
|
||||
const [depositsBalanceChange, lendsBalanceChange, debtsBalanceChange] = useMemo(
|
||||
() => (change ? getAccountPositionValues(change, prices) : [BN_ZERO, BN_ZERO, BN_ZERO]),
|
||||
[change, prices],
|
||||
)
|
||||
const totalBalance = useMemo(
|
||||
() => calculateAccountBalanceValue(account, prices),
|
||||
[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 (
|
||||
<div className='w-full flex-wrap p-4'>
|
||||
@ -57,10 +70,10 @@ export default function AccountComposition(props: Props) {
|
||||
/>
|
||||
<Item
|
||||
title='Total Debt'
|
||||
current={debtBalance}
|
||||
change={debtBalance.plus(debtBalanceChange)}
|
||||
current={debtsBalance}
|
||||
change={debtsBalance.plus(debtsBalanceChange)}
|
||||
className='pb-3'
|
||||
isBadIncrease
|
||||
isDecrease
|
||||
/>
|
||||
<Item
|
||||
title='Total Balance'
|
||||
@ -74,16 +87,16 @@ export default function AccountComposition(props: Props) {
|
||||
current={borrowRate}
|
||||
change={borrowRate.plus(borrowRateChange)}
|
||||
isPercentage
|
||||
isBadIncrease
|
||||
isDecrease
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Item(props: ItemProps) {
|
||||
const increase = props.isBadIncrease
|
||||
? props.current.isGreaterThan(props.change)
|
||||
: props.current.isLessThan(props.change)
|
||||
const { current, change } = props
|
||||
const increase = props.isDecrease ? current.isGreaterThan(change) : current.isLessThan(change)
|
||||
|
||||
return (
|
||||
<div className={classNames('flex w-full flex-nowrap', props.className)}>
|
||||
<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'>
|
||||
{props.isPercentage ? (
|
||||
<FormattedNumber
|
||||
amount={props.current.toNumber()}
|
||||
amount={current.toNumber()}
|
||||
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
||||
className='text-sm'
|
||||
animate
|
||||
/>
|
||||
) : (
|
||||
<DisplayCurrency
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.current)}
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, current)}
|
||||
className='text-sm'
|
||||
/>
|
||||
)}
|
||||
{!props.current.isEqualTo(props.change) && (
|
||||
{!current.isEqualTo(change) && (
|
||||
<>
|
||||
<span className={classNames('w-3', increase ? 'text-profit' : 'text-loss')}>
|
||||
<ArrowRight />
|
||||
</span>
|
||||
{props.isPercentage ? (
|
||||
<FormattedNumber
|
||||
amount={props.change.toNumber()}
|
||||
amount={change.toNumber()}
|
||||
options={{ suffix: '%', minDecimals: 2, maxDecimals: 2 }}
|
||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||
animate
|
||||
/>
|
||||
) : (
|
||||
<DisplayCurrency
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.change)}
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, change)}
|
||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||
/>
|
||||
)}
|
||||
|
@ -7,7 +7,7 @@ import FullOverlayContent from 'components/FullOverlayContent'
|
||||
import { Plus } from 'components/Icons'
|
||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||
import Text from 'components/Text'
|
||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||
import WalletBridges from 'components/Wallet/WalletBridges'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAccounts from 'hooks/useAccounts'
|
||||
@ -16,6 +16,7 @@ import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useWalletBalances from 'hooks/useWalletBalances'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
|
||||
import { hardcodedFee } from 'utils/constants'
|
||||
@ -30,13 +31,14 @@ export default function AccountFund() {
|
||||
const currentAccount = useCurrentAccount()
|
||||
const [isFunding, setIsFunding] = useToggle(false)
|
||||
const [selectedAccountId, setSelectedAccountId] = useState<null | string>(null)
|
||||
const [fundingAssets, setFundingAssets] = useState<Coin[]>([])
|
||||
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
|
||||
const { data: walletBalances } = useWalletBalances(address)
|
||||
const baseAsset = getBaseAsset()
|
||||
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId ?? '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(
|
||||
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
|
||||
@ -77,10 +79,9 @@ export default function AccountFund() {
|
||||
)
|
||||
return
|
||||
|
||||
const newFundingAssets = selectedDenoms.map((denom) => ({
|
||||
denom,
|
||||
amount: fundingAssets.find((asset) => asset.denom === denom)?.amount ?? '0',
|
||||
}))
|
||||
const newFundingAssets = selectedDenoms.map((denom) =>
|
||||
BNCoin.fromDenomAndBigNumber(denom, BN(fundingAssets.find(byDenom(denom))?.amount ?? '0')),
|
||||
)
|
||||
|
||||
setFundingAssets(newFundingAssets)
|
||||
}, [selectedDenoms, fundingAssets])
|
||||
@ -89,7 +90,7 @@ export default function AccountFund() {
|
||||
(amount: BigNumber, denom: string) => {
|
||||
const assetToUpdate = fundingAssets.find((asset) => asset.denom === denom)
|
||||
if (assetToUpdate) {
|
||||
assetToUpdate.amount = amount.toString()
|
||||
assetToUpdate.amount = amount
|
||||
setFundingAssets([...fundingAssets.filter((a) => a.denom !== denom), assetToUpdate])
|
||||
}
|
||||
},
|
||||
|
@ -14,7 +14,7 @@ import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
||||
import { calculateAccountValue } from 'utils/accounts'
|
||||
import { getPage, getRoute } from 'utils/route'
|
||||
|
||||
interface Props {
|
||||
@ -54,7 +54,7 @@ export default function AccountList(props: Props) {
|
||||
return (
|
||||
<div className='flex w-full flex-wrap p-4'>
|
||||
{props.accounts.map((account) => {
|
||||
const positionBalance = calculateAccountDepositsValue(account, prices)
|
||||
const positionBalance = calculateAccountValue('deposits', account, prices)
|
||||
const isActive = accountId === account.id
|
||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
||||
import { calculateAccountValue } from 'utils/accounts'
|
||||
import { formatHealth } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
@ -14,7 +14,7 @@ interface Props {
|
||||
|
||||
export default function AccountStats(props: Props) {
|
||||
const { data: prices } = usePrices()
|
||||
const positionBalance = calculateAccountDepositsValue(props.account, prices)
|
||||
const positionBalance = calculateAccountValue('deposits', props.account, prices)
|
||||
const { health } = useHealthComputer(props.account)
|
||||
const healthFactor = BN(100).minus(formatHealth(health)).toNumber()
|
||||
return (
|
||||
|
@ -13,7 +13,7 @@ import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
||||
import { calculateAccountValue } from 'utils/accounts'
|
||||
|
||||
interface Props {
|
||||
account?: Account
|
||||
@ -24,7 +24,7 @@ export default function AccountSummary(props: Props) {
|
||||
const [isOpen, toggleOpen] = useIsOpenArray(2, true)
|
||||
const { data: prices } = usePrices()
|
||||
const accountBalance = props.account
|
||||
? calculateAccountDepositsValue(props.account, prices)
|
||||
? calculateAccountValue('deposits', props.account, prices)
|
||||
: BN_ZERO
|
||||
const { availableAssets: borrowAvailableAssets, accountBorrowedAssets } =
|
||||
useBorrowMarketAssetsTableData()
|
||||
|
@ -8,10 +8,10 @@ import Divider from 'components/Divider'
|
||||
import { ArrowRight } from 'components/Icons'
|
||||
import Modal from 'components/Modal'
|
||||
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 { BN } from 'utils/helpers'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
|
||||
interface Props {
|
||||
asset: Asset
|
||||
|
@ -24,15 +24,12 @@ interface Props {
|
||||
export default function AssetSelectTable(props: Props) {
|
||||
const defaultSelected = useMemo(() => {
|
||||
const assets = props.assets as BorrowAsset[]
|
||||
return assets.reduce(
|
||||
(acc, asset, index) => {
|
||||
if (props.selectedDenoms?.includes(asset.denom)) {
|
||||
acc[index] = true
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{} as { [key: number]: boolean },
|
||||
)
|
||||
return assets.reduce((acc, asset, index) => {
|
||||
if (props.selectedDenoms?.includes(asset.denom)) {
|
||||
acc[index] = true
|
||||
}
|
||||
return acc
|
||||
}, {} as { [key: number]: boolean })
|
||||
}, [props.selectedDenoms, props.assets])
|
||||
const [sorting, setSorting] = useState<SortingState>([{ id: 'symbol', desc: false }])
|
||||
const [selected, setSelected] = useState<RowSelectionState>(defaultSelected)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import AccountSummary from 'components/Account/AccountSummary'
|
||||
import AssetImage from 'components/AssetImage'
|
||||
@ -11,17 +11,17 @@ import Modal from 'components/Modal'
|
||||
import Switch from 'components/Switch'
|
||||
import Text from 'components/Text'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { hardcodedFee } from 'utils/constants'
|
||||
import { formatPercent, formatValue } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
|
||||
function getDebtAmount(modal: BorrowModal | null) {
|
||||
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 AccountSummary from 'components/Account/AccountSummary'
|
||||
import Button from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import Divider from 'components/Divider'
|
||||
import { ArrowRight } from 'components/Icons'
|
||||
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'
|
||||
import FundAccount from 'components/Modals/FundWithdraw/FundAccount'
|
||||
import WithdrawFromAccount from 'components/Modals/FundWithdraw/WithdrawFromAccount'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
@ -19,103 +11,22 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function FundWithdrawModalContent(props: Props) {
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
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 { account, isFunding } = props
|
||||
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 (
|
||||
<div className='flex flex-1 items-start gap-6 p-6'>
|
||||
<Card
|
||||
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
|
||||
asset={currentAsset}
|
||||
onChange={onChangeAmount}
|
||||
onChangeAsset={setCurrentAsset}
|
||||
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 />}
|
||||
/>
|
||||
{isFunding ? (
|
||||
<FundAccount account={account} setChange={setChange} />
|
||||
) : (
|
||||
<WithdrawFromAccount account={account} setChange={setChange} />
|
||||
)}
|
||||
</Card>
|
||||
<AccountSummary account={props.account} change={change} />
|
||||
<AccountSummary account={account} change={change} />
|
||||
</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'>
|
||||
{props.borrowings.map((coin) => {
|
||||
const asset = getAssetByDenom(coin.denom)
|
||||
const maxAmount = maxBorrowAmounts.find((maxAmount) => maxAmount.denom === coin.denom)
|
||||
?.amount
|
||||
const maxAmount = maxBorrowAmounts.find(
|
||||
(maxAmount) => maxAmount.denom === coin.denom,
|
||||
)?.amount
|
||||
if (!asset || !maxAmount)
|
||||
return <React.Fragment key={`input-${coin.denom}`}></React.Fragment>
|
||||
return (
|
||||
|
@ -1,4 +1,3 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import Accordion from 'components/Accordion'
|
||||
@ -7,10 +6,10 @@ 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 useIsOpenArray from 'hooks/useIsOpenArray'
|
||||
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useDepositVault from 'hooks/broadcast/useDepositVault'
|
||||
import useIsOpenArray from 'hooks/useIsOpenArray'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
|
||||
interface Props {
|
||||
vault: Vault | DepositedVault
|
||||
|
@ -75,9 +75,10 @@ export default function Option(props: Props) {
|
||||
<Text size='sm' className='col-span-2 text-white/50'>
|
||||
{formatValue(5, { maxDecimals: 2, minDecimals: 0, prefix: 'APY ', suffix: '%' })}
|
||||
</Text>
|
||||
<Text size='sm' className='col-span-2 text-right text-white/50'>
|
||||
<DisplayCurrency coin={new BNCoin({ denom: asset.denom, amount: balance })} />
|
||||
</Text>
|
||||
<DisplayCurrency
|
||||
className='col-span-2 text-right text-sm text-white/50'
|
||||
coin={new BNCoin({ denom: asset.denom, amount: balance })}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ export default function Slider(props: Props) {
|
||||
{(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'>
|
||||
<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>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import Slider from 'components/Slider'
|
||||
import TokenInput from 'components/TokenInput'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
amount: BigNumber
|
||||
@ -44,6 +44,13 @@ export default function TokenInputWithSlider(props: Props) {
|
||||
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 (
|
||||
<div className={props.className}>
|
||||
<TokenInput
|
@ -43,66 +43,57 @@ export default function useHealthComputer(account?: Account) {
|
||||
|
||||
const vaultPositionValues = useMemo(() => {
|
||||
if (!account?.vaults) return null
|
||||
return account.vaults.reduce(
|
||||
(prev, curr) => {
|
||||
const baseCoinPrice = prices.find((price) => price.denom === curr.denoms.lp)?.amount || 0
|
||||
prev[curr.address] = {
|
||||
base_coin: {
|
||||
amount: '0', // Not used by healthcomputer
|
||||
denom: curr.denoms.lp,
|
||||
value: curr.amounts.unlocking.times(baseCoinPrice).integerValue().toString(),
|
||||
},
|
||||
vault_coin: {
|
||||
amount: '0', // Not used by healthcomputer
|
||||
denom: curr.denoms.vault,
|
||||
value: curr.values.primary
|
||||
.div(baseCurrencyPrice)
|
||||
.plus(curr.values.secondary.div(baseCurrencyPrice))
|
||||
.integerValue()
|
||||
.toString(),
|
||||
},
|
||||
}
|
||||
return prev
|
||||
},
|
||||
{} as { [key: string]: VaultPositionValue },
|
||||
)
|
||||
return account.vaults.reduce((prev, curr) => {
|
||||
const baseCoinPrice = prices.find((price) => price.denom === curr.denoms.lp)?.amount || 0
|
||||
prev[curr.address] = {
|
||||
base_coin: {
|
||||
amount: '0', // Not used by healthcomputer
|
||||
denom: curr.denoms.lp,
|
||||
value: curr.amounts.unlocking.times(baseCoinPrice).integerValue().toString(),
|
||||
},
|
||||
vault_coin: {
|
||||
amount: '0', // Not used by healthcomputer
|
||||
denom: curr.denoms.vault,
|
||||
value: curr.values.primary
|
||||
.div(baseCurrencyPrice)
|
||||
.plus(curr.values.secondary.div(baseCurrencyPrice))
|
||||
.integerValue()
|
||||
.toString(),
|
||||
},
|
||||
}
|
||||
return prev
|
||||
}, {} as { [key: string]: VaultPositionValue })
|
||||
}, [account?.vaults, prices, baseCurrencyPrice])
|
||||
|
||||
const priceData = useMemo(() => {
|
||||
const baseCurrencyPrice =
|
||||
prices.find((price) => price.denom === baseCurrency.denom)?.amount || 0
|
||||
|
||||
return prices.reduce(
|
||||
(prev, curr) => {
|
||||
prev[curr.denom] = curr.amount.div(baseCurrencyPrice).decimalPlaces(18).toString()
|
||||
return prev
|
||||
},
|
||||
{} as { [key: string]: string },
|
||||
)
|
||||
return prices.reduce((prev, curr) => {
|
||||
prev[curr.denom] = curr.amount.div(baseCurrencyPrice).decimalPlaces(18).toString()
|
||||
return prev
|
||||
}, {} as { [key: string]: string })
|
||||
}, [prices, baseCurrency.denom])
|
||||
|
||||
const denomsData = useMemo(
|
||||
() =>
|
||||
assetParams.reduce(
|
||||
(prev, curr) => {
|
||||
const params: AssetParamsBaseForAddr = {
|
||||
...curr,
|
||||
// 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.
|
||||
protocol_liquidation_fee: '1',
|
||||
liquidation_bonus: {
|
||||
max_lb: '1',
|
||||
min_lb: '1',
|
||||
slope: '1',
|
||||
starting_lb: '1',
|
||||
},
|
||||
}
|
||||
prev[params.denom] = params
|
||||
assetParams.reduce((prev, curr) => {
|
||||
const params: AssetParamsBaseForAddr = {
|
||||
...curr,
|
||||
// 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.
|
||||
protocol_liquidation_fee: '1',
|
||||
liquidation_bonus: {
|
||||
max_lb: '1',
|
||||
min_lb: '1',
|
||||
slope: '1',
|
||||
starting_lb: '1',
|
||||
},
|
||||
}
|
||||
prev[params.denom] = params
|
||||
|
||||
return prev
|
||||
},
|
||||
{} as { [key: string]: AssetParamsBaseForAddr },
|
||||
),
|
||||
return prev
|
||||
}, {} as { [key: string]: AssetParamsBaseForAddr }),
|
||||
[assetParams],
|
||||
)
|
||||
|
||||
@ -112,13 +103,10 @@ export default function useHealthComputer(account?: Account) {
|
||||
const vaultPositionDenoms = positions.vaults.map((vault) => vault.vault.address)
|
||||
return vaultConfigs
|
||||
.filter((config) => vaultPositionDenoms.includes(config.addr))
|
||||
.reduce(
|
||||
(prev, curr) => {
|
||||
prev[curr.addr] = curr
|
||||
return prev
|
||||
},
|
||||
{} as { [key: string]: VaultConfigBaseForString },
|
||||
)
|
||||
.reduce((prev, curr) => {
|
||||
prev[curr.addr] = curr
|
||||
return prev
|
||||
}, {} as { [key: string]: VaultConfigBaseForString })
|
||||
}, [vaultConfigs, positions])
|
||||
|
||||
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 { BNCoin } from 'types/classes/BNCoin'
|
||||
import { cloneAccount } from 'utils/accounts'
|
||||
|
||||
export interface VaultValue {
|
||||
@ -17,6 +17,16 @@ export function useUpdatedAccount(account: Account) {
|
||||
const [removedDebt, removeDebt] = useState<BNCoin[]>([])
|
||||
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(() => {
|
||||
async function updateAccount() {
|
||||
const accountCopy = cloneAccount(account)
|
||||
@ -35,6 +45,7 @@ export function useUpdatedAccount(account: Account) {
|
||||
updatedAccount,
|
||||
addDeposits,
|
||||
removeDeposits,
|
||||
removeDepositByDenom,
|
||||
addDebt,
|
||||
removeDebt,
|
||||
addVaultValues,
|
||||
|
@ -147,24 +147,26 @@ export default function createBroadcastSlice(
|
||||
|
||||
return !!response.result
|
||||
},
|
||||
deposit: async (options: { fee: StdFee; accountId: string; coins: Coin[] }) => {
|
||||
deposit: async (options: { fee: StdFee; accountId: string; coins: BNCoin[] }) => {
|
||||
const msg: CreditManagerExecuteMsg = {
|
||||
update_credit_account: {
|
||||
account_id: options.accountId,
|
||||
actions: options.coins.map((coin) => ({
|
||||
deposit: coin,
|
||||
deposit: coin.toCoin(),
|
||||
})),
|
||||
},
|
||||
}
|
||||
|
||||
const funds = options.coins.map((coin) => coin.toCoin())
|
||||
|
||||
const response = await get().executeMsg({
|
||||
messages: [
|
||||
generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, options.coins),
|
||||
],
|
||||
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, funds)],
|
||||
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}`)
|
||||
return !!response.result
|
||||
},
|
||||
@ -247,13 +249,23 @@ export default function createBroadcastSlice(
|
||||
handleResponseMessages(response, `Deposited into vault`)
|
||||
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 = {
|
||||
update_credit_account: {
|
||||
account_id: options.accountId,
|
||||
actions: options.coins.map((coin) => ({
|
||||
withdraw: coin,
|
||||
})),
|
||||
actions: [...borrowActions, ...withdrawActions],
|
||||
},
|
||||
}
|
||||
|
||||
@ -262,7 +274,9 @@ export default function createBroadcastSlice(
|
||||
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(
|
||||
response,
|
||||
`Withdrew ${withdrawString} from Account ${options.accountId}`,
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
src:
|
||||
url('../fonts/Inter-ExtraLight.woff2') format('woff2'),
|
||||
src: url('../fonts/Inter-ExtraLight.woff2') format('woff2'),
|
||||
url('../fonts/Inter-ExtraLight.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
@ -14,8 +13,7 @@
|
||||
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
src:
|
||||
url('../fonts/Inter-Regular.woff2') format('woff2'),
|
||||
src: url('../fonts/Inter-Regular.woff2') format('woff2'),
|
||||
url('../fonts/Inter-Regular.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
@ -24,8 +22,7 @@
|
||||
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
src:
|
||||
url('../fonts/Inter-SemiBold.woff2') format('woff2'),
|
||||
src: url('../fonts/Inter-SemiBold.woff2') format('woff2'),
|
||||
url('../fonts/Inter-SemiBold.woff') format('woff');
|
||||
font-weight: 600;
|
||||
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>
|
||||
createAccount: (options: { fee: StdFee }) => Promise<string | null>
|
||||
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: {
|
||||
fee: StdFee
|
||||
accountId: string
|
||||
@ -33,7 +33,12 @@ interface BroadcastSlice {
|
||||
accountId: string
|
||||
actions: Action[]
|
||||
}) => 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: {
|
||||
fee: StdFee
|
||||
accountId: string
|
||||
|
@ -13,39 +13,34 @@ export const calculateAccountBalanceValue = (
|
||||
account: Account | AccountChange,
|
||||
prices: BNCoin[],
|
||||
): BigNumber => {
|
||||
const totalDepositValue = calculateAccountDepositsValue(account, prices)
|
||||
const totalDebtValue = calculateAccountDebtValue(account, prices)
|
||||
const depositsValue = calculateAccountValue('deposits', 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,
|
||||
prices: BNCoin[],
|
||||
): BigNumber => {
|
||||
if (!account.deposits) return BN_ZERO
|
||||
return account.deposits.reduce((acc, deposit) => {
|
||||
const asset = getAssetByDenom(deposit.denom)
|
||||
if (!account[type]) return BN_ZERO
|
||||
return account[type]?.reduce((acc, position) => {
|
||||
const asset = getAssetByDenom(position.denom)
|
||||
if (!asset) return acc
|
||||
const price = prices.find((price) => price.denom === deposit.denom)?.amount ?? 0
|
||||
const amount = BN(deposit.amount).shiftedBy(-asset.decimals)
|
||||
const depositValue = amount.multipliedBy(price)
|
||||
return acc.plus(depositValue)
|
||||
}, 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)
|
||||
const price = prices.find((price) => price.denom === position.denom)?.amount ?? 0
|
||||
const amount = BN(position.amount).shiftedBy(-asset.decimals)
|
||||
const positionValue = amount.multipliedBy(price)
|
||||
return acc.plus(positionValue)
|
||||
}, BN_ZERO)
|
||||
}
|
||||
|
||||
@ -105,7 +100,7 @@ export function convertAccountToPositions(account: Account): Positions {
|
||||
],
|
||||
},
|
||||
},
|
||||
}) as VaultPosition,
|
||||
} as VaultPosition),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user