169 lines
5.1 KiB
TypeScript
169 lines
5.1 KiB
TypeScript
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
|
import usePrices from 'hooks/usePrices'
|
|
import useAssetParams from 'hooks/useAssetParams'
|
|
import {
|
|
AssetParamsBaseForAddr,
|
|
HealthComputer,
|
|
} from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
|
import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams.types'
|
|
import useVaultConfigs from 'hooks/useVaultConfigs'
|
|
import {
|
|
BorrowTarget,
|
|
compute_health_js,
|
|
max_borrow_estimate_js,
|
|
max_swap_estimate_js,
|
|
max_withdraw_estimate_js,
|
|
SwapKind,
|
|
} from 'utils/health_computer'
|
|
import { convertAccountToPositions } from 'utils/accounts'
|
|
import {
|
|
Positions,
|
|
VaultPositionValue,
|
|
} from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
|
import useStore from 'store'
|
|
import { BN_ZERO } from 'constants/math'
|
|
import { BN } from 'utils/helpers'
|
|
|
|
export default function useHealthComputer(account?: Account) {
|
|
const { data: prices } = usePrices()
|
|
const { data: assetParams } = useAssetParams()
|
|
const { data: vaultConfigs } = useVaultConfigs()
|
|
const baseCurrency = useStore((s) => s.baseCurrency)
|
|
|
|
const [health, setHealth] = useState(0)
|
|
const positions: Positions | null = useMemo(() => {
|
|
if (!account) return null
|
|
return convertAccountToPositions(account)
|
|
}, [account])
|
|
const baseCurrencyPrice = useMemo(
|
|
() => prices.find((price) => price.denom === baseCurrency.denom)?.amount || 0,
|
|
[prices, baseCurrency.denom],
|
|
)
|
|
|
|
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 },
|
|
)
|
|
}, [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 },
|
|
)
|
|
}, [prices, baseCurrency.denom])
|
|
|
|
const denomsData = useMemo(
|
|
() =>
|
|
assetParams.reduce(
|
|
(prev, curr) => {
|
|
prev[curr.denom] = curr
|
|
|
|
return prev
|
|
},
|
|
{} as { [key: string]: AssetParamsBaseForAddr },
|
|
),
|
|
[assetParams],
|
|
)
|
|
|
|
const vaultConfigsData = useMemo(() => {
|
|
if (!positions || !vaultConfigs.length) return null
|
|
|
|
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 },
|
|
)
|
|
}, [vaultConfigs, positions])
|
|
|
|
const healthComputer: HealthComputer | null = useMemo(() => {
|
|
if (
|
|
!positions ||
|
|
!vaultPositionValues ||
|
|
!vaultConfigsData ||
|
|
Object.keys(denomsData).length === 0 ||
|
|
Object.keys(priceData).length === 0 ||
|
|
positions.vaults.length !== Object.keys(vaultPositionValues).length
|
|
)
|
|
return null
|
|
|
|
return {
|
|
denoms_data: { params: denomsData, prices: priceData },
|
|
vaults_data: {
|
|
vault_configs: vaultConfigsData,
|
|
vault_values: vaultPositionValues,
|
|
},
|
|
positions: positions,
|
|
kind: 'default',
|
|
}
|
|
}, [priceData, denomsData, vaultConfigsData, vaultPositionValues, positions])
|
|
|
|
useEffect(() => {
|
|
if (!healthComputer) return
|
|
setHealth(Number(compute_health_js(healthComputer).max_ltv_health_factor) || 0)
|
|
}, [healthComputer])
|
|
|
|
const computeMaxBorrowAmount = useCallback(
|
|
(denom: string, target: BorrowTarget) => {
|
|
if (!healthComputer) return BN_ZERO
|
|
return BN(max_borrow_estimate_js(healthComputer, denom, target))
|
|
},
|
|
[healthComputer],
|
|
)
|
|
|
|
const computeMaxWithdrawAmount = useCallback(
|
|
(denom: string) => {
|
|
if (!healthComputer) return BN_ZERO
|
|
return BN(max_withdraw_estimate_js(healthComputer, denom))
|
|
},
|
|
[healthComputer],
|
|
)
|
|
|
|
const computeMaxSwapAmount = useCallback(
|
|
(from: string, to: string, kind: SwapKind) => {
|
|
if (!healthComputer) return BN_ZERO
|
|
try {
|
|
return BN(max_swap_estimate_js(healthComputer, from, to, kind))
|
|
} catch {
|
|
return BN_ZERO
|
|
}
|
|
},
|
|
[healthComputer],
|
|
)
|
|
|
|
return { health, computeMaxBorrowAmount, computeMaxWithdrawAmount, computeMaxSwapAmount }
|
|
}
|