diff --git a/.env.example b/.env.example index a7d2f8a7..2574e528 100644 --- a/.env.example +++ b/.env.example @@ -19,6 +19,8 @@ NEXT_PUBLIC_CANDLES_ENDPOINT="https://api.thegraph.com/subgraphs/name/{NAME}/{GR CHARTING_LIBRARY_USERNAME="username_with_access_to_charting_library" CHARTING_LIBRARY_ACCESS_TOKEN="access_token_with_access_to_charting_library" CHARTING_LIBRARY_REPOSITORY="github.com/username/charting_library/" +NEXT_PUBLIC_PYTH_ENDPOINT=https://xc-mainnet.pyth.network/api/ +NEXT_PUBLIC_MAINNET_REST=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-lcd-front/ # MAINNET # # NEXT_PUBLIC_NETWORK=mainnet @@ -40,3 +42,5 @@ CHARTING_LIBRARY_REPOSITORY="github.com/username/charting_library/" # CHARTING_LIBRARY_USERNAME="username_with_access_to_charting_library" # CHARTING_LIBRARY_ACCESS_TOKEN="access_token_with_access_to_charting_library" # CHARTING_LIBRARY_REPOSITORY="username/charting_library" +# NEXT_PUBLIC_PYTH_ENDPOINT=https://xc-mainnet.pyth.network/api/ +# NEXT_PUBLIC_MAINNET_REST=https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-lcd-front/ diff --git a/src/api/incentives/calculateAssetIncentivesApy.ts b/src/api/incentives/calculateAssetIncentivesApy.ts index 9b9210ce..f4fdda46 100644 --- a/src/api/incentives/calculateAssetIncentivesApy.ts +++ b/src/api/incentives/calculateAssetIncentivesApy.ts @@ -26,7 +26,7 @@ export default async function calculateAssetIncentivesApy( const marsDecimals = 6, priceFeedDecimals = 6 - const assetPrice = BN(assetPriceResponse.price).shiftedBy(assetDecimals - priceFeedDecimals) + const assetPrice = BN(assetPriceResponse).shiftedBy(assetDecimals - priceFeedDecimals) const marketLiquidityValue = BN(marketLiquidityAmount) .shiftedBy(-assetDecimals) .multipliedBy(assetPrice) diff --git a/src/api/prices/getMarsPrice.ts b/src/api/prices/getMarsPrice.ts index fe6c531e..f9eb3656 100644 --- a/src/api/prices/getMarsPrice.ts +++ b/src/api/prices/getMarsPrice.ts @@ -1,45 +1,14 @@ -import getPrice from 'api/prices/getPrice' -import { BN } from 'utils/helpers' - -const MARS_MAINNET_DENOM = 'ibc/573FCD90FACEE750F55A8864EF7D38265F07E5A9273FA0E8DAFD39951332B580' -const MARS_OSMO_POOL_URL = 'https://lcd-osmosis.blockapsis.com/osmosis/gamm/v1beta1/pools/907' - -interface PoolToken { - denom: string - amount: string -} - -interface PoolAsset { - token: PoolToken - weight: string -} - -const findPoolAssetByTokenDenom = (assets: PoolAsset[], denom: string) => - assets.find((a) => a.token.denom === denom) +import { ASSETS, MARS_MAINNET_DENOM } from 'constants/assets' +import { bySymbol } from 'utils/array' +import getPoolPrice from 'api/prices/getPoolPrice' async function getMarsPrice() { - const marsOsmoRate = await getMarsOsmoRate() - const osmoPrice = await getPrice('uosmo') + const marsAsset = { + ...(ASSETS.find(bySymbol('MARS')) as Asset), + denom: MARS_MAINNET_DENOM, + } - return marsOsmoRate.multipliedBy(osmoPrice.price) -} - -const getMarsOsmoRate = async () => { - const resp = await fetch(MARS_OSMO_POOL_URL).then((res) => res.json()) - const spotPrice = calculateSpotPrice(resp.pool.pool_assets) - - return BN(1).dividedBy(spotPrice) -} - -const calculateSpotPrice = (poolAssets: PoolAsset[]) => { - const assetIn = findPoolAssetByTokenDenom(poolAssets, MARS_MAINNET_DENOM) as PoolAsset - - const assetOut = findPoolAssetByTokenDenom(poolAssets, 'uosmo') as PoolAsset - - const numerator = BN(assetIn.token.amount).dividedBy(assetIn.weight) - const denominator = BN(assetOut.token.amount).dividedBy(assetOut.weight) - - return numerator.dividedBy(denominator) + return await getPoolPrice(marsAsset) } export default getMarsPrice diff --git a/src/api/prices/getOraclePrices.ts b/src/api/prices/getOraclePrices.ts new file mode 100644 index 00000000..81c605d7 --- /dev/null +++ b/src/api/prices/getOraclePrices.ts @@ -0,0 +1,24 @@ +import { getOracleQueryClient } from 'api/cosmwasm-client' +import { BNCoin } from 'types/classes/BNCoin' +import { BN } from 'utils/helpers' + +export default async function getOraclePrices(...assets: Asset[]): Promise { + try { + const baseDecimals = 6 + const oracleQueryClient = await getOracleQueryClient() + + const priceQueries = assets.map((asset) => + oracleQueryClient.price({ + denom: asset.denom, + }), + ) + const priceResults = await Promise.all(priceQueries) + + return priceResults.map(({ denom, price }, index) => { + const decimalDiff = assets[index].decimals - baseDecimals + return BNCoin.fromDenomAndBigNumber(denom, BN(price).shiftedBy(decimalDiff)) + }) + } catch (ex) { + throw ex + } +} diff --git a/src/api/prices/getPoolPrice.ts b/src/api/prices/getPoolPrice.ts new file mode 100644 index 00000000..ee0e3488 --- /dev/null +++ b/src/api/prices/getPoolPrice.ts @@ -0,0 +1,49 @@ +import { ENV } from 'constants/env' +import { byDenom, byTokenDenom, partition } from 'utils/array' +import { BN } from 'utils/helpers' +import getPrice from 'api/prices/getPrice' +import { BNCoin } from 'types/classes/BNCoin' + +interface PoolToken { + denom: string + amount: string +} + +interface PoolAsset { + token: PoolToken + weight: string +} + +export default async function getPoolPrice( + asset: Asset, + lookupPricesForBaseAsset?: BNCoin[], +): Promise { + if (!asset.poolId) throw 'given asset should have a poolId to fetch the price' + + const [assetRate, baseAsset] = await getAssetRate(asset) + const baseAssetPrice = + (lookupPricesForBaseAsset && + lookupPricesForBaseAsset.find(byDenom(baseAsset.token.denom))?.amount) || + (await getPrice(baseAsset.token.denom)) + + if (!baseAssetPrice) throw 'base asset price must be available on Pyth or in Oracle contract' + + return assetRate.multipliedBy(baseAssetPrice) +} + +const getAssetRate = async (asset: Asset) => { + const url = `${ENV.MAINNET_REST_API}osmosis/gamm/v1beta1/pools/${asset.poolId}` + const response = await fetch(url).then((res) => res.json()) + + return calculateSpotPrice(response.pool.pool_assets, asset) +} + +const calculateSpotPrice = (poolAssets: PoolAsset[], asset: Asset): [BigNumber, PoolAsset] => { + const [assetIn, assetOut] = partition(poolAssets, byTokenDenom(asset.denom)).flat() + + const numerator = BN(assetIn.token.amount).dividedBy(assetIn.weight) + const denominator = BN(assetOut.token.amount).dividedBy(assetOut.weight) + const spotPrice = BN(1).dividedBy(numerator.dividedBy(denominator)) + + return [spotPrice, assetOut] +} diff --git a/src/api/prices/getPrice.ts b/src/api/prices/getPrice.ts index a240508f..9da888b2 100644 --- a/src/api/prices/getPrice.ts +++ b/src/api/prices/getPrice.ts @@ -1,11 +1,30 @@ import { getOracleQueryClient } from 'api/cosmwasm-client' -import { PriceResponse } from 'types/generated/mars-mock-oracle/MarsMockOracle.types' +import { ASSETS } from 'constants/assets' +import { byDenom } from 'utils/array' +import getPythPrice from 'api/prices/getPythPrices' +import getPoolPrice from 'api/prices/getPoolPrice' +import { BN } from 'utils/helpers' -export default async function getPrice(denom: string): Promise { +export default async function getPrice(denom: string): Promise { try { - const oracleQueryClient = getOracleQueryClient() + const asset = ASSETS.find(byDenom(denom)) as Asset - return (await oracleQueryClient).price({ denom }) + if (asset.pythPriceFeedId) { + return (await getPythPrice(asset.pythPriceFeedId))[0] + } + + if (asset.hasOraclePrice) { + const oracleQueryClient = await getOracleQueryClient() + const priceResponse = await oracleQueryClient.price({ denom: asset.denom }) + + return BN(priceResponse.price) + } + + if (asset.poolId) { + return await getPoolPrice(asset) + } + + throw `could not fetch the price info for the given denom: ${denom}` } catch (ex) { throw ex } diff --git a/src/api/prices/getPrices.ts b/src/api/prices/getPrices.ts index c8edd931..ab91e172 100644 --- a/src/api/prices/getPrices.ts +++ b/src/api/prices/getPrices.ts @@ -1,33 +1,58 @@ -import { ASSETS } from 'constants/assets' -import { getEnabledMarketAssets } from 'utils/assets' -import { BN } from 'utils/helpers' -import { getOracleQueryClient } from 'api/cosmwasm-client' +import { getAssetsMustHavePriceInfo } from 'utils/assets' +import { partition } from 'utils/array' +import getPoolPrice from 'api/prices/getPoolPrice' +import fetchPythPrices from 'api/prices/getPythPrices' +import { BNCoin } from 'types/classes/BNCoin' +import getOraclePrices from 'api/prices/getOraclePrices' -export default async function getPrices(): Promise { +export default async function getPrices(): Promise { try { - const enabledAssets = getEnabledMarketAssets() - const oracleQueryClient = await getOracleQueryClient() - const baseCurrency = ASSETS[0] + const assetsToFetchPrices = getAssetsMustHavePriceInfo() + const [assetsWithPythPriceFeedId, assetsWithOraclePrices, assetsWithPoolIds] = + separateAssetsByPriceSources(assetsToFetchPrices) - const priceQueries = enabledAssets.map((asset) => - oracleQueryClient.price({ - denom: asset.denom, - }), - ) - const priceResults = await Promise.all(priceQueries) + const pythAndOraclePrices = ( + await Promise.all([ + requestPythPrices(assetsWithPythPriceFeedId), + getOraclePrices(...assetsWithOraclePrices), + ]) + ).flat() + const poolPrices = await requestPoolPrices(assetsWithPoolIds, pythAndOraclePrices) - const assetPrices = priceResults.map(({ denom, price }, index) => { - const asset = enabledAssets[index] - const decimalDiff = asset.decimals - baseCurrency.decimals - - return { - denom, - amount: BN(price).shiftedBy(decimalDiff).toString(), - } - }) - - return assetPrices + return [...pythAndOraclePrices, ...poolPrices] } catch (ex) { + console.error(ex) throw ex } } + +async function requestPythPrices(assets: Asset[]): Promise { + const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[] + + return await fetchPythPrices(...priceFeedIds).then(mapResponseToBnCoin(assets)) +} + +async function requestPoolPrices(assets: Asset[], lookupPrices: BNCoin[]): Promise { + const requests = assets.map((asset) => getPoolPrice(asset, lookupPrices)) + + return await Promise.all(requests).then(mapResponseToBnCoin(assets)) +} + +const mapResponseToBnCoin = (assets: Asset[]) => (prices: BigNumber[]) => + prices.map((price: BigNumber, index: number) => + BNCoin.fromDenomAndBigNumber(assets[index].denom, price), + ) + +function separateAssetsByPriceSources(assets: Asset[]) { + const [assetsWithPythPriceFeedId, assetsWithoutPythPriceFeedId] = partition( + assets, + (asset) => !!asset.pythPriceFeedId, + ) + const [assetsWithOraclePrice, assetsWithoutOraclePrice] = partition( + assetsWithoutPythPriceFeedId, + (asset) => asset.hasOraclePrice, + ) + const assetsWithPoolId = assetsWithoutOraclePrice.filter((asset) => !!asset.poolId) + + return [assetsWithPythPriceFeedId, assetsWithOraclePrice, assetsWithPoolId] +} diff --git a/src/api/prices/getPythPrices.ts b/src/api/prices/getPythPrices.ts new file mode 100644 index 00000000..c9131c92 --- /dev/null +++ b/src/api/prices/getPythPrices.ts @@ -0,0 +1,15 @@ +import { ENV } from 'constants/env' +import { BN } from 'utils/helpers' + +export default async function fetchPythPrices(...priceFeedIds: string[]) { + try { + const pricesUrl = new URL(`${ENV.PYTH_API}/latest_price_feeds`) + priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id)) + + const pythResponse: PythPriceData[] = await fetch(pricesUrl).then((res) => res.json()) + + return pythResponse.map(({ price }) => BN(price.price).shiftedBy(price.expo)) + } catch (ex) { + throw ex + } +} diff --git a/src/api/vaults/getDepositedVaults.ts b/src/api/vaults/getDepositedVaults.ts index 9845f272..1cc35834 100644 --- a/src/api/vaults/getDepositedVaults.ts +++ b/src/api/vaults/getDepositedVaults.ts @@ -129,8 +129,8 @@ async function getVaultValuesAndAmounts( secondary: BN(secondaryLpToken.amount), }, values: { - primary: BN(primaryLpToken.amount).multipliedBy(BN(primaryAsset.price)), - secondary: BN(secondaryLpToken.amount).multipliedBy(BN(secondaryAsset.price)), + primary: BN(primaryLpToken.amount).multipliedBy(primaryAsset), + secondary: BN(secondaryLpToken.amount).multipliedBy(secondaryAsset), }, } } catch (ex) { diff --git a/src/constants/assets.ts b/src/constants/assets.ts index 8016a9d2..39613183 100644 --- a/src/constants/assets.ts +++ b/src/constants/assets.ts @@ -1,5 +1,8 @@ import { IS_TESTNET } from 'constants/env' +export const MARS_MAINNET_DENOM = + 'ibc/573FCD90FACEE750F55A8864EF7D38265F07E5A9273FA0E8DAFD39951332B580' + export const ASSETS: Asset[] = [ { symbol: 'OSMO', @@ -14,6 +17,7 @@ export const ASSETS: Asset[] = [ isMarket: true, isDisplayCurrency: true, isAutoLendEnabled: true, + pythPriceFeedId: '5867f5683c757393a0670ef0f701490950fe93fdb006d181c8265a831ac0c5c6', }, { symbol: 'ATOM', @@ -31,6 +35,7 @@ export const ASSETS: Asset[] = [ isDisplayCurrency: true, isAutoLendEnabled: true, poolId: 1, + pythPriceFeedId: 'b00b60f88b03a6a625a8d1c048c3f66653edf217439983d037e7222c4e612819', }, { symbol: 'stATOM', @@ -40,11 +45,11 @@ export const ASSETS: Asset[] = [ color: '#9f1ab9', logo: '/tokens/statom.svg', decimals: 6, - hasOraclePrice: true, + poolId: 803, + hasOraclePrice: !IS_TESTNET, isEnabled: !IS_TESTNET, isMarket: !IS_TESTNET, isDisplayCurrency: !IS_TESTNET, - poolId: 803, }, { symbol: 'WBTC.axl', @@ -59,6 +64,7 @@ export const ASSETS: Asset[] = [ isMarket: !IS_TESTNET, isDisplayCurrency: !IS_TESTNET, poolId: 712, + pythPriceFeedId: 'e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43', }, { symbol: 'WETH.axl', @@ -73,6 +79,7 @@ export const ASSETS: Asset[] = [ isMarket: !IS_TESTNET, isDisplayCurrency: !IS_TESTNET, poolId: 704, + pythPriceFeedId: 'ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace', }, { symbol: 'MARS', @@ -80,14 +87,15 @@ export const ASSETS: Asset[] = [ id: 'MARS', denom: IS_TESTNET ? 'ibc/DB9D326CF53EA07610C394D714D78F8BB4DC7E312D4213193791A9046BF45E20' - : 'ibc/573FCD90FACEE750F55A8864EF7D38265F07E5A9273FA0E8DAFD39951332B580', + : MARS_MAINNET_DENOM, color: '#dd5b65', logo: '/tokens/mars.svg', decimals: 6, - hasOraclePrice: true, + poolId: 907, + hasOraclePrice: false, isMarket: false, isEnabled: true, - poolId: 907, + forceFetchPrice: true, }, { symbol: 'USDC.axl', @@ -105,6 +113,7 @@ export const ASSETS: Asset[] = [ isDisplayCurrency: true, isStable: true, poolId: 678, + pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a', }, { symbol: 'USDC.n', @@ -121,5 +130,6 @@ export const ASSETS: Asset[] = [ isMarket: IS_TESTNET, isDisplayCurrency: IS_TESTNET, isStable: true, + pythPriceFeedId: 'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a', }, ] diff --git a/src/constants/env.ts b/src/constants/env.ts index 8cbacb46..5ee2098d 100644 --- a/src/constants/env.ts +++ b/src/constants/env.ts @@ -16,6 +16,8 @@ interface EnvironmentVariables { URL_API: string URL_APOLLO_APR: string WALLETS: string[] + PYTH_API: string + MAINNET_REST_API: string } export const ENV: EnvironmentVariables = { @@ -38,6 +40,8 @@ export const ENV: EnvironmentVariables = { : process.env.NEXT_PUBLIC_API || '', URL_APOLLO_APR: process.env.NEXT_PUBLIC_APOLLO_APR || '', WALLETS: process.env.NEXT_PUBLIC_WALLETS?.split(',') || [], + PYTH_API: process.env.NEXT_PUBLIC_PYTH_API || '', + MAINNET_REST_API: process.env.NEXT_PUBLIC_MAINNET_REST || '', } export const VERCEL_BYPASS = process.env.NEXT_PUBLIC_BYPASS diff --git a/src/hooks/useDisplayCurrencyPrice.ts b/src/hooks/useDisplayCurrencyPrice.ts index 63e2537c..ad2e125f 100644 --- a/src/hooks/useDisplayCurrencyPrice.ts +++ b/src/hooks/useDisplayCurrencyPrice.ts @@ -30,16 +30,16 @@ function useDisplayCurrencyPrice() { if (assetPrice && displayCurrencyPrice) { return BN(assetPrice.amount).dividedBy(displayCurrencyPrice.amount) - } else { - throw 'Given denom or display currency price has not found' } + + return BN(0) }, [prices, displayCurrency], ) const convertAmount = useCallback( (asset: Asset, amount: string | number | BigNumber) => - getConversionRate(asset.denom).multipliedBy(BN(amount).shiftedBy(-asset.decimals)), + getConversionRate(asset.denom)?.multipliedBy(BN(amount).shiftedBy(-asset.decimals)) ?? BN(0), [getConversionRate], ) diff --git a/src/types/interfaces/asset.d.ts b/src/types/interfaces/asset.d.ts index 6b431b84..32af095c 100644 --- a/src/types/interfaces/asset.d.ts +++ b/src/types/interfaces/asset.d.ts @@ -16,6 +16,9 @@ interface Asset { isStable?: boolean isFavorite?: boolean isAutoLendEnabled?: boolean + pythPriceFeedId?: string + forceFetchPrice?: boolean + testnetDenom?: string } interface PseudoAsset { diff --git a/src/types/interfaces/pyth.d.ts b/src/types/interfaces/pyth.d.ts new file mode 100644 index 00000000..64f652f4 --- /dev/null +++ b/src/types/interfaces/pyth.d.ts @@ -0,0 +1,12 @@ +interface PythPriceData { + price: PythConfidenceData + ema_price: PythConfidenceData + id: string +} + +interface PythConfidenceData { + conf: string + expo: number + price: string + publish_time: number +} diff --git a/src/utils/accounts.ts b/src/utils/accounts.ts index 4a2e702d..3a82a931 100644 --- a/src/utils/accounts.ts +++ b/src/utils/accounts.ts @@ -1,11 +1,12 @@ import BigNumber from 'bignumber.js' +import { BNCoin } from 'types/classes/BNCoin' import { BN, getApproximateHourlyInterest } from 'utils/helpers' import { getTokenValue } from 'utils/tokens' export const calculateAccountBalance = ( account: Account | AccountChange, - prices: Coin[], + prices: BNCoin[], ): BigNumber => { const totalDepositValue = calculateAccountDeposits(account, prices) const totalDebtValue = calculateAccountDebt(account, prices) @@ -15,7 +16,7 @@ export const calculateAccountBalance = ( export const calculateAccountDeposits = ( account: Account | AccountChange, - prices: Coin[], + prices: BNCoin[], ): BigNumber => { if (!account.deposits) return BN(0) return account.deposits.reduce((acc, deposit) => { @@ -26,7 +27,7 @@ export const calculateAccountDeposits = ( } export const calculateAccountDebt = ( account: Account | AccountChange, - prices: Coin[], + prices: BNCoin[], ): BigNumber => { if (!account.debts) return BN(0) return account.debts.reduce((acc, debt) => { @@ -39,21 +40,21 @@ export const calculateAccountDebt = ( export const calculateAccountPnL = ( account: Account | AccountChange, - prices: Coin[], + prices: BNCoin[], ): BigNumber => { return BN(0) } export const calculateAccountApr = ( account: Account | AccountChange, - prices: Coin[], + prices: BNCoin[], ): BigNumber => { return BN(0) } export const calculateAccountBorrowRate = ( account: Account | AccountChange, - prices: Coin[], + prices: BNCoin[], ): BigNumber => { return BN(0) } @@ -62,7 +63,7 @@ export function getAmount(denom: string, coins: Coin[]): BigNumber { return BN(coins.find((asset) => asset.denom === denom)?.amount ?? 0) } -export function getNetCollateralValue(account: Account, marketAssets: Market[], prices: Coin[]) { +export function getNetCollateralValue(account: Account, marketAssets: Market[], prices: BNCoin[]) { const depositCollateralValue = account.deposits.reduce((acc, coin) => { const asset = marketAssets.find((asset) => asset.denom === coin.denom) diff --git a/src/utils/array.ts b/src/utils/array.ts index 2b45107a..1a49c965 100644 --- a/src/utils/array.ts +++ b/src/utils/array.ts @@ -1 +1,14 @@ export const byDenom = (denom: string) => (entity: any) => entity.denom === denom +export const bySymbol = (symbol: string) => (entity: any) => entity.symbol === symbol +export const byTokenDenom = (denom: string) => (entity: any) => entity.token.denom === denom + +export function partition(arr: Array, predicate: (val: T) => boolean): [Array, Array] { + const partitioned: [Array, Array] = [[], []] + + arr.forEach((val: T) => { + const partitionIndex: 0 | 1 = predicate(val) ? 0 : 1 + partitioned[partitionIndex].push(val) + }) + + return partitioned +} diff --git a/src/utils/assets.ts b/src/utils/assets.ts index 45394771..3db59754 100644 --- a/src/utils/assets.ts +++ b/src/utils/assets.ts @@ -12,6 +12,10 @@ export function getEnabledMarketAssets(): Asset[] { return ASSETS.filter((asset) => asset.isEnabled && asset.isMarket) } +export function getAssetsMustHavePriceInfo(): Asset[] { + return ASSETS.filter((asset) => (asset.isEnabled && asset.isMarket) || asset.forceFetchPrice) +} + export function getBaseAsset() { return ASSETS.find((asset) => asset.denom === 'uosmo')! } diff --git a/src/utils/formatters.ts b/src/utils/formatters.ts index 5f1f30ff..b816a840 100644 --- a/src/utils/formatters.ts +++ b/src/utils/formatters.ts @@ -168,14 +168,14 @@ export function demagnify(amount: number | string | BigNumber, asset: Asset | Ps return value.isZero() ? 0 : value.shiftedBy(-1 * asset.decimals).toNumber() } -export function convertToDisplayAmount(coin: BNCoin, displayCurrency: string, prices: Coin[]) { +export function convertToDisplayAmount(coin: BNCoin, displayCurrency: string, prices: BNCoin[]) { const price = prices.find((price) => price.denom === coin.denom) const asset = getEnabledMarketAssets().find((asset) => asset.denom === coin.denom) const displayPrice = prices.find((price) => price.denom === displayCurrency) if (!price || !asset || !displayPrice) return BN(0) - return BN(coin.amount) + return coin.amount .shiftedBy(-1 * asset.decimals) .multipliedBy(price.amount) .dividedBy(displayPrice.amount) diff --git a/src/utils/tokens.ts b/src/utils/tokens.ts index 6dce7e0e..05d66fc8 100644 --- a/src/utils/tokens.ts +++ b/src/utils/tokens.ts @@ -16,12 +16,12 @@ export const getTokenIcon = (denom: string, marketAssets: Asset[]) => export const getTokenInfo = (denom: string, marketAssets: Asset[]) => marketAssets.find((asset) => asset.denom.toLowerCase() === denom.toLowerCase()) || getBaseAsset() -export function getTokenValue(coin: BNCoin, prices: Coin[]): BigNumber { +export function getTokenValue(coin: BNCoin, prices: BNCoin[]): BigNumber { const price = prices.find((price) => price.denom === coin.denom)?.amount || '0' return BN(price).multipliedBy(coin.amount).decimalPlaces(0) } -export function getTokenPrice(denom: string, prices: Coin[]): BigNumber { +export function getTokenPrice(denom: string, prices: BNCoin[]): BigNumber { const price = prices.find((price) => price.denom === denom)?.amount || '0' return BN(price) } diff --git a/src/utils/vaults.ts b/src/utils/vaults.ts index 04681471..79bdc738 100644 --- a/src/utils/vaults.ts +++ b/src/utils/vaults.ts @@ -15,7 +15,7 @@ export function getVaultMetaData(address: string) { export function calculateMaxBorrowAmounts( account: Account, marketAssets: Market[], - prices: Coin[], + prices: BNCoin[], denoms: string[], ): BNCoin[] { const maxAmounts: BNCoin[] = [] @@ -40,7 +40,7 @@ export function getVaultDepositCoinsAndValue( vault: Vault, deposits: BNCoin[], borrowings: BNCoin[], - prices: Coin[], + prices: BNCoin[], ) { const totalValue = [...deposits, ...borrowings].reduce((prev, bnCoin) => { const price = prices.find((coin) => coin.denom === bnCoin.denom)?.amount @@ -76,7 +76,7 @@ export function getVaultSwapActions( vault: Vault, deposits: BNCoin[], borrowings: BNCoin[], - prices: Coin[], + prices: BNCoin[], slippage: number, totalValue: BigNumber, ): Action[] {