UNPKG

@crypto-dex-sdk/parachains-amplitude

Version:

Zenlink Parachains Impl for Amplitude

218 lines (187 loc) 6.21 kB
import type { ParachainId } from '@crypto-dex-sdk/chain' import type { Type } from '@crypto-dex-sdk/currency' import type { QueryableStorageEntry } from '@polkadot/api/types' import { zenlinkAssetIdToAddress } from '@crypto-dex-sdk/format' import { JSBI } from '@crypto-dex-sdk/math' import { useAccount, useApi, useBlockNumber, useCallMulti } from '@crypto-dex-sdk/polkadot' import { useEffect, useMemo, useState } from 'react' import { nodePrimitiveCurrencyToZenlinkProtocolPrimitivesAssetId } from '../libs' import '@pendulum-chain/types/argument/api-rpc' interface UserReward { token: string amount: string } interface FarmReward { pid: number nextClaimableBlock?: string nextClaimableTime?: string userRewards: UserReward[] } interface UseFarmsRewardsParams { account: string | undefined pids: (number | undefined)[] chainId?: ParachainId enabled?: boolean } type UseFarmsRewards = (params: UseFarmsRewardsParams) => { data: Record<number, FarmReward> isLoading: boolean isError: boolean } type FarmRewardsMap = Record<number, FarmReward> export const useFarmsRewards: UseFarmsRewards = ({ chainId, account, enabled = true, pids = [], }) => { const api = useApi(chainId) const { isAccount } = useAccount() const [userRewards, setUserRewards] = useState<any[]>([]) const blockNumber = useBlockNumber() const poolInfoCalls: [QueryableStorageEntry<'promise'>, number | undefined][] = useMemo( () => api ? pids.map(pid => [api.query.farming.poolInfos, pid]) : [], [api, pids], ) const poolInfos = useCallMulti<any[]>({ chainId, calls: poolInfoCalls, options: { enabled: enabled && Boolean(api) }, }) const poolInfoMap = useMemo( () => poolInfos.reduce((map, info, i) => { const pid = pids[i] const poolInfo = info?.isSome ? info?.value?.toJSON() : undefined if (!pid || !poolInfo) return map map[pid] = info return map }, {}), [pids, poolInfos], ) const userShareInfo = useCallMulti<any[]>({ chainId, calls: (api && isAccount(account)) ? pids .map(pid => [api.query.farming.sharesAndWithdrawnRewards, [pid, account]]) .filter((call): call is [QueryableStorageEntry<'promise'>, [number, string]] => Boolean(call[0])) : [], options: { enabled: enabled && Boolean(api && isAccount(account)) }, }) const userShareInfoMap = useMemo(() => { const result: { [pid: number]: any } = {} if (userShareInfo.length !== pids.length) return result for (let i = 0; i < pids.length; i++) { const pid = pids[i] const value = userShareInfo[i]?.value?.toJSON() if (value && pid) result[pid] = value } return result }, [userShareInfo, pids]) useEffect(() => { if (!api || !account || !isAccount(account)) return if (!api.rpc.farming.getFarmingRewards || !api.rpc.farming.getGaugeRewards) return try { Promise.all( pids.map((pid) => { return Promise.all([ api.rpc.farming.getFarmingRewards(account, Number(pid)), api.rpc.farming.getGaugeRewards(account, Number(pid)), ]) }), ).then((result) => { const userReward = result.map((reward, index) => { const pid = pids[index] const [farmingRewards, gaugeRewards] = reward const userRewards = Object.entries([...farmingRewards, ...gaugeRewards] .map((item) => { const token = nodePrimitiveCurrencyToZenlinkProtocolPrimitivesAssetId( item[0].toHuman() as any, chainId as number, ) return { token: zenlinkAssetIdToAddress(token), amount: item[1].toString(), } }) .reduce<Record<string, { token: string, amount: string }>>((map, cur) => { if (!map[cur.token]) { map[cur.token] = { token: cur.token, amount: cur.amount, } } else { map[cur.token].amount = JSBI.add( JSBI.BigInt(cur.amount), JSBI.BigInt(map[cur.token].amount), ).toString() } return map }, {})).map(item => item[1]) return { pid, userRewards } }) setUserRewards(userReward) }) } catch {} }, [account, api, chainId, isAccount, pids, blockNumber]) const userFarmInfosMap: FarmRewardsMap = useMemo(() => { const result: FarmRewardsMap = {} if (userRewards.length !== pids.length) return result for (let i = 0; i < pids.length; i++) { const value = userRewards[i] const poolInfo = poolInfoMap[pids[i]!]?.poolInfo const claimLimitTime = poolInfo?.claimLimitTime ?? 0 const userShareInfo = userShareInfoMap[pids[i]!] const claimLastBlock = userShareInfo?.claimLastBlock ?? 0 if (value) value.nextClaimableBlock = claimLastBlock + claimLimitTime result[pids[i]!] = value } return result }, [pids, poolInfoMap, userRewards, userShareInfoMap]) return useMemo(() => ({ data: userFarmInfosMap, isLoading: isAccount(account) && !userRewards.length && !!pids.length, isError: !isAccount(account), }), [userFarmInfosMap, isAccount, account, userRewards.length, pids.length]) } interface UseFarmRewardsParams { account: string | undefined currency: Type | undefined chainId?: ParachainId pid: number enabled?: boolean } type UseFarmRewards = (params: UseFarmRewardsParams) => Pick<ReturnType<typeof useFarmsRewards>, 'isError' | 'isLoading'> & { data?: FarmReward } export const useFarmRewards: UseFarmRewards = ({ chainId, account, enabled, pid, }) => { const pids = useMemo(() => [pid], [pid]) const { data, isLoading, isError } = useFarmsRewards({ chainId, pids, account, enabled }) return useMemo(() => { const balance = pid ? data?.[pid] : undefined return { isError, isLoading, data: balance, } }, [data, isError, isLoading, pid]) }