From f9318dfe6e7bef1af99726ccad74871b5c41565a Mon Sep 17 00:00:00 2001 From: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:55:53 -0300 Subject: [PATCH] [CM details] support changes (#359) * [CM details] support changes * Update src/components/Trade/TradeModule/SwapForm/index.tsx Co-authored-by: Yusuf Seyrek * Update src/components/Trade/TradeModule/SwapForm/index.tsx Co-authored-by: Yusuf Seyrek * [HC] update to bncoin.from --------- Co-authored-by: Yusuf Seyrek --- .gitignore | 5 +- package.json | 2 + src/components/Account/AccountDetails.tsx | 80 +++++++++++++------ .../Modals/Vault/VaultModalContent.tsx | 2 +- .../Trade/TradeModule/SwapForm/index.tsx | 34 ++++++++ src/hooks/useUpdatedAccount/index.ts | 29 ++++--- src/store/slices/common.ts | 2 - src/types/interfaces/store/common.d.ts | 1 + src/utils/accounts.ts | 25 +++++- src/utils/formatters.ts | 3 +- yarn.lock | 7 ++ 11 files changed, 144 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 36c3731d..dd910e53 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,7 @@ next-env.d.ts .env.local.testnet .env.local.mainnet .env.production -.env \ No newline at end of file +.env + +# IDE +.idea \ No newline at end of file diff --git a/package.json b/package.json index e7d6c77d..daa7f6f5 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/Account/AccountDetails.tsx b/src/components/Account/AccountDetails.tsx index 3d85b09e..7ebeb862 100644 --- a/src/components/Account/AccountDetails.tsx +++ b/src/components/Account/AccountDetails.tsx @@ -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 } +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 (
-
- } /> +
+ } /> Health - +
+ + {updatedHealth && health !== updatedHealth && ( + <> + updatedHealth ? 'text-loss' : 'text-success')} + /> + + + )} +
-
+
- Balance + Leverage - + + {formatLeverage(leverage.toNumber())} + +
+
+ + Net worth + +
) diff --git a/src/components/Modals/Vault/VaultModalContent.tsx b/src/components/Modals/Vault/VaultModalContent.tsx index 4e7ba6b1..434dd4f2 100644 --- a/src/components/Modals/Vault/VaultModalContent.tsx +++ b/src/components/Modals/Vault/VaultModalContent.tsx @@ -102,7 +102,7 @@ export default function VaultModalContent(props: Props) { { renderContent: () => ( 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]) diff --git a/src/hooks/useUpdatedAccount/index.ts b/src/hooks/useUpdatedAccount/index.ts index 34be021d..e67c1b2e 100644 --- a/src/hooks/useUpdatedAccount/index.ts +++ b/src/hooks/useUpdatedAccount/index.ts @@ -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(cloneAccount(account)) +export function useUpdatedAccount(account?: Account) { + const [updatedAccount, setUpdatedAccount] = useState( + account ? cloneAccount(account) : undefined, + ) const [addedDeposits, addDeposits] = useState([]) const [removedDeposits, removeDeposits] = useState([]) const [addedDebt, addDebt] = useState([]) @@ -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 { diff --git a/src/store/slices/common.ts b/src/store/slices/common.ts index f361e148..deebd552 100644 --- a/src/store/slices/common.ts +++ b/src/store/slices/common.ts @@ -1,7 +1,5 @@ import { GetState, SetState } from 'zustand' -import { ASSETS } from 'constants/assets' - export default function createCommonSlice(set: SetState, get: GetState) { return { accounts: null, diff --git a/src/types/interfaces/store/common.d.ts b/src/types/interfaces/store/common.d.ts index 3854743f..0b47f88f 100644 --- a/src/types/interfaces/store/common.d.ts +++ b/src/types/interfaces/store/common.d.ts @@ -5,6 +5,7 @@ interface CommonSlice { client?: WalletClient isOpen: boolean selectedAccount: string | null + updatedAccount?: Account focusComponent: FocusComponent | null } diff --git a/src/utils/accounts.ts b/src/utils/accounts.ts index 58674b75..0a8b9c3d 100644 --- a/src/utils/accounts.ts +++ b/src/utils/accounts.ts @@ -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) } diff --git a/src/utils/formatters.ts b/src/utils/formatters.ts index 76cbbfff..b3f4da47 100644 --- a/src/utils/formatters.ts +++ b/src/utils/formatters.ts @@ -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', }) } diff --git a/yarn.lock b/yarn.lock index 674db576..f511a6f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"