mirror of
https://github.com/Instadapp/assembly.git
synced 2024-07-29 22:37:06 +00:00
280 lines
7.7 KiB
TypeScript
280 lines
7.7 KiB
TypeScript
import {
|
|
computed,
|
|
reactive,
|
|
onMounted,
|
|
useContext,
|
|
watch
|
|
} from "@nuxtjs/composition-api";
|
|
import BigNumber from "bignumber.js";
|
|
import abis from "~/constant/abis";
|
|
import addresses from "~/constant/addresses";
|
|
import tokens from "~/constant/tokens";
|
|
import uniPoolTokens from "~/constant/uniPoolTokens";
|
|
import { useDSA } from "./useDSA";
|
|
import { Network } from "./useNetwork";
|
|
import { useWeb3 } from "./useWeb3";
|
|
import Web3 from "web3";
|
|
import { AbiItem } from "web3-utils";
|
|
import { useToken } from "./useToken";
|
|
import { useBigNumber } from "./useBigNumber";
|
|
import { useSorting } from "./useSorting";
|
|
|
|
const balances = reactive({
|
|
user: null,
|
|
dsa: null
|
|
});
|
|
|
|
const prices = reactive({
|
|
mainnet: {},
|
|
polygon: {}
|
|
});
|
|
|
|
export function useBalances() {
|
|
const { $axios } = useContext();
|
|
const { times, plus, ensureValue } = useBigNumber();
|
|
const { account, networkName, web3 } = useWeb3();
|
|
const { activeAccount } = useDSA();
|
|
const { getTokenByKey } = useToken();
|
|
const { by } = useSorting();
|
|
|
|
onMounted(async () => {
|
|
prices.mainnet = await $axios.$get("https://api.internal.instadapp.io/defi/prices");
|
|
prices.polygon = await $axios.$get(
|
|
"https://api.internal.instadapp.io/defi/polygon/prices"
|
|
);
|
|
});
|
|
const fetchBalances = async (refresh = false) => {
|
|
if (!balances.user || refresh) {
|
|
if (!account.value) return;
|
|
balances.user = {
|
|
mainnet:
|
|
networkName.value === Network.Mainnet
|
|
? await getBalances(account.value, Network.Mainnet, web3.value)
|
|
: {},
|
|
polygon:
|
|
networkName.value === Network.Polygon
|
|
? await getBalances(account.value, Network.Polygon, web3.value)
|
|
: {}
|
|
};
|
|
}
|
|
|
|
if (!balances.dsa || refresh) {
|
|
if (!activeAccount.value) return;
|
|
|
|
balances.dsa = {
|
|
mainnet:
|
|
networkName.value === Network.Mainnet
|
|
? await getBalances(
|
|
activeAccount.value.address,
|
|
Network.Mainnet,
|
|
web3.value
|
|
)
|
|
: {},
|
|
polygon:
|
|
networkName.value === Network.Polygon
|
|
? await getBalances(
|
|
activeAccount.value.address,
|
|
Network.Polygon,
|
|
web3.value
|
|
)
|
|
: {}
|
|
};
|
|
}
|
|
};
|
|
|
|
const getBalanceByKey = (tokenKey, network = null, type = "dsa") => {
|
|
return getBalanceByAddress(getTokenByKey(tokenKey)?.address, network, type);
|
|
};
|
|
|
|
const getBalanceByAddress = (address, network = null, type = "dsa") => {
|
|
return (
|
|
balances[type]?.[network || networkName.value][address]?.balance || "0"
|
|
);
|
|
};
|
|
|
|
const getBalanceRawByKey = (tokenKey, network = null, type = "dsa") => {
|
|
return (
|
|
balances[type]?.[network || networkName.value][
|
|
getTokenByKey(tokenKey)?.address
|
|
]?.raw || "0"
|
|
);
|
|
};
|
|
|
|
const netWorth = (address, type = "dsa") => {
|
|
const balance = getBalanceByAddress(address, networkName.value, type);
|
|
const price = ensureValue(prices[networkName.value][address]).toFixed();
|
|
|
|
return times(balance, price).toFixed();
|
|
};
|
|
|
|
const balanceTotal = computed(() =>
|
|
tokens[networkName.value].allTokens.reduce(
|
|
(totalNetWorth, token) =>
|
|
plus(totalNetWorth, netWorth(token.address)).toFixed(),
|
|
"0"
|
|
)
|
|
);
|
|
|
|
const getAssets = (type = "dsa") => {
|
|
return tokens[networkName.value].allTokens
|
|
.map(token => ({
|
|
...token,
|
|
balance: getBalanceByAddress(token.address, networkName.value, type),
|
|
netWorth: netWorth(token.address, type)
|
|
}))
|
|
.sort(by("-netWorth"));
|
|
};
|
|
|
|
watch(web3, () => {
|
|
fetchBalances(true);
|
|
});
|
|
return {
|
|
balances,
|
|
fetchBalances,
|
|
getBalanceByKey,
|
|
getBalanceRawByKey,
|
|
balanceTotal,
|
|
prices,
|
|
getAssets
|
|
};
|
|
}
|
|
|
|
async function getBalances(
|
|
owner,
|
|
network: Network,
|
|
web3: Web3,
|
|
additionalTokens = []
|
|
) {
|
|
try {
|
|
const tokenResolverABI = abis.resolver.balance;
|
|
const tokenResolverAddr = addresses[network].resolver.balance;
|
|
|
|
const tokensArr = tokens[network].allTokens;
|
|
const tokensList =
|
|
network === Network.Mainnet
|
|
? [...tokensArr, ...uniPoolTokens[network].allTokens]
|
|
: tokensArr;
|
|
|
|
let tokensAddrArr = tokensList.map(a => a.address);
|
|
const tokenResolverInstance = new web3.eth.Contract(
|
|
tokenResolverABI as AbiItem[],
|
|
tokenResolverAddr
|
|
);
|
|
|
|
const tokensAddrArrLength = tokensAddrArr.length;
|
|
let additionalTokensInfo;
|
|
let isNotTokens;
|
|
if (additionalTokens && additionalTokens.length) {
|
|
additionalTokens = additionalTokens.filter(
|
|
token =>
|
|
!tokensArr.find(a => a.address.toLowerCase() === token.toLowerCase())
|
|
);
|
|
}
|
|
if (additionalTokens && additionalTokens.length) {
|
|
additionalTokensInfo = await getTokensDetails(
|
|
additionalTokens,
|
|
network,
|
|
web3
|
|
);
|
|
isNotTokens = Object.fromEntries(
|
|
additionalTokens
|
|
.filter((val, index) => !additionalTokensInfo[index].isToken)
|
|
.map(val => [val, { isToken: false }])
|
|
);
|
|
additionalTokens = additionalTokens.filter(
|
|
(val, index) => additionalTokensInfo[index].isToken
|
|
);
|
|
additionalTokensInfo = additionalTokensInfo.filter(val => val.isToken);
|
|
tokensAddrArr = tokensAddrArr.concat(additionalTokens);
|
|
}
|
|
|
|
const tokenBalances = await tokenResolverInstance.methods
|
|
.getBalances(owner, tokensAddrArr)
|
|
.call();
|
|
|
|
let tokensBalObj = {};
|
|
tokenBalances.forEach((a, i) => {
|
|
const tokenAddress = web3.utils.toChecksumAddress(tokensAddrArr[i]);
|
|
let tokenData;
|
|
if (i < tokensAddrArrLength) {
|
|
tokenData = {
|
|
...tokensList[i],
|
|
decimals: tokensList[i].decimals.toString()
|
|
};
|
|
} else {
|
|
tokenData = additionalTokensInfo[i - tokensAddrArrLength];
|
|
}
|
|
const { name, symbol, decimals, type, isStableCoin, key } = tokenData;
|
|
tokensBalObj[tokenAddress] = {
|
|
name,
|
|
symbol,
|
|
decimals,
|
|
type,
|
|
isStableCoin,
|
|
key,
|
|
balance: new BigNumber(a).dividedBy(10 ** tokenData.decimals).toFixed(),
|
|
raw: String(a)
|
|
};
|
|
});
|
|
tokensBalObj = { ...tokensBalObj, ...isNotTokens };
|
|
|
|
return tokensBalObj;
|
|
} catch (error) {
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
|
|
const storedTokens = {};
|
|
|
|
async function getTokensDetails(addressArr, network: Network, web3: Web3) {
|
|
try {
|
|
const balanceInstance = new web3.eth.Contract(
|
|
abis.resolver.balance as AbiItem[],
|
|
addresses[network].resolver.balance
|
|
);
|
|
|
|
const result = [];
|
|
for (let i = 0; i < addressArr.length; i++) {
|
|
let details = tokens[network].getTokenByAddress(addressArr[i]);
|
|
if (!details) {
|
|
details = uniPoolTokens[network].getTokenByAddress(addressArr[i]);
|
|
}
|
|
if (!details) {
|
|
details = storedTokens[addressArr[i]];
|
|
} else {
|
|
details.isToken = true;
|
|
}
|
|
try {
|
|
if (!details) {
|
|
details = await balanceInstance.methods
|
|
.getTokenDetails([addressArr[i]])
|
|
.call();
|
|
const { name, symbol, decimals, isToken } = details[0];
|
|
details = {
|
|
name,
|
|
symbol,
|
|
decimals,
|
|
isToken,
|
|
type: "token",
|
|
isStableCoin: false,
|
|
key: symbol.toLowerCase()
|
|
};
|
|
storedTokens[addressArr[i]] = details;
|
|
}
|
|
} catch (error) {
|
|
if (
|
|
error.message &&
|
|
error.message === "Returned error: execution reverted"
|
|
) {
|
|
details = { isToken: false };
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
details.address = addressArr[i];
|
|
result[i] = details;
|
|
}
|
|
return result;
|
|
} catch (error) {}
|
|
}
|