From e763203d15d3faeac940184cb555699e38a3ec36 Mon Sep 17 00:00:00 2001 From: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:17:13 +0100 Subject: [PATCH] Mp 2182 convert api folder to swr hooks (#758) * moved api/openingFee to hook * moved api/icns and api/balances to hooks * moved api/assetIncentivesApy to hooks * moved api/incentives to hooks * fix relative import --- src/api/cosmwasm-client.ts | 59 ------------------- .../incentives/getTotalActiveEmissionValue.ts | 42 ------------- src/api/incentives/getUnclaimedRewards.ts | 33 ----------- src/api/perps/getOpeningFee.ts | 14 ----- src/api/wallets/getICNS.ts | 15 ----- src/api/wallets/getWalletBalances.ts | 15 ----- src/components/common/DisplayCurrency.tsx | 4 +- src/hooks/perps/useOpeningFee.ts | 10 +++- src/hooks/useAssetIncentiveApy.ts | 55 ++++++++++++++--- src/hooks/useClients.ts | 2 + src/hooks/useICNSDomain.tsx | 15 +++-- src/hooks/useUnclaimedRewards.tsx | 29 ++++++++- src/hooks/useWalletBalances.tsx | 16 ++++- src/types/interfaces/chain.d.ts | 1 + src/utils/formatters.ts | 8 +-- 15 files changed, 113 insertions(+), 205 deletions(-) delete mode 100644 src/api/incentives/getTotalActiveEmissionValue.ts delete mode 100644 src/api/incentives/getUnclaimedRewards.ts delete mode 100644 src/api/perps/getOpeningFee.ts delete mode 100644 src/api/wallets/getICNS.ts delete mode 100644 src/api/wallets/getWalletBalances.ts diff --git a/src/api/cosmwasm-client.ts b/src/api/cosmwasm-client.ts index bca16491..357b6167 100644 --- a/src/api/cosmwasm-client.ts +++ b/src/api/cosmwasm-client.ts @@ -1,26 +1,20 @@ import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate' -import { ICNSQueryClient } from 'types/classes/ICNSClient.client' -import { MarsAccountNftQueryClient } from 'types/generated/mars-account-nft/MarsAccountNft.client' import { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client' import { MarsIncentivesQueryClient } from 'types/generated/mars-incentives/MarsIncentives.client' import { MarsMockVaultQueryClient } from 'types/generated/mars-mock-vault/MarsMockVault.client' import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client' import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.client' import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.client' -import { MarsRedBankQueryClient } from 'types/generated/mars-red-bank/MarsRedBank.client' import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client' let _cosmWasmClient: Map = new Map() -let _accountNftQueryClient: Map = new Map() let _creditManagerQueryClient: Map = new Map() let _oracleQueryClient: Map = new Map() -let _redBankQueryClient: Map = new Map() let _paramsQueryClient: Map = new Map() let _incentivesQueryClient: Map = new Map() let _swapperOsmosisClient: Map = new Map() let _perpsClient: Map = new Map() -let _ICNSQueryClient: Map = new Map() const getClient = async (rpc: string) => { try { @@ -35,23 +29,6 @@ const getClient = async (rpc: string) => { } } -const getAccountNftQueryClient = async (chainConfig: ChainConfig) => { - try { - const contract = chainConfig.contracts.accountNft - const rpc = chainConfig.endpoints.rpc - const key = rpc + contract - - if (!_accountNftQueryClient.get(key)) { - const client = await getClient(rpc) - _accountNftQueryClient.set(key, new MarsAccountNftQueryClient(client, contract)) - } - - return _accountNftQueryClient.get(key)! - } catch (error) { - throw error - } -} - const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => { try { const contract = chainConfig.contracts.creditManager @@ -103,23 +80,6 @@ const getOracleQueryClient = async (chainConfig: ChainConfig) => { } } -const getRedBankQueryClient = async (chainConfig: ChainConfig) => { - try { - const contract = chainConfig.contracts.redBank - const rpc = chainConfig.endpoints.rpc - const key = rpc + contract - - if (!_redBankQueryClient.get(key)) { - const client = await getClient(rpc) - _redBankQueryClient.set(key, new MarsRedBankQueryClient(client, contract)) - } - - return _redBankQueryClient.get(key)! - } catch (error) { - throw error - } -} - const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) => { try { const client = await getClient(chainConfig.endpoints.rpc) @@ -177,31 +137,12 @@ const getPerpsQueryClient = async (chainConfig: ChainConfig) => { } } -const getICNSQueryClient = async (chainConfig: ChainConfig) => { - try { - const contract = chainConfig.contracts.params - const rpc = chainConfig.endpoints.rpc - const key = rpc + contract - if (!_ICNSQueryClient.get(key)) { - const client = await getClient(rpc) - _ICNSQueryClient.set(key, new ICNSQueryClient(client)) - } - - return _ICNSQueryClient.get(key)! - } catch (error) { - throw error - } -} - export { - getAccountNftQueryClient, getClient, getCreditManagerQueryClient, - getICNSQueryClient, getIncentivesQueryClient, getOracleQueryClient, getParamsQueryClient, - getRedBankQueryClient, getSwapperQueryClient, getVaultQueryClient, getPerpsQueryClient, diff --git a/src/api/incentives/getTotalActiveEmissionValue.ts b/src/api/incentives/getTotalActiveEmissionValue.ts deleted file mode 100644 index f71132a2..00000000 --- a/src/api/incentives/getTotalActiveEmissionValue.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { cacheFn, emissionsCache } from 'api/cache' -import { getIncentivesQueryClient } from 'api/cosmwasm-client' -import getPrice from 'api/prices/getPrice' -import { BN_ZERO } from 'constants/math' -import { byDenom } from 'utils/array' -import { BN } from 'utils/helpers' - -export default async function getTotalActiveEmissionValue( - chainConfig: ChainConfig, - denom: string, -): Promise { - try { - const client = await getIncentivesQueryClient(chainConfig) - const activeEmissions = await cacheFn( - () => - client.activeEmissions({ - collateralDenom: denom, - }), - emissionsCache, - `emission/${denom}`, - 60, - ) - - if (activeEmissions.length === 0) { - throw 'Asset has no active incentive emission.' - } - - const prices = await Promise.all( - activeEmissions.map((activeEmission) => getPrice(chainConfig, activeEmission.denom)), - ) - - return activeEmissions.reduce((accumulation, current, index) => { - const price = prices[index] - const decimals = chainConfig.assets.find(byDenom(current.denom))?.decimals as number - const emissionValue = BN(current.emission_rate).shiftedBy(-decimals).multipliedBy(price) - - return accumulation.plus(emissionValue) - }, BN_ZERO) - } catch (ex) { - return null - } -} diff --git a/src/api/incentives/getUnclaimedRewards.ts b/src/api/incentives/getUnclaimedRewards.ts deleted file mode 100644 index 66304905..00000000 --- a/src/api/incentives/getUnclaimedRewards.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { cacheFn, unclaimedRewardsCache } from 'api/cache' -import { getIncentivesQueryClient } from 'api/cosmwasm-client' -import { BNCoin } from 'types/classes/BNCoin' -import iterateContractQuery from 'utils/iterateContractQuery' - -export default async function getUnclaimedRewards( - chainConfig: ChainConfig, - accountId: string, -): Promise { - try { - const client = await getIncentivesQueryClient(chainConfig) - const unclaimedRewards = await cacheFn( - () => - iterateContractQuery(() => - client.userUnclaimedRewards({ - user: chainConfig.contracts.creditManager, - accountId, - }), - ), - unclaimedRewardsCache, - `incentives/${accountId}`, - 60, - ) - - if (unclaimedRewards.length === 0) return [] - - return await Promise.all( - unclaimedRewards.map((reward) => new BNCoin({ denom: reward.denom, amount: reward.amount })), - ) - } catch (ex) { - return [] - } -} diff --git a/src/api/perps/getOpeningFee.ts b/src/api/perps/getOpeningFee.ts deleted file mode 100644 index f89d41c6..00000000 --- a/src/api/perps/getOpeningFee.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { getPerpsQueryClient } from 'api/cosmwasm-client' -import { BNCoin } from 'types/classes/BNCoin' - -export default async function getOpeningFee( - chainConfig: ChainConfig, - denom: string, - amount: string, -) { - const perpsClient = await getPerpsQueryClient(chainConfig) - - return perpsClient - .openingFee({ denom, size: amount as any }) - .then((resp) => BNCoin.fromCoin(resp.fee)) -} diff --git a/src/api/wallets/getICNS.ts b/src/api/wallets/getICNS.ts deleted file mode 100644 index 3e951714..00000000 --- a/src/api/wallets/getICNS.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { getICNSQueryClient } from 'api/cosmwasm-client' -import { ChainInfoID } from 'types/enums/wallet' - -export default async function getICNS( - chainConfig: ChainConfig, - address?: string, -): Promise { - if (!address || chainConfig.id !== ChainInfoID.Osmosis1) return - try { - const icnsQueryClient = await getICNSQueryClient(chainConfig) - return icnsQueryClient.primaryName({ address }) - } catch (ex) { - throw ex - } -} diff --git a/src/api/wallets/getWalletBalances.ts b/src/api/wallets/getWalletBalances.ts deleted file mode 100644 index c6ea4d3f..00000000 --- a/src/api/wallets/getWalletBalances.ts +++ /dev/null @@ -1,15 +0,0 @@ -export default async function getWalletBalances( - chainConfig: ChainConfig, - address: string, -): Promise { - const uri = '/cosmos/bank/v1beta1/balances/' - - const response = await fetch(`${chainConfig.endpoints.rest}${uri}${address}`) - - if (response.ok) { - const data = await response.json() - return data.balances - } - - return new Promise((_, reject) => reject('No data')) -} diff --git a/src/components/common/DisplayCurrency.tsx b/src/components/common/DisplayCurrency.tsx index d2b43796..e356dafd 100644 --- a/src/components/common/DisplayCurrency.tsx +++ b/src/components/common/DisplayCurrency.tsx @@ -63,8 +63,8 @@ export default function DisplayCurrency(props: Props) { ? amount > 0 ? '+' : amount < 0 - ? '-' - : '' + ? '-' + : '' : '' const approximationPrefix = isApproximation ? '~ ' : '' const smallerThanPrefix = isLessThanACent && !showZero ? '< ' : '' diff --git a/src/hooks/perps/useOpeningFee.ts b/src/hooks/perps/useOpeningFee.ts index 2499d19d..d81cd390 100644 --- a/src/hooks/perps/useOpeningFee.ts +++ b/src/hooks/perps/useOpeningFee.ts @@ -1,16 +1,20 @@ import BigNumber from 'bignumber.js' import useSWR from 'swr' -import getOpeningFee from 'api/perps/getOpeningFee' import useChainConfig from 'hooks/useChainConfig' +import useClients from 'hooks/useClients' import useDebounce from 'hooks/useDebounce' +import { BNCoin } from 'types/classes/BNCoin' export default function useOpeningFee(denom: string, amount: BigNumber) { const chainConfig = useChainConfig() const debouncedAmount = useDebounce(amount.toString(), 500) - const enabled = !amount.isZero() + const clients = useClients() + const enabled = !amount.isZero() && clients return useSWR(enabled && `${chainConfig.id}/perps/${denom}/openingFee/${debouncedAmount}`, () => - getOpeningFee(chainConfig, denom, amount.toString()), + clients!.perps + .openingFee({ denom, size: amount as any }) + .then((resp) => BNCoin.fromCoin(resp.fee)), ) } diff --git a/src/hooks/useAssetIncentiveApy.ts b/src/hooks/useAssetIncentiveApy.ts index 6d5307a8..45851b4d 100644 --- a/src/hooks/useAssetIncentiveApy.ts +++ b/src/hooks/useAssetIncentiveApy.ts @@ -1,20 +1,26 @@ import useSWR from 'swr' -import getTotalActiveEmissionValue from 'api/incentives/getTotalActiveEmissionValue' +import { BN_ZERO } from 'constants/math' +import useAllAssets from 'hooks/assets/useAllAssets' import useMarket from 'hooks/markets/useMarket' import useChainConfig from 'hooks/useChainConfig' -import usePrice from 'hooks/usePrice' +import useClients from 'hooks/useClients' +import usePrices from 'hooks/usePrices' +import { byDenom } from 'utils/array' import { SECONDS_IN_A_YEAR } from 'utils/constants' import { BN } from 'utils/helpers' export default function useAssetIncentivesApy(denom: string) { const chainConfig = useChainConfig() const market = useMarket(denom) - const price = usePrice(denom) + const { data: prices } = usePrices() + const assets = useAllAssets() + const clients = useClients() + const enabled = !!market && !!prices.length && !!assets.length && !!clients return useSWR( - market && `chains/${chainConfig.id}/assets/${denom}/incentives`, - () => calculateAssetIncentivesApy(chainConfig, market!, price), + enabled && `chains/${chainConfig.id}/assets/${denom}/incentives`, + () => calculateAssetIncentivesApy(clients!, assets, prices, market!), { revalidateOnFocus: false, }, @@ -22,16 +28,20 @@ export default function useAssetIncentivesApy(denom: string) { } async function calculateAssetIncentivesApy( - chainConfig: ChainConfig, + clients: ContractClients, + assets: Asset[], + prices: BNCoin[], market: Market, - price: BigNumber, ) { const totalActiveEmissionValue = await getTotalActiveEmissionValue( - chainConfig, - market.asset.denom, + clients, + assets, + prices, + market, ) if (!totalActiveEmissionValue) return null + const price = prices.find(byDenom(market.asset.denom))?.amount ?? BN_ZERO const marketLiquidityValue = BN(market.deposits) .shiftedBy(-market.asset.decimals) @@ -43,3 +53,30 @@ async function calculateAssetIncentivesApy( const totalAnnualReturnsValue = annualEmission.plus(marketReturns) return totalAnnualReturnsValue.dividedBy(marketLiquidityValue).multipliedBy(100) } + +async function getTotalActiveEmissionValue( + clients: ContractClients, + assets: Asset[], + prices: BNCoin[], + market: Market, +): Promise { + try { + const activeEmissions = await clients.incentives.activeEmissions({ + collateralDenom: market.asset.denom, + }) + + if (activeEmissions.length === 0) { + throw 'Asset has no active incentive emission.' + } + + return activeEmissions.reduce((accumulation, current, index) => { + const price = prices.find(byDenom(current.denom))?.amount ?? BN_ZERO + const decimals = assets.find(byDenom(current.denom))?.decimals as number + const emissionValue = BN(current.emission_rate).shiftedBy(-decimals).multipliedBy(price) + + return accumulation.plus(emissionValue) + }, BN_ZERO) + } catch (ex) { + return null + } +} diff --git a/src/hooks/useClients.ts b/src/hooks/useClients.ts index e87ca0c2..24b03dbb 100644 --- a/src/hooks/useClients.ts +++ b/src/hooks/useClients.ts @@ -2,6 +2,7 @@ import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate' import useSWR from 'swr' import useChainConfig from 'hooks/useChainConfig' +import { ICNSQueryClient } from 'types/classes/ICNSClient.client' import { MarsAccountNftQueryClient } from 'types/generated/mars-account-nft/MarsAccountNft.client' import { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client' import { MarsIncentivesQueryClient } from 'types/generated/mars-incentives/MarsIncentives.client' @@ -31,6 +32,7 @@ export default function useClients() { swapper: new MarsSwapperOsmosisQueryClient(client, chainConfig.contracts.swapper), incentives: new MarsIncentivesQueryClient(client, chainConfig.contracts.incentives), perps: new MarsPerpsQueryClient(client, chainConfig.contracts.perps), + icns: new ICNSQueryClient(client), } as ContractClients }, { diff --git a/src/hooks/useICNSDomain.tsx b/src/hooks/useICNSDomain.tsx index 7080edf2..30ce9dd0 100644 --- a/src/hooks/useICNSDomain.tsx +++ b/src/hooks/useICNSDomain.tsx @@ -1,12 +1,19 @@ import useSWR from 'swr' -import getICNS from 'api/wallets/getICNS' import useChainConfig from 'hooks/useChainConfig' +import useClients from 'hooks/useClients' +import { ChainInfoID } from 'types/enums/wallet' export default function useICNSDomain(address?: string) { const chainConfig = useChainConfig() + const clients = useClients() + const enabled = !!clients && chainConfig.id === ChainInfoID.Osmosis1 && address - return useSWR(`ICNS-${address}`, () => getICNS(chainConfig, address), { - revalidateOnFocus: false, - }) + return useSWR( + enabled && `chains/${chainConfig.id}/${address}/icns`, + () => clients!.icns.primaryName({ address: address! }), + { + revalidateOnFocus: false, + }, + ) } diff --git a/src/hooks/useUnclaimedRewards.tsx b/src/hooks/useUnclaimedRewards.tsx index ddf9f1cd..49d5f564 100644 --- a/src/hooks/useUnclaimedRewards.tsx +++ b/src/hooks/useUnclaimedRewards.tsx @@ -1,17 +1,21 @@ import useSWR from 'swr' -import getUnclaimedRewards from 'api/incentives/getUnclaimedRewards' import useAccountId from 'hooks/useAccountId' import useChainConfig from 'hooks/useChainConfig' +import useClients from 'hooks/useClients' import { BNCoin } from 'types/classes/BNCoin' +import iterateContractQuery from 'utils/iterateContractQuery' export default function useUserUnclaimedRewards() { const accountId = useAccountId() const chainConfig = useChainConfig() + const clients = useClients() + + const enabled = !!accountId && !!clients return useSWR( - `chains/${chainConfig.id}/accounts/${accountId}/unclaimed-rewards`, - () => getUnclaimedRewards(chainConfig, accountId ?? ''), + enabled && `chains/${chainConfig.id}/accounts/${accountId}/unclaimed-rewards`, + () => getUnclaimedRewards(clients!, accountId!), { fallbackData: [] as BNCoin[], isPaused: () => !accountId, @@ -19,3 +23,22 @@ export default function useUserUnclaimedRewards() { }, ) } + +async function getUnclaimedRewards(clients: ContractClients, accountId: string): Promise { + try { + const unclaimedRewards = await iterateContractQuery(() => + clients.incentives.userUnclaimedRewards({ + user: clients.creditManager.contractAddress, + accountId, + }), + ) + + if (unclaimedRewards.length === 0) return [] + + return await Promise.all( + unclaimedRewards.map((reward) => new BNCoin({ denom: reward.denom, amount: reward.amount })), + ) + } catch (ex) { + return [] + } +} diff --git a/src/hooks/useWalletBalances.tsx b/src/hooks/useWalletBalances.tsx index fcba55ec..0a57a630 100644 --- a/src/hooks/useWalletBalances.tsx +++ b/src/hooks/useWalletBalances.tsx @@ -1,6 +1,5 @@ import useSWR from 'swr' -import getWalletBalances from 'api/wallets/getWalletBalances' import useChainConfig from 'hooks/useChainConfig' export default function useWalletBalances(address?: string) { @@ -8,10 +7,23 @@ export default function useWalletBalances(address?: string) { return useSWR( address && `chains/${chainConfig.id}/wallets/${address}/balances`, - () => getWalletBalances(chainConfig, address || ''), + () => getWalletBalances(chainConfig, address!), { isPaused: () => !address, fallbackData: [], }, ) } + +async function getWalletBalances(chainConfig: ChainConfig, address: string): Promise { + const uri = '/cosmos/bank/v1beta1/balances/' + + const response = await fetch(`${chainConfig.endpoints.rest}${uri}${address}`) + + if (response.ok) { + const data = await response.json() + return data.balances + } + + return new Promise((_, reject) => reject('No data')) +} diff --git a/src/types/interfaces/chain.d.ts b/src/types/interfaces/chain.d.ts index 2ceaa596..30ca1cab 100644 --- a/src/types/interfaces/chain.d.ts +++ b/src/types/interfaces/chain.d.ts @@ -56,4 +56,5 @@ interface ContractClients { perps: import('types/generated/mars-perps/MarsPerps.client').MarsPerpsQueryClient redBank: import('types/generated/mars-red-bank/MarsRedBank.client').MarsRedBankQueryClient swapper: import('types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client').MarsSwapperOsmosisQueryClient + icns: import('types/classes/ICNSClient.client').ICNSQueryClient } diff --git a/src/utils/formatters.ts b/src/utils/formatters.ts index 6c733a11..ecd0d1fd 100644 --- a/src/utils/formatters.ts +++ b/src/utils/formatters.ts @@ -58,10 +58,10 @@ export const formatValue = (amount: number | string, options?: FormatOptions): s ? convertedAmount.isGreaterThanOrEqualTo(1_000_000_000) ? 'B' : convertedAmount.isGreaterThanOrEqualTo(1_000_000) - ? 'M' - : convertedAmount.isGreaterThanOrEqualTo(1_000) - ? 'K' - : false + ? 'M' + : convertedAmount.isGreaterThanOrEqualTo(1_000) + ? 'K' + : false : '' if (amountSuffix === 'B') {