import { fetchNullableWithSessionCache } from "@saberhq/sail"; import type { Network } from "@saberhq/solana-contrib"; import { useConnectionContext } from "@saberhq/use-solana"; import { mapValues } from "lodash-es"; import type { UseQueryOptions } from "react-query"; import { useQuery } from "react-query"; import type { ParsedRewarderConfig, ParsedRewardersList } from "./parsed"; import { parseRewarderConfig } from "./parsed"; import type { RewarderConfig, RewardersList } from "./types"; /** * Raw GitHub URL of the rewarder list. * * Avoid using this, as it is easy to get rate limited here. */ const ROOT_URL_GITHUB = "https://raw.githubusercontent.com/QuarryProtocol/rewarder-list-build/master"; /** * CDN Root URL of the rewarder list. */ const ROOT_URL_CDN = "https://cdn.jsdelivr.net/gh/QuarryProtocol/rewarder-list-build@master"; /** * Default time in milliseconds for when the data becomes stale. */ const DEFAULT_STALE_TIME = 600 * 1_000; /** * Fetches the JSON in the rewarder list at the path provided. * * @param path * @returns */ const fetchRewarderListURL = async ( path: string, signal?: AbortSignal ): Promise => { const data = await fetchNullableWithSessionCache( `${ROOT_URL_GITHUB}${path}`, signal ); if (data) { return data; } return await fetchNullableWithSessionCache( `${ROOT_URL_CDN}${path}`, signal ); }; export const fetchRawRewarderList = async ( network: Network, signal?: AbortSignal ) => { const data = await fetchRewarderListURL< Record> >(`/${network}/all-rewarders-with-info.json`, signal); if (data === null) { return null; } return mapValues( data, (d, k): RewarderConfig => ({ ...d, rewarder: k, }) ); }; /** * Creates the query to fetch the raw, unparsed rewarder list. * @param network * @param options * @returns */ export const createRawRewarderListQuery = ( network: Network, options: Omit< UseQueryOptions, "queryKey" | "queryFn" > = {} ): UseQueryOptions => { return { queryKey: ["react-quarry", "githubRewardersListRaw", network], queryFn: async ({ signal }) => { return await fetchRawRewarderList(network, signal); }, staleTime: DEFAULT_STALE_TIME, ...options, }; }; /** * Creates the query to fetch the rewarder list. * @param network * @param options * @returns */ export const createRewarderListQuery = ( network: Network, options: Omit< UseQueryOptions, "queryKey" | "queryFn" > = {} ): UseQueryOptions => { return { queryKey: ["react-quarry", "githubRewardersListParsed", network], queryFn: async ({ signal }) => { const data = await fetchRawRewarderList(network, signal); if (data === null) { return null; } return mapValues( data, (d): ParsedRewarderConfig => parseRewarderConfig(d) ); }, staleTime: DEFAULT_STALE_TIME, ...options, }; }; /** * Uses the rewarder registry from GitHub. * @deprecated Use {@link useRewarderList} instead. * @returns */ export const useGithubRewarderRegistry = ( options: Omit< UseQueryOptions, "queryKey" | "queryFn" > = {} ) => { const { network } = useConnectionContext(); return useQuery(createRawRewarderListQuery(network, options)); }; /** * Uses the rewarder registry from GitHub. * @returns */ export const useRewarderList = ( options: Omit< UseQueryOptions, "queryKey" | "queryFn" > = {} ) => { const { network } = useConnectionContext(); return useQuery(createRewarderListQuery(network, options)); }; /** * Creates a query to fetch the rewarder config of an address from GitHub. * @param network * @param address * @param options * @returns */ export const createRewarderConfigQuery = ( network: Network, address: string, options: Omit< UseQueryOptions, "queryKey" | "queryFn" > = {} ): UseQueryOptions => { return { queryKey: ["react-quarry", "rewarderConfig", network, address], queryFn: async ({ signal }) => { const data = await fetchRewarderListURL>( `/${network}/rewarders/${address}/full.json`, signal ); if (data === null) { return null; } return parseRewarderConfig({ ...data, rewarder: address, }); }, staleTime: DEFAULT_STALE_TIME, ...options, }; }; /** * Uses the rewarder registry from GitHub. * * @param address Base-58 encoded address of the rewarder. * @returns */ export const useRewarderConfig = ( address: string, options: Omit< UseQueryOptions, "queryKey" | "queryFn" > = {} ) => { const { network } = useConnectionContext(); return useQuery(createRewarderConfigQuery(network, address, options)); };