import { computed, Ref, ref, watch } from "@nuxtjs/composition-api"; import { useBalances } from "../useBalances"; import { useBigNumber } from "../useBigNumber"; import { useToken } from "../useToken"; import { useWeb3 } from "@instadapp/vue-web3"; import { AbiItem } from "web3-utils"; import BigNumber from "bignumber.js"; BigNumber.config({ POW_PRECISION: 200 }); import abis from "~/constant/abis"; import addresses from "~/constant/addresses"; import { useDSA } from "../useDSA"; import useEventBus from "../useEventBus"; export const trove = ref({ collateral: "0", debt: "0", stabilityAmount: "0", stabilityEthGain: "0", stabilityLqtyGain: "0", stakeAmount: "0", stakeEthGain: "0", stakeLqtyGain: "0", price: "0", ratio: "0", tokenKey: "eth", token: "ETH", liquidation: "0" }); export const troveTypes = ref([ { totalCollateral: "0", price: "0", totalRatio: "0", tokenKey: "eth", token: "ETH", isRecoveryMode: false, borrowFee: "0", liquidation: "0", minDebt: "2000", liquidationReserve: "200" } ]); export const troveOverallDetails = computed(() => troveTypes.value.find(t => t.tokenKey === trove.value.tokenKey) ); export function useLiquityPosition( collateralAmountRef: Ref = null, debtAmountRef: Ref = null ) { const { library } = useWeb3(); const { onEvent } = useEventBus() const { activeAccount } = useDSA(); const { isZero, times, div, max, minus, plus } = useBigNumber(); const { getTokenByKey, valInt } = useToken(); const { prices } = useBalances(); const collateralToken = computed(() => getTokenByKey("eth")); const debtToken = computed(() => getTokenByKey("lusd")); const poolToken = computed(() => getTokenByKey('lusd')) const stakingToken = computed(() => getTokenByKey("lqty")); const collateral = computed(() => trove.value.collateral); const collateralInWei = computed(() => valInt(collateral.value, collateralToken.value?.decimals) ); const priceInUsd = computed(() => trove.value.price); const ratio = computed(() => trove.value.ratio); const debt = computed(() => trove.value.debt); const debtInWei = computed(() => valInt(debt.value, debtToken.value?.decimals)) const collateralUsd = computed(() => times(collateral.value, priceInUsd.value).toFixed() ); const stabilityAmount = computed(() => trove.value.stabilityAmount); const stabilityEthGain = computed(() => trove.value.stabilityEthGain) const stabilityLqtyGain = computed(() => trove.value.stabilityLqtyGain) const debtUsd = computed(() => times(debt.value, "1").toFixed()); const stabilityAmountUsd = computed(() => times(stabilityAmount.value, "1").toFixed() ); const stakingTokenPrice = computed(() => stakingToken.value ? prices.mainnet[stakingToken.value.address] : "0" ); const stakeAmount = computed(() => trove.value.stakeAmount); const stakeEthGain = computed(() => trove.value.stakeEthGain); const stakeLqtyGain = computed(() => trove.value.stakeLqtyGain); const stakingAmountUsd = computed(() => times(stakeAmount.value, stakingTokenPrice.value).toFixed() ); const netValue = computed(() => plus( plus(minus(collateralUsd.value, debtUsd.value), stabilityAmountUsd.value), stakingAmountUsd.value ).toFixed() ); const borrowFee = computed(() => troveOverallDetails.value.borrowFee); const maxFeePercentageInWei = computed(() => times(times(borrowFee.value, "100"), "1e18").toFixed() ); const liquidation = computed(() => troveOverallDetails.value.liquidation); const status = computed(() => { if (!collateralAmountRef || !debtAmountRef) return ratio.value; return isZero(collateralAmountRef.value) && !isZero(debtAmountRef.value) ? "1.1" : div( debtAmountRef.value, times(collateralAmountRef.value, priceInUsd.value) ).toFixed(); }); const liquidationPrice = computed(() => { if (!collateralAmountRef || !debtAmountRef) { return max( div(div(debt.value, collateral.value), liquidation.value), "0" ).toFixed(); } return isZero(collateralAmountRef.value) && !isZero(debtAmountRef.value) ? times(priceInUsd.value, "1.1").toFixed() : max( div( div(debtAmountRef.value, collateralAmountRef.value), liquidation.value ), "0" ).toFixed(); }); const troveOpened = computed( () => !isZero(collateral.value) && !isZero(debt.value) ); const minDebt = computed(() => troveOverallDetails.value.minDebt); const liquidationReserve = computed( () => troveOverallDetails.value.liquidationReserve ); const fetchPosition = async () => { if (!library.value) { return; } troveTypes.value = await getTroveTypes(library.value); if (!activeAccount.value) { return; } trove.value = await getTrove(activeAccount.value.address, library.value); }; async function getTrovePositionHints(collateralInWei, debtInWei) { try { const liquityInstance = new library.value.eth.Contract( abis.resolver.liquity as AbiItem[], addresses.mainnet.resolver.liquity ); const { upperHint, lowerHint } = await liquityInstance.methods .getTrovePositionHints( collateralInWei.toString(), debtInWei.toString(), 0, 0 ) .call(); return { upperHint, lowerHint }; } catch (error) { return Promise.reject(error); } } onEvent("protocol::liquity::refresh", fetchPosition); watch( library, async val => { if (val) { fetchPosition(); } }, { immediate: true } ); watch( activeAccount, async val => { if (val) { fetchPosition(); } }, { immediate: true } ); return { fetchPosition, troveOpened, netValue, borrowFee, status, liquidation, liquidationPrice, liquidationMaxPrice: priceInUsd, collateralToken, debtToken, minDebt, liquidationReserve, maxFeePercentageInWei, getTrovePositionHints, collateral, collateralInWei, collateralUsd, priceInUsd, debt, debtInWei, poolToken, stabilityAmount, stabilityEthGain, stabilityLqtyGain, }; } async function getTrove(user, web3) { const resolveABI = abis.resolver.liquity; const resolveAddr = addresses.mainnet.resolver.liquity; const liquityInstance = new web3.eth.Contract( resolveABI as AbiItem[], resolveAddr ); try { const { trove, stake, stability } = await liquityInstance.methods.getPosition(user).call(); const { collateral, debt, icr, price } = trove; const ratio = icr === "115792089237316195423570985008687907853269984665640564039457584007913129639935" ? "0" : new BigNumber(1e18).dividedBy(icr).toString(); return { collateral: new BigNumber(collateral).dividedBy(1e18).toString(), debt: new BigNumber(debt).dividedBy(1e18).toString(), stabilityAmount: new BigNumber(stability.deposit) .dividedBy(1e18) .toString(), stabilityEthGain: new BigNumber(stability.ethGain) .dividedBy(1e18) .toString(), stabilityLqtyGain: new BigNumber(stability.lqtyGain) .dividedBy(1e18) .toString(), stakeAmount: new BigNumber(stake.amount).dividedBy(1e18).toString(), stakeEthGain: new BigNumber(stake.ethGain).dividedBy(1e18).toString(), stakeLqtyGain: new BigNumber(stake.lusdGain).dividedBy(1e18).toString(), price: new BigNumber(price).dividedBy(1e18).toString(), ratio, tokenKey: "eth", token: "ETH", liquidation: ratio }; } catch (error) { console.error(error); return {}; } } async function getTroveTypes(web3) { try { const resolveABI = abis.resolver.liquity; const resolveAddr = addresses.mainnet.resolver.liquity; const liquityInstance = new web3.eth.Contract( resolveABI as AbiItem[], resolveAddr ); const { borrowFee, ethTvl, isInRecoveryMode: isRecoveryMode, tcr, price } = await liquityInstance.methods.getSystemState().call(); return [ { totalCollateral: new BigNumber(ethTvl).dividedBy(1e18).toString(), price: new BigNumber(price).dividedBy(1e18).toString(), totalRatio: new BigNumber(1e18).dividedBy(tcr).toString(), tokenKey: "eth", token: "ETH", isRecoveryMode, borrowFee: new BigNumber(borrowFee).dividedBy(1e18).toString(), liquidation: new BigNumber(100).dividedBy(110).toString(), minDebt: new BigNumber(2000).toString(), liquidationReserve: "200" } ]; } catch (error) { return []; } }