mars-v2-frontend/src/hooks/useHealthComputer.tsx
2023-08-11 15:46:35 -03:00

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 }
}