import { zip } from "lodash-es"; import { useEffect, useMemo, useState } from "react"; import type { RewardRates } from "./calculateRewardRates"; /** * Generates the `getPreciseClaimableAmounts` function, which allows computing a * precise amount of tokens to be claimed. * * @param rates * @returns */ export const makeGetPreciseClaimableAmounts = ( rates: RewardRates | null ): (() => PreciseClaimableAmounts | null) => { if (!rates || !rates.amountsT0.sum) { // eslint-disable-next-line react/display-name return () => null; } const initialTotalAmount = parseFloat(rates.amountsT0.sum.toExact()); const initialPoolAmounts = zip( rates.amountsT0.allClaimable.map((c) => c ? parseFloat(c.toExact()) : null ), rates.pools ); return () => { const secondsElapsed = (Date.now() - rates.timeT0Ms) / 1_000; const pools = initialPoolAmounts.map( ([initialPoolAmount, poolRatePerSecond]) => typeof initialPoolAmount === "number" && typeof poolRatePerSecond === "number" ? initialPoolAmount + poolRatePerSecond * secondsElapsed : null ); const total = initialTotalAmount + rates.total * secondsElapsed; return { pools, total, }; }; }; export interface PreciseClaimableAmounts { pools: (number | null)[]; total: number; } /** * Hook to generate the `getPreciseClaimableAmounts` function, which allows computing a * precise amount of tokens to be claimed. * * @param rates * @returns */ export const useGetPreciseClaimableAmounts = ( rates: RewardRates | null ): (() => PreciseClaimableAmounts | null) => { return useMemo(() => { return makeGetPreciseClaimableAmounts(rates); }, [rates]); }; /** * Uses a real-time feed of the claimable amounts. * * Warning: this causes the component to re-render extremely frequently, so one should * take care to not put this too high up in the component tree. * * @param getter * @returns */ export const useClaimableAmounts = ( getter: () => PreciseClaimableAmounts | null ): PreciseClaimableAmounts | null => { const [amounts, setAmounts] = useState(null); useEffect(() => { let playing = true; const doFrame = () => { setAmounts(getter()); if (playing) { requestAnimationFrame(doFrame); } }; doFrame(); return () => { playing = false; }; }, [getter]); return amounts; };