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
This commit is contained in:
Bob van der Helm 2024-01-31 09:17:13 +01:00 committed by GitHub
parent c4a2a7d913
commit e763203d15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 113 additions and 205 deletions

View File

@ -1,26 +1,20 @@
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate' 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 { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client'
import { MarsIncentivesQueryClient } from 'types/generated/mars-incentives/MarsIncentives.client' import { MarsIncentivesQueryClient } from 'types/generated/mars-incentives/MarsIncentives.client'
import { MarsMockVaultQueryClient } from 'types/generated/mars-mock-vault/MarsMockVault.client' import { MarsMockVaultQueryClient } from 'types/generated/mars-mock-vault/MarsMockVault.client'
import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client' import { MarsOracleOsmosisQueryClient } from 'types/generated/mars-oracle-osmosis/MarsOracleOsmosis.client'
import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.client' import { MarsParamsQueryClient } from 'types/generated/mars-params/MarsParams.client'
import { MarsPerpsQueryClient } from 'types/generated/mars-perps/MarsPerps.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' import { MarsSwapperOsmosisQueryClient } from 'types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client'
let _cosmWasmClient: Map<string, CosmWasmClient> = new Map() let _cosmWasmClient: Map<string, CosmWasmClient> = new Map()
let _accountNftQueryClient: Map<string, MarsAccountNftQueryClient> = new Map()
let _creditManagerQueryClient: Map<string, MarsCreditManagerQueryClient> = new Map() let _creditManagerQueryClient: Map<string, MarsCreditManagerQueryClient> = new Map()
let _oracleQueryClient: Map<string, MarsOracleOsmosisQueryClient> = new Map() let _oracleQueryClient: Map<string, MarsOracleOsmosisQueryClient> = new Map()
let _redBankQueryClient: Map<string, MarsRedBankQueryClient> = new Map()
let _paramsQueryClient: Map<string, MarsParamsQueryClient> = new Map() let _paramsQueryClient: Map<string, MarsParamsQueryClient> = new Map()
let _incentivesQueryClient: Map<string, MarsIncentivesQueryClient> = new Map() let _incentivesQueryClient: Map<string, MarsIncentivesQueryClient> = new Map()
let _swapperOsmosisClient: Map<string, MarsSwapperOsmosisQueryClient> = new Map() let _swapperOsmosisClient: Map<string, MarsSwapperOsmosisQueryClient> = new Map()
let _perpsClient: Map<string, MarsPerpsQueryClient> = new Map() let _perpsClient: Map<string, MarsPerpsQueryClient> = new Map()
let _ICNSQueryClient: Map<string, ICNSQueryClient> = new Map()
const getClient = async (rpc: string) => { const getClient = async (rpc: string) => {
try { 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) => { const getCreditManagerQueryClient = async (chainConfig: ChainConfig) => {
try { try {
const contract = chainConfig.contracts.creditManager 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) => { const getVaultQueryClient = async (chainConfig: ChainConfig, address: string) => {
try { try {
const client = await getClient(chainConfig.endpoints.rpc) 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 { export {
getAccountNftQueryClient,
getClient, getClient,
getCreditManagerQueryClient, getCreditManagerQueryClient,
getICNSQueryClient,
getIncentivesQueryClient, getIncentivesQueryClient,
getOracleQueryClient, getOracleQueryClient,
getParamsQueryClient, getParamsQueryClient,
getRedBankQueryClient,
getSwapperQueryClient, getSwapperQueryClient,
getVaultQueryClient, getVaultQueryClient,
getPerpsQueryClient, getPerpsQueryClient,

View File

@ -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<BigNumber | null> {
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
}
}

View File

@ -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<BNCoin[]> {
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 []
}
}

View File

@ -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))
}

View File

@ -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<ICNSResult | undefined> {
if (!address || chainConfig.id !== ChainInfoID.Osmosis1) return
try {
const icnsQueryClient = await getICNSQueryClient(chainConfig)
return icnsQueryClient.primaryName({ address })
} catch (ex) {
throw ex
}
}

View File

@ -1,15 +0,0 @@
export default async function getWalletBalances(
chainConfig: ChainConfig,
address: string,
): Promise<Coin[]> {
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'))
}

View File

@ -63,8 +63,8 @@ export default function DisplayCurrency(props: Props) {
? amount > 0 ? amount > 0
? '+' ? '+'
: amount < 0 : amount < 0
? '-' ? '-'
: '' : ''
: '' : ''
const approximationPrefix = isApproximation ? '~ ' : '' const approximationPrefix = isApproximation ? '~ ' : ''
const smallerThanPrefix = isLessThanACent && !showZero ? '< ' : '' const smallerThanPrefix = isLessThanACent && !showZero ? '< ' : ''

View File

@ -1,16 +1,20 @@
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import useSWR from 'swr' import useSWR from 'swr'
import getOpeningFee from 'api/perps/getOpeningFee'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients'
import useDebounce from 'hooks/useDebounce' import useDebounce from 'hooks/useDebounce'
import { BNCoin } from 'types/classes/BNCoin'
export default function useOpeningFee(denom: string, amount: BigNumber) { export default function useOpeningFee(denom: string, amount: BigNumber) {
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
const debouncedAmount = useDebounce<string>(amount.toString(), 500) const debouncedAmount = useDebounce<string>(amount.toString(), 500)
const enabled = !amount.isZero() const clients = useClients()
const enabled = !amount.isZero() && clients
return useSWR(enabled && `${chainConfig.id}/perps/${denom}/openingFee/${debouncedAmount}`, () => 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)),
) )
} }

View File

@ -1,20 +1,26 @@
import useSWR from 'swr' 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 useMarket from 'hooks/markets/useMarket'
import useChainConfig from 'hooks/useChainConfig' 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 { SECONDS_IN_A_YEAR } from 'utils/constants'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
export default function useAssetIncentivesApy(denom: string) { export default function useAssetIncentivesApy(denom: string) {
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
const market = useMarket(denom) 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( return useSWR(
market && `chains/${chainConfig.id}/assets/${denom}/incentives`, enabled && `chains/${chainConfig.id}/assets/${denom}/incentives`,
() => calculateAssetIncentivesApy(chainConfig, market!, price), () => calculateAssetIncentivesApy(clients!, assets, prices, market!),
{ {
revalidateOnFocus: false, revalidateOnFocus: false,
}, },
@ -22,16 +28,20 @@ export default function useAssetIncentivesApy(denom: string) {
} }
async function calculateAssetIncentivesApy( async function calculateAssetIncentivesApy(
chainConfig: ChainConfig, clients: ContractClients,
assets: Asset[],
prices: BNCoin[],
market: Market, market: Market,
price: BigNumber,
) { ) {
const totalActiveEmissionValue = await getTotalActiveEmissionValue( const totalActiveEmissionValue = await getTotalActiveEmissionValue(
chainConfig, clients,
market.asset.denom, assets,
prices,
market,
) )
if (!totalActiveEmissionValue) return null if (!totalActiveEmissionValue) return null
const price = prices.find(byDenom(market.asset.denom))?.amount ?? BN_ZERO
const marketLiquidityValue = BN(market.deposits) const marketLiquidityValue = BN(market.deposits)
.shiftedBy(-market.asset.decimals) .shiftedBy(-market.asset.decimals)
@ -43,3 +53,30 @@ async function calculateAssetIncentivesApy(
const totalAnnualReturnsValue = annualEmission.plus(marketReturns) const totalAnnualReturnsValue = annualEmission.plus(marketReturns)
return totalAnnualReturnsValue.dividedBy(marketLiquidityValue).multipliedBy(100) return totalAnnualReturnsValue.dividedBy(marketLiquidityValue).multipliedBy(100)
} }
async function getTotalActiveEmissionValue(
clients: ContractClients,
assets: Asset[],
prices: BNCoin[],
market: Market,
): Promise<BigNumber | null> {
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
}
}

View File

@ -2,6 +2,7 @@ import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import useSWR from 'swr' import useSWR from 'swr'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
import { ICNSQueryClient } from 'types/classes/ICNSClient.client'
import { MarsAccountNftQueryClient } from 'types/generated/mars-account-nft/MarsAccountNft.client' import { MarsAccountNftQueryClient } from 'types/generated/mars-account-nft/MarsAccountNft.client'
import { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client' import { MarsCreditManagerQueryClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client'
import { MarsIncentivesQueryClient } from 'types/generated/mars-incentives/MarsIncentives.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), swapper: new MarsSwapperOsmosisQueryClient(client, chainConfig.contracts.swapper),
incentives: new MarsIncentivesQueryClient(client, chainConfig.contracts.incentives), incentives: new MarsIncentivesQueryClient(client, chainConfig.contracts.incentives),
perps: new MarsPerpsQueryClient(client, chainConfig.contracts.perps), perps: new MarsPerpsQueryClient(client, chainConfig.contracts.perps),
icns: new ICNSQueryClient(client),
} as ContractClients } as ContractClients
}, },
{ {

View File

@ -1,12 +1,19 @@
import useSWR from 'swr' import useSWR from 'swr'
import getICNS from 'api/wallets/getICNS'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients'
import { ChainInfoID } from 'types/enums/wallet'
export default function useICNSDomain(address?: string) { export default function useICNSDomain(address?: string) {
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
const clients = useClients()
const enabled = !!clients && chainConfig.id === ChainInfoID.Osmosis1 && address
return useSWR(`ICNS-${address}`, () => getICNS(chainConfig, address), { return useSWR(
revalidateOnFocus: false, enabled && `chains/${chainConfig.id}/${address}/icns`,
}) () => clients!.icns.primaryName({ address: address! }),
{
revalidateOnFocus: false,
},
)
} }

View File

@ -1,17 +1,21 @@
import useSWR from 'swr' import useSWR from 'swr'
import getUnclaimedRewards from 'api/incentives/getUnclaimedRewards'
import useAccountId from 'hooks/useAccountId' import useAccountId from 'hooks/useAccountId'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
import useClients from 'hooks/useClients'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import iterateContractQuery from 'utils/iterateContractQuery'
export default function useUserUnclaimedRewards() { export default function useUserUnclaimedRewards() {
const accountId = useAccountId() const accountId = useAccountId()
const chainConfig = useChainConfig() const chainConfig = useChainConfig()
const clients = useClients()
const enabled = !!accountId && !!clients
return useSWR( return useSWR(
`chains/${chainConfig.id}/accounts/${accountId}/unclaimed-rewards`, enabled && `chains/${chainConfig.id}/accounts/${accountId}/unclaimed-rewards`,
() => getUnclaimedRewards(chainConfig, accountId ?? ''), () => getUnclaimedRewards(clients!, accountId!),
{ {
fallbackData: [] as BNCoin[], fallbackData: [] as BNCoin[],
isPaused: () => !accountId, isPaused: () => !accountId,
@ -19,3 +23,22 @@ export default function useUserUnclaimedRewards() {
}, },
) )
} }
async function getUnclaimedRewards(clients: ContractClients, accountId: string): Promise<BNCoin[]> {
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 []
}
}

View File

@ -1,6 +1,5 @@
import useSWR from 'swr' import useSWR from 'swr'
import getWalletBalances from 'api/wallets/getWalletBalances'
import useChainConfig from 'hooks/useChainConfig' import useChainConfig from 'hooks/useChainConfig'
export default function useWalletBalances(address?: string) { export default function useWalletBalances(address?: string) {
@ -8,10 +7,23 @@ export default function useWalletBalances(address?: string) {
return useSWR( return useSWR(
address && `chains/${chainConfig.id}/wallets/${address}/balances`, address && `chains/${chainConfig.id}/wallets/${address}/balances`,
() => getWalletBalances(chainConfig, address || ''), () => getWalletBalances(chainConfig, address!),
{ {
isPaused: () => !address, isPaused: () => !address,
fallbackData: [], fallbackData: [],
}, },
) )
} }
async function getWalletBalances(chainConfig: ChainConfig, address: string): Promise<Coin[]> {
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'))
}

View File

@ -56,4 +56,5 @@ interface ContractClients {
perps: import('types/generated/mars-perps/MarsPerps.client').MarsPerpsQueryClient perps: import('types/generated/mars-perps/MarsPerps.client').MarsPerpsQueryClient
redBank: import('types/generated/mars-red-bank/MarsRedBank.client').MarsRedBankQueryClient redBank: import('types/generated/mars-red-bank/MarsRedBank.client').MarsRedBankQueryClient
swapper: import('types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client').MarsSwapperOsmosisQueryClient swapper: import('types/generated/mars-swapper-osmosis/MarsSwapperOsmosis.client').MarsSwapperOsmosisQueryClient
icns: import('types/classes/ICNSClient.client').ICNSQueryClient
} }

View File

@ -58,10 +58,10 @@ export const formatValue = (amount: number | string, options?: FormatOptions): s
? convertedAmount.isGreaterThanOrEqualTo(1_000_000_000) ? convertedAmount.isGreaterThanOrEqualTo(1_000_000_000)
? 'B' ? 'B'
: convertedAmount.isGreaterThanOrEqualTo(1_000_000) : convertedAmount.isGreaterThanOrEqualTo(1_000_000)
? 'M' ? 'M'
: convertedAmount.isGreaterThanOrEqualTo(1_000) : convertedAmount.isGreaterThanOrEqualTo(1_000)
? 'K' ? 'K'
: false : false
: '' : ''
if (amountSuffix === 'B') { if (amountSuffix === 'B') {