[CM details] support changes (#359)
* [CM details] support changes * Update src/components/Trade/TradeModule/SwapForm/index.tsx Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com> * Update src/components/Trade/TradeModule/SwapForm/index.tsx Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com> * [HC] update to bncoin.from --------- Co-authored-by: Yusuf Seyrek <yusufseyrek@users.noreply.github.com>
This commit is contained in:
parent
5358b8c39e
commit
f9318dfe6e
3
.gitignore
vendored
3
.gitignore
vendored
@ -44,3 +44,6 @@ next-env.d.ts
|
||||
.env.local.mainnet
|
||||
.env.production
|
||||
.env
|
||||
|
||||
# IDE
|
||||
.idea
|
@ -27,6 +27,7 @@
|
||||
"classnames": "^2.3.2",
|
||||
"debounce-promise": "^3.1.2",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"moment": "^2.29.4",
|
||||
"next": "13.4.9",
|
||||
"react": "^18.2.0",
|
||||
@ -49,6 +50,7 @@
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/debounce-promise": "^3.1.6",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/lodash.throttle": "^4.1.7",
|
||||
"@types/node": "^20.4.8",
|
||||
"@types/react": "18.2.19",
|
||||
|
@ -1,9 +1,10 @@
|
||||
import classNames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import { Gauge } from 'components/Gauge'
|
||||
import { Heart } from 'components/Icons'
|
||||
import { ArrowRight, Heart } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
@ -11,13 +12,8 @@ import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { calculateAccountBalanceValue } from 'utils/accounts'
|
||||
import { formatHealth } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
import { calculateAccountBalanceValue, calculateAccountLeverage } from 'utils/accounts'
|
||||
import { formatLeverage } from 'utils/formatters'
|
||||
|
||||
export default function AccountDetailsController() {
|
||||
const account = useCurrentAccount()
|
||||
@ -29,37 +25,71 @@ export default function AccountDetailsController() {
|
||||
return <AccountDetails account={account} />
|
||||
}
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
}
|
||||
|
||||
function AccountDetails(props: Props) {
|
||||
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||
const { health } = useHealthComputer(props.account)
|
||||
const { health: updatedHealth } = useHealthComputer(updatedAccount)
|
||||
const { data: prices } = usePrices()
|
||||
const accountBalanceValue = calculateAccountBalanceValue(props.account, prices)
|
||||
const accountBalanceValue = calculateAccountBalanceValue(
|
||||
updatedAccount ? updatedAccount : props.account,
|
||||
prices,
|
||||
)
|
||||
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalanceValue)
|
||||
const healthFactor = BN(100).minus(formatHealth(health)).toNumber()
|
||||
const leverage = useMemo(
|
||||
() => calculateAccountLeverage(updatedAccount ? updatedAccount : props.account, prices),
|
||||
[props.account, updatedAccount, prices],
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid='account-details'
|
||||
className={classNames(
|
||||
'hidden w-16 rounded-base border border-white/20 bg-white/5 backdrop-blur-sticky',
|
||||
'md:block',
|
||||
)}
|
||||
className='w-16 rounded-base border border-white/20 bg-white/5 backdrop-blur-sticky'
|
||||
>
|
||||
<div className='flex flex-wrap justify-center w-full py-4'>
|
||||
<Gauge tooltip='Health Factor' percentage={healthFactor} icon={<Heart />} />
|
||||
<div className='flex w-full flex-wrap justify-center py-4'>
|
||||
<Gauge tooltip='Health Factor' percentage={health} icon={<Heart />} />
|
||||
<Text size='2xs' className='mb-0.5 mt-1 w-full text-center text-white/50'>
|
||||
Health
|
||||
</Text>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-xs'}
|
||||
amount={healthFactor}
|
||||
options={{ maxDecimals: 0, minDecimals: 0 }}
|
||||
animate
|
||||
/>
|
||||
<div className='flex'>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-xs'}
|
||||
amount={health}
|
||||
options={{ maxDecimals: 1, minDecimals: 0 }}
|
||||
animate
|
||||
/>
|
||||
{updatedHealth && health !== updatedHealth && (
|
||||
<>
|
||||
<ArrowRight
|
||||
width={16}
|
||||
className={classNames(health > updatedHealth ? 'text-loss' : 'text-success')}
|
||||
/>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-xs'}
|
||||
amount={updatedHealth}
|
||||
options={{ maxDecimals: 1, minDecimals: 0 }}
|
||||
animate
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full py-4 border border-x-0 border-white/20'>
|
||||
<div className='w-full border-t border-white/20 py-4'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Balance
|
||||
Leverage
|
||||
</Text>
|
||||
<DisplayCurrency coin={coin} className='w-full text-center truncate text-2xs ' />
|
||||
<Text size='xs' className='text-center'>
|
||||
{formatLeverage(leverage.toNumber())}
|
||||
</Text>
|
||||
</div>
|
||||
<div className='w-full border-t border-white/20 py-4'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Net worth
|
||||
</Text>
|
||||
<DisplayCurrency coin={coin} className='w-full truncate text-center text-2xs ' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -102,7 +102,7 @@ export default function VaultModalContent(props: Props) {
|
||||
{
|
||||
renderContent: () => (
|
||||
<VaultBorrowings
|
||||
updatedAccount={updatedAccount}
|
||||
updatedAccount={updatedAccount || props.account}
|
||||
borrowings={addedDebt}
|
||||
deposits={removedDeposits}
|
||||
primaryAsset={props.primaryAsset}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import debounce from 'lodash.debounce'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import Divider from 'components/Divider'
|
||||
@ -21,6 +22,7 @@ import { BNCoin } from 'types/classes/BNCoin'
|
||||
import estimateExactIn from 'api/swap/estimateExactIn'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import useMarketBorrowings from 'hooks/useMarketBorrowings'
|
||||
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
|
||||
|
||||
interface Props {
|
||||
buyAsset: Asset
|
||||
@ -45,6 +47,7 @@ export default function SwapForm(props: Props) {
|
||||
const [estimatedFee, setEstimatedFee] = useState(defaultFee)
|
||||
|
||||
const throttledEstimateExactIn = useMemo(() => asyncThrottle(estimateExactIn, 250), [])
|
||||
const { removeDeposits, addDeposits, addDebt } = useUpdatedAccount(account)
|
||||
|
||||
const borrowAsset = useMemo(
|
||||
() => borrowAssets.find(byDenom(sellAsset.denom)),
|
||||
@ -152,6 +155,37 @@ export default function SwapForm(props: Props) {
|
||||
setSellAssetAmount(BN_ZERO)
|
||||
}, [buyAsset.denom, sellAsset.denom])
|
||||
|
||||
const debouncedUpdateAccount = useMemo(
|
||||
() =>
|
||||
debounce((removeCoin: BNCoin, addCoin: BNCoin, debtCoin: BNCoin) => {
|
||||
removeDeposits([removeCoin])
|
||||
addDeposits([addCoin])
|
||||
if (debtCoin.amount.isGreaterThan(BN_ZERO)) addDebt([debtCoin])
|
||||
}, 1000),
|
||||
[removeDeposits, addDeposits, addDebt],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const removeDepositAmount = sellAssetAmount.isGreaterThanOrEqualTo(marginThreshold)
|
||||
? marginThreshold
|
||||
: sellAssetAmount
|
||||
const addDebtAmount = sellAssetAmount.isGreaterThan(marginThreshold)
|
||||
? sellAssetAmount.minus(marginThreshold)
|
||||
: BN_ZERO
|
||||
const removeCoin = BNCoin.fromDenomAndBigNumber(sellAsset.denom, removeDepositAmount)
|
||||
const debtCoin = BNCoin.fromDenomAndBigNumber(sellAsset.denom, addDebtAmount)
|
||||
const addCoin = BNCoin.fromDenomAndBigNumber(buyAsset.denom, buyAssetAmount)
|
||||
|
||||
debouncedUpdateAccount(removeCoin, addCoin, debtCoin)
|
||||
}, [
|
||||
sellAssetAmount,
|
||||
buyAssetAmount,
|
||||
marginThreshold,
|
||||
buyAsset.denom,
|
||||
sellAsset.denom,
|
||||
debouncedUpdateAccount,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
swapTx.estimateFee().then(setEstimatedFee)
|
||||
}, [swapTx])
|
||||
|
@ -3,14 +3,17 @@ import { useCallback, useEffect, useState } from 'react'
|
||||
import { addCoins, addValueToVaults, removeCoins } from 'hooks/useUpdatedAccount/functions'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { cloneAccount } from 'utils/accounts'
|
||||
import useStore from 'store'
|
||||
|
||||
export interface VaultValue {
|
||||
address: string
|
||||
value: BigNumber
|
||||
}
|
||||
|
||||
export function useUpdatedAccount(account: Account) {
|
||||
const [updatedAccount, setUpdatedAccount] = useState<Account>(cloneAccount(account))
|
||||
export function useUpdatedAccount(account?: Account) {
|
||||
const [updatedAccount, setUpdatedAccount] = useState<Account | undefined>(
|
||||
account ? cloneAccount(account) : undefined,
|
||||
)
|
||||
const [addedDeposits, addDeposits] = useState<BNCoin[]>([])
|
||||
const [removedDeposits, removeDeposits] = useState<BNCoin[]>([])
|
||||
const [addedDebt, addDebt] = useState<BNCoin[]>([])
|
||||
@ -19,6 +22,7 @@ export function useUpdatedAccount(account: Account) {
|
||||
|
||||
const removeDepositByDenom = useCallback(
|
||||
(denom: string) => {
|
||||
if (!account) return
|
||||
const deposit = account.deposits.find((deposit) => deposit.denom === denom)
|
||||
if (deposit) {
|
||||
removeDeposits([...removedDeposits, deposit])
|
||||
@ -28,17 +32,18 @@ export function useUpdatedAccount(account: Account) {
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
async function updateAccount() {
|
||||
const accountCopy = cloneAccount(account)
|
||||
accountCopy.deposits = addCoins(addedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = addCoins(addedDebt, [...accountCopy.debts])
|
||||
accountCopy.vaults = addValueToVaults(addedVaultValues, [...accountCopy.vaults])
|
||||
accountCopy.deposits = removeCoins(removedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = removeCoins(removedDebt, [...accountCopy.debts])
|
||||
setUpdatedAccount(accountCopy)
|
||||
}
|
||||
if (!account) return
|
||||
|
||||
updateAccount()
|
||||
const accountCopy = cloneAccount(account)
|
||||
accountCopy.deposits = addCoins(addedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = addCoins(addedDebt, [...accountCopy.debts])
|
||||
accountCopy.vaults = addValueToVaults(addedVaultValues, [...accountCopy.vaults])
|
||||
accountCopy.deposits = removeCoins(removedDeposits, [...accountCopy.deposits])
|
||||
accountCopy.debts = removeCoins(removedDebt, [...accountCopy.debts])
|
||||
setUpdatedAccount(accountCopy)
|
||||
useStore.setState({ updatedAccount: accountCopy })
|
||||
|
||||
return () => useStore.setState({ updatedAccount: undefined })
|
||||
}, [account, addedDebt, removedDebt, addedDeposits, removedDeposits, addedVaultValues])
|
||||
|
||||
return {
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { GetState, SetState } from 'zustand'
|
||||
|
||||
import { ASSETS } from 'constants/assets'
|
||||
|
||||
export default function createCommonSlice(set: SetState<CommonSlice>, get: GetState<CommonSlice>) {
|
||||
return {
|
||||
accounts: null,
|
||||
|
1
src/types/interfaces/store/common.d.ts
vendored
1
src/types/interfaces/store/common.d.ts
vendored
@ -5,6 +5,7 @@ interface CommonSlice {
|
||||
client?: WalletClient
|
||||
isOpen: boolean
|
||||
selectedAccount: string | null
|
||||
updatedAccount?: Account
|
||||
focusComponent: FocusComponent | null
|
||||
}
|
||||
|
||||
|
@ -16,24 +16,36 @@ export const calculateAccountBalanceValue = (
|
||||
const depositsValue = calculateAccountValue('deposits', account, prices)
|
||||
const lendsValue = calculateAccountValue('lends', account, prices)
|
||||
const debtsValue = calculateAccountValue('debts', account, prices)
|
||||
const vaultsValue = calculateAccountValue('vaults', account, prices)
|
||||
|
||||
return depositsValue.plus(lendsValue).minus(debtsValue)
|
||||
return depositsValue.plus(lendsValue).plus(vaultsValue).minus(debtsValue)
|
||||
}
|
||||
|
||||
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]
|
||||
const vaults = calculateAccountValue('vaults', account, prices)
|
||||
return [deposits, lends, debts, vaults]
|
||||
}
|
||||
|
||||
export const calculateAccountValue = (
|
||||
type: 'deposits' | 'lends' | 'debts',
|
||||
type: 'deposits' | 'lends' | 'debts' | 'vaults',
|
||||
account: Account | AccountChange,
|
||||
prices: BNCoin[],
|
||||
): BigNumber => {
|
||||
if (!account[type]) return BN_ZERO
|
||||
|
||||
if (type === 'vaults') {
|
||||
return (
|
||||
account.vaults?.reduce(
|
||||
(acc, vaultPosition) =>
|
||||
acc.plus(vaultPosition.values.primary).plus(vaultPosition.values.secondary),
|
||||
BN_ZERO,
|
||||
) || BN_ZERO
|
||||
).shiftedBy(-6)
|
||||
}
|
||||
|
||||
return account[type]?.reduce((acc, position) => {
|
||||
const asset = getAssetByDenom(position.denom)
|
||||
if (!asset) return acc
|
||||
@ -65,6 +77,11 @@ export const calculateAccountBorrowRate = (
|
||||
return BN_ZERO
|
||||
}
|
||||
|
||||
export function calculateAccountLeverage(account: Account, prices: BNCoin[]) {
|
||||
const [deposits, lends, debts, vaults] = getAccountPositionValues(account, prices)
|
||||
return debts.dividedBy(deposits.plus(lends).plus(vaults)).plus(1)
|
||||
}
|
||||
|
||||
export function getAmount(denom: string, coins: Coin[]): BigNumber {
|
||||
return BN(coins.find((asset) => asset.denom === denom)?.amount ?? 0)
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ export const formatValue = (amount: number | string, options?: FormatOptions): s
|
||||
|
||||
return returnValue
|
||||
}
|
||||
|
||||
export function formatHealth(health: number) {
|
||||
return formatValue(health, {
|
||||
minDecimals: 0,
|
||||
@ -134,7 +135,7 @@ export function formatHealth(health: number) {
|
||||
|
||||
export function formatLeverage(leverage: number) {
|
||||
return formatValue(leverage, {
|
||||
minDecimals: 0,
|
||||
minDecimals: 2,
|
||||
suffix: 'x',
|
||||
})
|
||||
}
|
||||
|
@ -3594,6 +3594,13 @@
|
||||
dependencies:
|
||||
"@types/lodash" "*"
|
||||
|
||||
"@types/lodash.debounce@^4.0.7":
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz#0285879defb7cdb156ae633cecd62d5680eded9f"
|
||||
integrity sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==
|
||||
dependencies:
|
||||
"@types/lodash" "*"
|
||||
|
||||
"@types/lodash.values@^4.3.6":
|
||||
version "4.3.7"
|
||||
resolved "https://registry.npmjs.org/@types/lodash.values/-/lodash.values-4.3.7.tgz"
|
||||
|
Loading…
Reference in New Issue
Block a user