import { useMemo, useState } from "react"; import { assocPath, sum } from "ramda"; import { useRecoilState } from "recoil"; import { bigNumAsInt, weiBigNumAsFloat } from "../../../utils/parse/parse"; import { Pool, poolsState } from "../../../state/pools"; import { config } from "../../../config"; import { BigNumber, ethers } from "ethers"; import { useWeb3Provider } from "../../useWeb3Provider/useWeb3Provider"; import { ReliquaryABI__factory, ParentRewarderABI__factory, } from "digit-shared/src/types/generatedContractTypes"; const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" export const usePools = () => { const [poolLoading, setPoolLoading] = useState(false); const [allLoading, setAllLoading] = useState(false); const [pools, setPools] = useRecoilState(poolsState); const { signer } = useWeb3Provider(); const fetchIncentiveEmissionsForPool = async (poolId: number) => { const reliquary = ReliquaryABI__factory.connect( config!.reliquaryContractAddress, signer! ); const rewarderAddress = await reliquary.rewarder(poolId); if (rewarderAddress == ZERO_ADDRESS) return [ { rewardTokenAddress: await reliquary.rewardToken(), rewardMultiplier: 1, } ] const rewarder = ParentRewarderABI__factory.connect( rewarderAddress, signer! ); const [firstRewardTokenAddress, firstRewardTokenMultiplier] = await Promise.all([ //TODO: handle child rewarders rewarder.rewardToken(), rewarder.rewardMultiplier(), ]); return [ { rewardTokenAddress: firstRewardTokenAddress, rewardMultiplier: weiBigNumAsFloat(firstRewardTokenMultiplier), }, ]; }; const fetchPool = async (poolId: number) => { if (!config?.poolConfig[poolId]) { throw new Error( `PoolId ${poolId} has not been configured. See 'configureReliquary' for more info` ); } setPoolLoading(true); try { const reliquary = ReliquaryABI__factory.connect( config!.reliquaryContractAddress, signer! ); const [poolInfo, level, lpAddress, incentiveTokens] = await Promise.all([ reliquary.getPoolInfo(poolId), reliquary.getLevelInfo(poolId), reliquary.poolToken(poolId), fetchIncentiveEmissionsForPool(poolId), ]); //in LP const totalInvestedBig = level.balance.reduce( (acc: BigNumber, bal: BigNumber) => acc.add(bal), ethers.BigNumber.from(0) ); //create new instance from config?.poolConfig[poolId].type const lpInterface = new config!.poolConfig[poolId].type( lpAddress, signer!, config!.poolConfig[poolId] ); const [ totalInvestedUnderlyingBig, lpPriceUsd, poolTvl, poolTvlCap, poolYields, ] = await Promise.all([ lpInterface.convertToAssets(totalInvestedBig), lpInterface.getSharePriceUSD(), lpInterface.getTvl(), lpInterface.getTvlCap(), lpInterface.getYields(), ]); const totalInvestedUnderlying = totalInvestedUnderlyingBig.map( (bal: BigNumber, index: number) => weiBigNumAsFloat( bal, config!.poolConfig[poolId].underlyingFarmAsset[index].decimals ) ); const totalInvested = sum( level.balance.map((bal: BigNumber) => weiBigNumAsFloat(bal, config!.poolConfig[poolId].lpDecimalPlaces) ) ); // let chainId = await signer?.getChainId(); // const farmData = fetchUnderlyingFarmDataForPool(lpAddress, chainId!); // const assetName = config.poolConfig[poolId].underlyingFarmAsset[0].name; const pool: Pool = { ...config.poolConfig[poolId], assetPriceUsd: 0, accOathPerShare: weiBigNumAsFloat(poolInfo.accRewardPerShare, 12), allocationPoints: bigNumAsInt(poolInfo.allocPoint), incentiveTokens, lastRewardTime: bigNumAsInt(poolInfo.lastRewardTime), lpAddress, lpPriceUsd, maturityAllocations: level.multipliers.map(bigNumAsInt), maturityAllocationTotal: sum(level.multipliers.map(bigNumAsInt)), maturityBalances: level.balance.map((bal: BigNumber) => weiBigNumAsFloat(bal, config!.poolConfig[poolId].lpDecimalPlaces) ), maturityBands: level.requiredMaturities.map(bigNumAsInt), poolId, totalInvested: poolTvl || 0, totalInvestedReliquary: totalInvested || 0, totalInvestedReliquaryUnderlying: totalInvestedUnderlying, underlyingYield: poolYields, tvlCap: poolTvlCap, } as Pool; setPools(assocPath([poolId], pool)); setPoolLoading(false); return pool; } catch (e) { console.error(e); } }; const fetchAllPools = async () => { setAllLoading(true); try { await Promise.all( Object.keys(config!.poolConfig).map((id) => fetchPool(parseInt(id))) ); } catch (e) { console.error("fetchAllPools", e); } setAllLoading(false); }; const poolsArray = useMemo(() => Object.values(pools), [pools]); return { allLoading, fetchAllPools, fetchPool, poolLoading, pools, poolsArray, }; };