import type { ProgramAccount } from "@project-serum/anchor"; import type { MinerData, QuarryData } from "@quarryprotocol/quarry-sdk"; import { Payroll } from "@quarryprotocol/quarry-sdk"; import type { BatchedParsedAccountQueryData } from "@saberhq/sail"; import { mapSome } from "@saberhq/solana-contrib"; import type { Token } from "@saberhq/token-utils"; import { TokenAmount } from "@saberhq/token-utils"; import { zip } from "lodash-es"; import { useMemo } from "react"; import { FastPayroll } from "./fastPayroll"; import type { GetAllClaimableAmounts } from "./types"; /** * Creates the getAllClaimableAmounts function. * @param quarryData * @returns */ export const makeGetAllClaimableAmounts = ({ payrolls, token, }: { payrolls: | { payroll: Payroll | null | undefined; minerData?: MinerData | null; }[] | null | undefined; token: Token | null; }): GetAllClaimableAmounts => { const fastPayrolls = mapSome(payrolls, (ps) => ps.map(({ payroll, minerData }) => ({ payroll: mapSome(payroll, (p) => FastPayroll.fromPayroll(p)), minerData, })) ); return (additionalMilliseconds = 0) => { if (!fastPayrolls) { return fastPayrolls; } if (!token) { return null; } const now = Math.floor( (new Date().getTime() + additionalMilliseconds) / 1_000 ); const allClaimable = fastPayrolls.map(({ payroll, minerData }) => { if (!payroll || !minerData) { return null; } const rewards = payroll.calculateRewardsEarned( now, minerData.balance, minerData.rewardsPerTokenPaid, minerData.rewardsEarned ); try { return new TokenAmount(token, rewards); } catch (e) { console.error(`Could not parse claimable amount`, e); return null; } }); const allAmounts = allClaimable.filter((t): t is TokenAmount => !!t); const sum = allAmounts.length > 0 ? allAmounts.reduce((acc, el) => acc.add(el)) : null; return { sum, allClaimable, }; }; }; /** * Creates a Payroll from a Quarry. * @param quarryData * @returns */ export const createQuarryPayroll = (quarryData: QuarryData) => new Payroll( quarryData.famineTs, quarryData.lastUpdateTs, quarryData.annualRewardsRate, quarryData.rewardsPerTokenStored, quarryData.totalTokensDeposited ); export const useGetAllClaimableAmounts = ({ token, quarriesData, minersData, }: { token: Token | null; quarriesData?: readonly ProgramAccount[]; minersData: BatchedParsedAccountQueryData; }): { payrolls: readonly (Payroll | null | undefined)[] | null | undefined; getAllClaimableAmounts: GetAllClaimableAmounts; } => { const payrolls = useMemo(() => { if (!quarriesData) { return quarriesData; } return zip(quarriesData, minersData).map(([quarry, miner]) => { const payroll = quarry ? createQuarryPayroll(quarry.account) : quarry; return { payroll, minerData: miner ? miner.account : miner }; }); }, [minersData, quarriesData]); const getAllClaimableAmounts: GetAllClaimableAmounts = useMemo( () => makeGetAllClaimableAmounts({ payrolls, token }), [payrolls, token] ); return { payrolls: payrolls ? payrolls.map((p) => p.payroll) : payrolls, getAllClaimableAmounts, }; };