feat: multi price source implementation (#299)
This commit is contained in:
parent
515036ac05
commit
d949cc84b7
@ -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/
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
24
src/api/prices/getOraclePrices.ts
Normal file
24
src/api/prices/getOraclePrices.ts
Normal file
@ -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<BNCoin[]> {
|
||||
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
|
||||
}
|
||||
}
|
49
src/api/prices/getPoolPrice.ts
Normal file
49
src/api/prices/getPoolPrice.ts
Normal file
@ -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<BigNumber> {
|
||||
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]
|
||||
}
|
@ -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<PriceResponse> {
|
||||
export default async function getPrice(denom: string): Promise<BigNumber> {
|
||||
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
|
||||
}
|
||||
|
@ -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<Coin[]> {
|
||||
export default async function getPrices(): Promise<BNCoin[]> {
|
||||
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<BNCoin[]> {
|
||||
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
||||
|
||||
return await fetchPythPrices(...priceFeedIds).then(mapResponseToBnCoin(assets))
|
||||
}
|
||||
|
||||
async function requestPoolPrices(assets: Asset[], lookupPrices: BNCoin[]): Promise<BNCoin[]> {
|
||||
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]
|
||||
}
|
||||
|
15
src/api/prices/getPythPrices.ts
Normal file
15
src/api/prices/getPythPrices.ts
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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',
|
||||
},
|
||||
]
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
)
|
||||
|
||||
|
3
src/types/interfaces/asset.d.ts
vendored
3
src/types/interfaces/asset.d.ts
vendored
@ -16,6 +16,9 @@ interface Asset {
|
||||
isStable?: boolean
|
||||
isFavorite?: boolean
|
||||
isAutoLendEnabled?: boolean
|
||||
pythPriceFeedId?: string
|
||||
forceFetchPrice?: boolean
|
||||
testnetDenom?: string
|
||||
}
|
||||
|
||||
interface PseudoAsset {
|
||||
|
12
src/types/interfaces/pyth.d.ts
vendored
Normal file
12
src/types/interfaces/pyth.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
interface PythPriceData {
|
||||
price: PythConfidenceData
|
||||
ema_price: PythConfidenceData
|
||||
id: string
|
||||
}
|
||||
|
||||
interface PythConfidenceData {
|
||||
conf: string
|
||||
expo: number
|
||||
price: string
|
||||
publish_time: number
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -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<T>(arr: Array<T>, predicate: (val: T) => boolean): [Array<T>, Array<T>] {
|
||||
const partitioned: [Array<T>, Array<T>] = [[], []]
|
||||
|
||||
arr.forEach((val: T) => {
|
||||
const partitionIndex: 0 | 1 = predicate(val) ? 0 : 1
|
||||
partitioned[partitionIndex].push(val)
|
||||
})
|
||||
|
||||
return partitioned
|
||||
}
|
||||
|
@ -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')!
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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[] {
|
||||
|
Loading…
Reference in New Issue
Block a user