mirror of
https://github.com/Instadapp/assembly.git
synced 2024-07-29 22:37:06 +00:00
549 lines
15 KiB
TypeScript
549 lines
15 KiB
TypeScript
import { AbiItem } from "web3-utils";
|
|
|
|
import aaveV2ABI from "~/abis/read/aaveV2.json";
|
|
import { computed, ref, watch } from "@nuxtjs/composition-api";
|
|
import { useDSA } from "~/composables/useDSA";
|
|
import { useWeb3 } from "@kabbouchi/vue-web3";
|
|
import BigNumber from "bignumber.js";
|
|
import atokensV2 from "~/constant/atokensV2";
|
|
import tokens from "~/constant/tokens";
|
|
import { Network, useNetwork } from "~/composables/useNetwork";
|
|
import { useBigNumber } from "~/composables/useBigNumber";
|
|
import { usePosition } from "~/composables/usePosition";
|
|
import { useToken } from "~/composables/useToken";
|
|
import { useSorting } from "~/composables/useSorting";
|
|
|
|
const {
|
|
times,
|
|
isZero,
|
|
div,
|
|
max,
|
|
gt,
|
|
minus,
|
|
ensureValue,
|
|
plus
|
|
} = useBigNumber();
|
|
const { getType } = usePosition();
|
|
|
|
const position = ref<any>({
|
|
totalSupplyInEth: new BigNumber(0),
|
|
totalBorrowInEth: new BigNumber(0),
|
|
totalBorrowStableInEth: new BigNumber(0),
|
|
totalBorrowVariableInEth: new BigNumber(0),
|
|
maxBorrowLimitInEth: new BigNumber(0),
|
|
maxBorrowLiquidityLimitInEth: new BigNumber(0),
|
|
ethPriceInUsd: "0",
|
|
data: []
|
|
});
|
|
const totalSupply = computed(() =>
|
|
position.value
|
|
? times(
|
|
position.value.totalSupplyInEth,
|
|
position.value.ethPriceInUsd
|
|
).toFixed()
|
|
: 0
|
|
);
|
|
|
|
const totalBorrow = computed(() =>
|
|
position.value
|
|
? times(
|
|
position.value.totalBorrowInEth,
|
|
position.value.ethPriceInUsd
|
|
).toFixed()
|
|
: 0
|
|
);
|
|
|
|
const ethPriceInUsd = computed(() => position.value?.ethPriceInUsd);
|
|
|
|
const annualPercentageRateTypes = computed(() => [
|
|
{ label: "Variable", value: "variable", rateMode: 2 },
|
|
{ label: "Stable", value: "stable", rateMode: 1 }
|
|
]);
|
|
|
|
export function useAaveV2Position(
|
|
{ overridePosition } = { overridePosition: null }
|
|
) {
|
|
overridePosition = overridePosition || (pos => pos);
|
|
|
|
const { library, chainId } = useWeb3();
|
|
const { activeNetworkId } = useNetwork();
|
|
const { activeAccount } = useDSA();
|
|
const { getTokenByKey, allATokensV2 } = useToken();
|
|
const { byMaxSupplyOrBorrowDesc } = useSorting();
|
|
|
|
const resolver = computed(() =>
|
|
chainId.value === 1
|
|
? "0xFb3a1D56eD56F046721B9aCa749895100754578b"
|
|
: "0xD6E0803d0eB34af8Ea135835512D7E77960b28F1"
|
|
);
|
|
|
|
const fetchPosition = async () => {
|
|
if (!library.value) {
|
|
return;
|
|
}
|
|
|
|
if (!activeAccount.value) {
|
|
return;
|
|
}
|
|
|
|
const aaveResolverInstance = new library.value.eth.Contract(
|
|
aaveV2ABI as AbiItem[],
|
|
resolver.value
|
|
);
|
|
|
|
const aaveTokensArr = atokensV2[activeNetworkId.value].allTokens.map(
|
|
a => tokens[activeNetworkId.value].getTokenByKey(a.root).address
|
|
);
|
|
|
|
const aaveRawData = await aaveResolverInstance.methods
|
|
.getPosition(activeAccount.value.address, aaveTokensArr)
|
|
.call();
|
|
|
|
const newPos = calculateAavePosition(aaveRawData, activeNetworkId.value);
|
|
|
|
return newPos;
|
|
};
|
|
|
|
const refreshPosition = async () => {
|
|
position.value = await fetchPosition();
|
|
};
|
|
|
|
watch(
|
|
library,
|
|
async val => {
|
|
if (val) {
|
|
refreshPosition();
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
watch(
|
|
activeAccount,
|
|
async val => {
|
|
if (val) {
|
|
refreshPosition();
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
const stats = computed(() =>
|
|
displayPositions.value.reduce(
|
|
(stats, { key, supply, borrow, priceInEth, factor, liquidation }) => {
|
|
if (key === "eth") {
|
|
stats.ethSupplied = supply;
|
|
}
|
|
|
|
stats.totalSupplyInEth = plus(
|
|
stats.totalSupplyInEth,
|
|
times(supply, priceInEth)
|
|
).toFixed();
|
|
stats.totalBorrowInEth = plus(
|
|
stats.totalBorrowInEth,
|
|
times(borrow, priceInEth)
|
|
).toFixed();
|
|
stats.totalMaxBorrowLimitInEth = plus(
|
|
stats.totalMaxBorrowLimitInEth,
|
|
times(supply, times(priceInEth, factor))
|
|
).toFixed();
|
|
stats.totalMaxLiquidationLimitInEth = plus(
|
|
stats.totalMaxLiquidationLimitInEth,
|
|
times(supply, times(priceInEth, liquidation))
|
|
).toFixed();
|
|
|
|
return stats;
|
|
},
|
|
{
|
|
totalSupplyInEth: "0",
|
|
totalBorrowInEth: "0",
|
|
totalMaxBorrowLimitInEth: "0",
|
|
totalMaxLiquidationLimitInEth: "0",
|
|
ethSupplied: "0"
|
|
}
|
|
)
|
|
);
|
|
|
|
const rewardTokenPriceInUsd = computed(() => {
|
|
if (activeNetworkId.value === Network.Polygon) {
|
|
return ensureValue(
|
|
position.value.data.find(position => position.key === "matic")
|
|
?.priceInUsd
|
|
);
|
|
}
|
|
return ensureValue(
|
|
position.value.data.find(position => position.key === "aave")?.priceInUsd
|
|
);
|
|
});
|
|
|
|
const displayPositions = computed(() => {
|
|
if (!position.value) {
|
|
return [];
|
|
}
|
|
|
|
return allATokensV2.value
|
|
.flatMap(atoken => {
|
|
const token = getTokenByKey(atoken.root);
|
|
|
|
const atokenPosition = position.value.data.find(
|
|
x => x.key === atoken.root
|
|
);
|
|
|
|
const p = getPositionOrDefaultPosition(token, atokenPosition);
|
|
|
|
if (gt(p.supply, "0") && gt(p.borrow, "0")) {
|
|
return [
|
|
{ ...p, type: "supply" },
|
|
{ ...p, type: "borrow" }
|
|
];
|
|
} else {
|
|
return [p];
|
|
}
|
|
})
|
|
.sort((a, b) =>
|
|
minus(
|
|
max(b.supplyUsd, b.borrowUsd),
|
|
max(a.supplyUsd, a.borrowUsd)
|
|
).toNumber()
|
|
)
|
|
.map(overridePosition)
|
|
.sort(byMaxSupplyOrBorrowDesc);
|
|
});
|
|
|
|
function getPositionOrDefaultPosition(token, position) {
|
|
if (!position) {
|
|
const defaultPosition = {
|
|
key: token.key,
|
|
aTokenKey: "",
|
|
aTokenBal: "0",
|
|
aDecimals: "0",
|
|
cf: "0",
|
|
ll: "0",
|
|
supply: "0",
|
|
supplyUsd: "0",
|
|
supplyRate: "0",
|
|
borrow: "0",
|
|
borrowUsd: "0",
|
|
borrowRate: "0",
|
|
type: "no",
|
|
isEnabledAsCollateral: true,
|
|
borrowEnabled: true,
|
|
availableLiquidity: "0",
|
|
stableBorrowEnabled: true,
|
|
borrowStable: "0",
|
|
borrowStableRate: "0",
|
|
supplyRewardRate: "0",
|
|
borrowRewardRate: "0"
|
|
};
|
|
|
|
return defaultPosition;
|
|
}
|
|
|
|
return {
|
|
key: token.key,
|
|
aTokenKey: position.aTokenKey,
|
|
aTokenBal: position.aTokenBal,
|
|
aDecimals: position.aDecimals,
|
|
cf: position.factor,
|
|
ll: position.liquidation,
|
|
factor: position.factor,
|
|
liquidation: position.liquidation,
|
|
supply: position.supply,
|
|
supplyUsd: times(position.supply, position.priceInUsd).toFixed(),
|
|
supplyRate: position.supplyRate,
|
|
borrow: position.borrow,
|
|
borrowUsd: times(position.borrow, position.priceInUsd).toFixed(),
|
|
borrowRate: position.borrowRate,
|
|
priceInEth: position.priceInEth,
|
|
type: getType(position),
|
|
isEnabledAsCollateral: position.isEnabledAsCollateral,
|
|
borrowEnabled: position.borrowEnabled,
|
|
availableLiquidity: position.availableLiquidity,
|
|
borrowStableUsd: times(
|
|
position.borrowStable,
|
|
position.priceInUsd
|
|
).toFixed(),
|
|
stableBorrowEnabled: position.stableBorrowEnabled,
|
|
borrowStable: position.borrowStable,
|
|
borrowStableRate: position.borrowStableRate,
|
|
priceInUsd: position.priceInUsd,
|
|
supplyRewardRate: times(
|
|
position.supplyRewardRate,
|
|
rewardTokenPriceInUsd.value
|
|
).toFixed(),
|
|
borrowRewardRate: times(
|
|
position.borrowRewardRate,
|
|
rewardTokenPriceInUsd.value
|
|
).toFixed()
|
|
};
|
|
}
|
|
|
|
const maxLiquidation = computed(() => {
|
|
if (isZero(stats.value.totalSupplyInEth)) return "0";
|
|
|
|
return max(
|
|
div(
|
|
stats.value.totalMaxLiquidationLimitInEth,
|
|
stats.value.totalSupplyInEth
|
|
),
|
|
"0"
|
|
).toFixed();
|
|
});
|
|
|
|
const liquidationPrice = computed(() => {
|
|
if (isZero(stats.value.ethSupplied)) return "0";
|
|
|
|
return max(
|
|
times(
|
|
div(
|
|
stats.value.totalBorrowInEth,
|
|
stats.value.totalMaxLiquidationLimitInEth
|
|
),
|
|
ethPriceInUsd.value
|
|
),
|
|
"0"
|
|
).toFixed();
|
|
});
|
|
|
|
const status = computed(() => {
|
|
if (
|
|
isZero(stats.value.totalSupplyInEth) &&
|
|
!isZero(stats.value.totalBorrowInEth)
|
|
)
|
|
return "1.1";
|
|
if (isZero(stats.value.totalSupplyInEth)) return "0";
|
|
|
|
return max(
|
|
div(stats.value.totalBorrowInEth, stats.value.totalSupplyInEth),
|
|
"0"
|
|
).toFixed();
|
|
});
|
|
|
|
const liquidation = computed(() => {
|
|
if (isZero(stats.value.totalSupplyInEth)) return "0";
|
|
|
|
return max(
|
|
div(stats.value.totalMaxBorrowLimitInEth, stats.value.totalSupplyInEth),
|
|
"0"
|
|
).toFixed();
|
|
});
|
|
|
|
return {
|
|
stats,
|
|
displayPositions,
|
|
position,
|
|
fetchPosition,
|
|
refreshPosition,
|
|
totalSupply,
|
|
totalBorrow,
|
|
status,
|
|
liquidation,
|
|
maxLiquidation,
|
|
liquidationPrice,
|
|
liquidationMaxPrice: ethPriceInUsd,
|
|
annualPercentageRateTypes
|
|
};
|
|
}
|
|
|
|
function calculateAavePosition(res: any[], network: Network = Network.Mainnet) {
|
|
try {
|
|
const newPos = {
|
|
totalSupplyInEth: new BigNumber(0),
|
|
totalBorrowInEth: new BigNumber(0),
|
|
totalBorrowStableInEth: new BigNumber(0),
|
|
totalBorrowVariableInEth: new BigNumber(0),
|
|
maxBorrowLimitInEth: new BigNumber(0),
|
|
maxBorrowLiquidityLimitInEth: new BigNumber(0)
|
|
// tokens: {},
|
|
};
|
|
const dataPos = [];
|
|
atokensV2[network].allTokens.forEach((atoken, i) => {
|
|
const key = atoken.address;
|
|
|
|
/* eslint-disable no-unused-vars */
|
|
const [
|
|
priceInEthInWei,
|
|
priceInUsdInWei,
|
|
supplyBalanceInWei,
|
|
borrowStableBalanceInWei,
|
|
borrowVariableBalanceInWei,
|
|
supplyRatePerBlock,
|
|
borrowStableRatePerBlock,
|
|
userStableBorrowRatePerBlock,
|
|
borrowVariableRatePerBlock,
|
|
isCollateralEnabled,
|
|
AaveTokenData
|
|
] = res[0][i];
|
|
|
|
const [
|
|
ltv,
|
|
threshold,
|
|
reserveFactor,
|
|
usageAsCollEnabled,
|
|
borrowEnabled,
|
|
stableBorrowEnabled,
|
|
isActive,
|
|
isFrozen,
|
|
totalSupply,
|
|
availableLiquidity,
|
|
totalStableDebt,
|
|
totalVariableDebt,
|
|
collateralEmission,
|
|
debtEmission
|
|
] = AaveTokenData;
|
|
/* eslint-enable no-unused-vars */
|
|
|
|
const decimals = tokens[network].getTokenByKey(atoken.root).decimals;
|
|
const root = atoken.root;
|
|
const factor = new BigNumber(ltv).dividedBy(1e4);
|
|
const priceInEth = new BigNumber(priceInEthInWei).dividedBy(1e18);
|
|
const priceInUsd = new BigNumber(priceInUsdInWei)
|
|
.dividedBy(1e18)
|
|
.toFixed();
|
|
const supply = new BigNumber(supplyBalanceInWei).dividedBy(
|
|
10 ** decimals
|
|
);
|
|
const borrowStable = new BigNumber(borrowStableBalanceInWei).dividedBy(
|
|
10 ** decimals
|
|
);
|
|
const borrowVariable = new BigNumber(
|
|
borrowVariableBalanceInWei
|
|
).dividedBy(10 ** decimals);
|
|
const supplyRate = new BigNumber(supplyRatePerBlock)
|
|
.dividedBy(1e27)
|
|
.toFixed();
|
|
const supplyYield = supplyRate;
|
|
const borrowStableRate = new BigNumber(borrowStableRatePerBlock)
|
|
.dividedBy(1e27)
|
|
.toFixed();
|
|
const userBorrowStableRate = new BigNumber(userStableBorrowRatePerBlock)
|
|
.dividedBy(1e27)
|
|
.toFixed();
|
|
const borrowVariableRate = new BigNumber(borrowVariableRatePerBlock)
|
|
.dividedBy(1e27)
|
|
.toFixed();
|
|
const borrowStableYield = borrowStableRate;
|
|
const borrowVariableYield = borrowVariableRate;
|
|
const liquidity = new BigNumber(availableLiquidity)
|
|
.dividedBy(10 ** decimals)
|
|
.multipliedBy(0.9999)
|
|
.toFixed();
|
|
const totalSupplied = new BigNumber(totalSupply)
|
|
.dividedBy(10 ** decimals)
|
|
.multipliedBy(priceInUsd);
|
|
const totalDebt = new BigNumber(totalVariableDebt)
|
|
.dividedBy(10 ** decimals)
|
|
.multipliedBy(priceInUsd);
|
|
const supplyRewardRate = new BigNumber(collateralEmission)
|
|
.multipliedBy(31536000)
|
|
.dividedBy(1e18)
|
|
.dividedBy(totalSupplied)
|
|
.toFixed();
|
|
const borrowRewardRate = new BigNumber(debtEmission)
|
|
.multipliedBy(31536000)
|
|
.dividedBy(1e18)
|
|
.dividedBy(totalDebt)
|
|
.toFixed();
|
|
|
|
newPos.totalSupplyInEth = newPos.totalSupplyInEth.plus(
|
|
supply.multipliedBy(priceInEth)
|
|
);
|
|
newPos.maxBorrowLimitInEth = newPos.maxBorrowLimitInEth.plus(
|
|
supply.multipliedBy(priceInEth).multipliedBy(factor)
|
|
);
|
|
newPos.maxBorrowLiquidityLimitInEth = newPos.maxBorrowLiquidityLimitInEth.plus(
|
|
supply
|
|
.multipliedBy(priceInEth)
|
|
.multipliedBy((threshold / 10000).toString())
|
|
);
|
|
newPos.totalBorrowInEth = newPos.totalBorrowInEth.plus(
|
|
borrowStable.plus(borrowVariable).multipliedBy(priceInEth)
|
|
);
|
|
newPos.totalBorrowStableInEth = newPos.totalBorrowStableInEth.plus(
|
|
borrowStable.multipliedBy(priceInEth)
|
|
);
|
|
newPos.totalBorrowVariableInEth = newPos.totalBorrowVariableInEth.plus(
|
|
borrowVariable.multipliedBy(priceInEth)
|
|
);
|
|
|
|
dataPos.push({
|
|
key: root,
|
|
aTokenAddr: key,
|
|
aTokenBal: supplyBalanceInWei,
|
|
aTokenKey: atoken.key,
|
|
aDecimals: atoken.decimals.toString(),
|
|
priceInEth: priceInEth.toFixed(),
|
|
priceInUsd,
|
|
supply: supply.toFixed(),
|
|
borrowStable: borrowStable.toFixed(),
|
|
borrow: borrowVariable.toFixed(), // TODO: change later
|
|
supplyRate,
|
|
supplyYield,
|
|
borrowStableRate,
|
|
userBorrowStableRate,
|
|
borrowStableYield,
|
|
borrowRate: borrowVariableRate, // TODO: change later
|
|
borrowYield: borrowVariableYield, // TODO: change later
|
|
factor: factor.toFixed(),
|
|
liquidation: (threshold / 10000).toString(),
|
|
isEnabledAsCollateral: isCollateralEnabled,
|
|
borrowEnabled,
|
|
stableBorrowEnabled,
|
|
availableLiquidity: liquidity,
|
|
supplyRewardRate,
|
|
borrowRewardRate
|
|
});
|
|
});
|
|
|
|
const totalSupplyInEthIsZero = newPos.totalSupplyInEth.isZero();
|
|
const status = totalSupplyInEthIsZero
|
|
? 0
|
|
: newPos.totalBorrowInEth.dividedBy(newPos.totalSupplyInEth).toFixed();
|
|
const liquidation = totalSupplyInEthIsZero
|
|
? 0
|
|
: newPos.maxBorrowLimitInEth.dividedBy(newPos.totalSupplyInEth).toFixed();
|
|
const maxLiquidation = totalSupplyInEthIsZero
|
|
? 0
|
|
: newPos.maxBorrowLiquidityLimitInEth
|
|
.dividedBy(newPos.totalSupplyInEth)
|
|
.toFixed();
|
|
const ethPrice = new BigNumber(res[1].ethPriceInUsd)
|
|
.dividedBy(1e8)
|
|
.toFixed();
|
|
const pendingRewards = new BigNumber(res[1].pendingRewards)
|
|
.dividedBy(1e18)
|
|
.toFixed();
|
|
|
|
// @ts-ignore
|
|
newPos.totalSupplyInEth = newPos.totalSupplyInEth.toFixed();
|
|
// @ts-ignore
|
|
newPos.totalBorrowInEth = newPos.totalBorrowInEth.toFixed();
|
|
// @ts-ignore
|
|
newPos.maxBorrowLimitInEth = newPos.maxBorrowLimitInEth.toFixed();
|
|
// @ts-ignore
|
|
newPos.totalBorrowStableInEth = newPos.totalBorrowStableInEth.toFixed();
|
|
// @ts-ignore
|
|
newPos.maxBorrowLiquidityLimitInEth = newPos.maxBorrowLiquidityLimitInEth.toFixed();
|
|
// @ts-ignore
|
|
newPos.totalBorrowVariableInEth = newPos.totalBorrowVariableInEth.toFixed();
|
|
|
|
// @ts-ignore
|
|
newPos.status = status;
|
|
// @ts-ignore
|
|
newPos.liquidation = liquidation;
|
|
// @ts-ignore
|
|
newPos.maxLiquidation = maxLiquidation;
|
|
// @ts-ignore
|
|
newPos.ethPriceInUsd = ethPrice;
|
|
// @ts-ignore
|
|
newPos.pendingRewards = pendingRewards;
|
|
// @ts-ignore
|
|
newPos.data = dataPos;
|
|
|
|
return newPos;
|
|
} catch (error) {
|
|
console.error(error);
|
|
return Promise.reject(error);
|
|
}
|
|
}
|