Pyth price fetching (#723)
* env: remove testing library * fix: use pyth over oracle * fix: fix the endpoints * fix: fix build * tidy: refactor * fix: fixed account fetching * fix: made all queries chain agnostic * fix: fixed the chart position
This commit is contained in:
parent
f1f934d4c1
commit
0960f84b58
@ -55,7 +55,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"@testing-library/react": "^14.0.0",
|
|
||||||
"@types/debounce-promise": "^3.1.9",
|
"@types/debounce-promise": "^3.1.9",
|
||||||
"@types/lodash.debounce": "^4.0.9",
|
"@types/lodash.debounce": "^4.0.9",
|
||||||
"@types/lodash.throttle": "^4.1.8",
|
"@types/lodash.throttle": "^4.1.8",
|
||||||
|
@ -16,7 +16,7 @@ export default async function getAccount(
|
|||||||
const accountPosition: Positions = await cacheFn(
|
const accountPosition: Positions = await cacheFn(
|
||||||
() => creditManagerQueryClient.positions({ accountId: accountId }),
|
() => creditManagerQueryClient.positions({ accountId: accountId }),
|
||||||
positionsCache,
|
positionsCache,
|
||||||
`account/${accountId}`,
|
`${chainConfig.id}/account/${accountId}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const accountKind = await creditManagerQueryClient.accountKind({ accountId: accountId })
|
const accountKind = await creditManagerQueryClient.accountKind({ accountId: accountId })
|
||||||
|
@ -13,7 +13,7 @@ export default async function getAssetParams(
|
|||||||
return iterateContractQuery(paramsQueryClient.allAssetParams)
|
return iterateContractQuery(paramsQueryClient.allAssetParams)
|
||||||
},
|
},
|
||||||
assetParamsCache,
|
assetParamsCache,
|
||||||
'assetParams',
|
`${chainConfig.id}/assetParams`,
|
||||||
600,
|
600,
|
||||||
)
|
)
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
@ -19,7 +19,7 @@ export default async function getOraclePrices(
|
|||||||
const priceResults = await cacheFn(
|
const priceResults = await cacheFn(
|
||||||
() => iterateContractQuery(oracleQueryClient.prices),
|
() => iterateContractQuery(oracleQueryClient.prices),
|
||||||
oraclePriceCache,
|
oraclePriceCache,
|
||||||
'oraclePrices',
|
`${chainConfig.id}/oraclePrices`,
|
||||||
60,
|
60,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ const getAssetRate = async (chainConfig: ChainConfig, asset: Asset) => {
|
|||||||
const response = await cacheFn(
|
const response = await cacheFn(
|
||||||
() => fetch(url).then((res) => res.json()),
|
() => fetch(url).then((res) => res.json()),
|
||||||
poolPriceCache,
|
poolPriceCache,
|
||||||
`poolPrices/${(asset.poolId || 0).toString()}`,
|
`${chainConfig.id}/poolPrices/${(asset.poolId || 0).toString()}`,
|
||||||
60,
|
60,
|
||||||
)
|
)
|
||||||
const pool = response.pool
|
const pool = response.pool
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import { cacheFn, priceCache } from 'api/cache'
|
import { cacheFn, priceCache } from 'api/cache'
|
||||||
import { getOracleQueryClient } from 'api/cosmwasm-client'
|
import getPrices from 'api/prices/getPrices'
|
||||||
import getPoolPrice from 'api/prices/getPoolPrice'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import getPythPrice from 'api/prices/getPythPrices'
|
|
||||||
import { PRICE_ORACLE_DECIMALS } from 'constants/query'
|
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { BN } from 'utils/helpers'
|
|
||||||
|
|
||||||
export default async function getPrice(
|
export default async function getPrice(
|
||||||
chainConfig: ChainConfig,
|
chainConfig: ChainConfig,
|
||||||
@ -15,25 +12,9 @@ export default async function getPrice(
|
|||||||
|
|
||||||
async function fetchPrice(chainConfig: ChainConfig, denom: string) {
|
async function fetchPrice(chainConfig: ChainConfig, denom: string) {
|
||||||
try {
|
try {
|
||||||
const asset = chainConfig.assets.find(byDenom(denom)) as Asset
|
const prices = await getPrices(chainConfig)
|
||||||
|
|
||||||
if (asset.pythPriceFeedId) {
|
return prices.find(byDenom(denom))?.amount ?? BN_ZERO
|
||||||
return (await getPythPrice(chainConfig, [asset.pythPriceFeedId]))[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset.hasOraclePrice) {
|
|
||||||
const oracleQueryClient = await getOracleQueryClient(chainConfig)
|
|
||||||
const priceResponse = await oracleQueryClient.price({ denom: asset.denom })
|
|
||||||
const decimalDiff = asset.decimals - PRICE_ORACLE_DECIMALS
|
|
||||||
|
|
||||||
return BN(priceResponse.price).shiftedBy(decimalDiff)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset.poolId) {
|
|
||||||
return await getPoolPrice(chainConfig, asset)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw `could not fetch the price info for the given denom: ${denom}`
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
import fetchPythPriceData from 'api/prices/getPythPriceData'
|
import fetchPythPriceData from 'api/prices/getPythPriceData'
|
||||||
|
|
||||||
export default async function getPricesData(
|
export default async function getPricesData(assets: Asset[]): Promise<string[]> {
|
||||||
chainConfig: ChainConfig,
|
|
||||||
assets: Asset[],
|
|
||||||
): Promise<string[]> {
|
|
||||||
try {
|
try {
|
||||||
const assetsWithPythPriceFeedId = assets.filter((asset) => !!asset.pythPriceFeedId)
|
const assetsWithPythPriceFeedId = assets.filter((asset) => !!asset.pythPriceFeedId)
|
||||||
return await requestPythPriceData(chainConfig, assetsWithPythPriceFeedId)
|
return await requestPythPriceData(assetsWithPythPriceFeedId)
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.error(ex)
|
console.error(ex)
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestPythPriceData(chainConfig: ChainConfig, assets: Asset[]): Promise<string[]> {
|
async function requestPythPriceData(assets: Asset[]): Promise<string[]> {
|
||||||
if (!assets.length) return []
|
if (!assets.length) return []
|
||||||
|
|
||||||
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
||||||
return await fetchPythPriceData(chainConfig, priceFeedIds)
|
return await fetchPythPriceData(priceFeedIds)
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,35 @@
|
|||||||
import getOraclePrices from 'api/prices/getOraclePrices'
|
import getOraclePrices from 'api/prices/getOraclePrices'
|
||||||
import getPoolPrice from 'api/prices/getPoolPrice'
|
import getPoolPrice from 'api/prices/getPoolPrice'
|
||||||
import fetchPythPrices from 'api/prices/getPythPrices'
|
import fetchPythPrices from 'api/prices/getPythPrices'
|
||||||
|
import chains from 'configs/chains'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { partition } from 'utils/array'
|
import { partition } from 'utils/array'
|
||||||
|
import { getAllAssetsWithPythId } from 'utils/assets'
|
||||||
|
|
||||||
export default async function getPrices(chainConfig: ChainConfig): Promise<BNCoin[]> {
|
export default async function getPrices(chainConfig: ChainConfig): Promise<BNCoin[]> {
|
||||||
const usdPrice = new BNCoin({ denom: 'usd', amount: '1' })
|
const usdPrice = new BNCoin({ denom: 'usd', amount: '1' })
|
||||||
try {
|
|
||||||
|
const pythAndOraclePrices = []
|
||||||
const assetsToFetchPrices = useStore
|
const assetsToFetchPrices = useStore
|
||||||
.getState()
|
.getState()
|
||||||
.chainConfig.assets.filter(
|
.chainConfig.assets.filter(
|
||||||
(asset) => (asset.isEnabled && asset.isMarket) || asset.forceFetchPrice,
|
(asset) => (asset.isEnabled && asset.isMarket) || asset.forceFetchPrice,
|
||||||
)
|
)
|
||||||
const [assetsWithPythPriceFeedId, assetsWithOraclePrices, assetsWithPoolIds] =
|
|
||||||
separateAssetsByPriceSources(assetsToFetchPrices)
|
|
||||||
|
|
||||||
const pythAndOraclePrices = (
|
const assetsWithPythPriceFeedId = getAllAssetsWithPythId(chains)
|
||||||
await Promise.all([
|
const pythPrices = await requestPythPrices(assetsWithPythPriceFeedId)
|
||||||
requestPythPrices(chainConfig, assetsWithPythPriceFeedId),
|
pythAndOraclePrices.push(...pythPrices)
|
||||||
getOraclePrices(chainConfig, assetsWithOraclePrices),
|
|
||||||
])
|
try {
|
||||||
).flat()
|
const [assetsWithOraclePrices, assetsWithPoolIds] =
|
||||||
|
separateAssetsByPriceSources(assetsToFetchPrices)
|
||||||
|
const oraclePrices = await getOraclePrices(chainConfig, assetsWithOraclePrices)
|
||||||
const poolPrices = await requestPoolPrices(chainConfig, assetsWithPoolIds, pythAndOraclePrices)
|
const poolPrices = await requestPoolPrices(chainConfig, assetsWithPoolIds, pythAndOraclePrices)
|
||||||
|
|
||||||
useStore.setState({ isOracleStale: false })
|
useStore.setState({ isOracleStale: false })
|
||||||
|
|
||||||
return [...pythAndOraclePrices, ...poolPrices, usdPrice]
|
return [...pythAndOraclePrices, ...oraclePrices, ...poolPrices, usdPrice]
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.error(ex)
|
console.error(ex)
|
||||||
let message = 'Unknown Error'
|
let message = 'Unknown Error'
|
||||||
@ -34,15 +37,17 @@ export default async function getPrices(chainConfig: ChainConfig): Promise<BNCoi
|
|||||||
if (message.includes('price publish time is too old'))
|
if (message.includes('price publish time is too old'))
|
||||||
useStore.setState({ isOracleStale: true })
|
useStore.setState({ isOracleStale: true })
|
||||||
|
|
||||||
throw ex
|
return [...pythAndOraclePrices, usdPrice]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestPythPrices(chainConfig: ChainConfig, assets: Asset[]): Promise<BNCoin[]> {
|
async function requestPythPrices(assets: Asset[]): Promise<BNCoin[]> {
|
||||||
if (!assets.length) return []
|
if (!assets.length) return []
|
||||||
|
|
||||||
const priceFeedIds = assets.map((a) => a.pythPriceFeedId) as string[]
|
const priceFeedIds = assets
|
||||||
return await fetchPythPrices(chainConfig, priceFeedIds).then(mapResponseToBnCoin(assets))
|
.map((a) => a.pythPriceFeedId)
|
||||||
|
.filter((priceFeedId, index, array) => array.indexOf(priceFeedId) === index) as string[]
|
||||||
|
return await fetchPythPrices(priceFeedIds, assets)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestPoolPrices(
|
async function requestPoolPrices(
|
||||||
@ -55,24 +60,20 @@ async function requestPoolPrices(
|
|||||||
return await Promise.all(requests).then(mapResponseToBnCoin(assets))
|
return await Promise.all(requests).then(mapResponseToBnCoin(assets))
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapResponseToBnCoin = (assets: Asset[]) => (prices: BigNumber[]) =>
|
const mapResponseToBnCoin = (assets: Asset[]) => (prices: BigNumber[]) => {
|
||||||
prices.map((price: BigNumber, index: number) =>
|
return prices.map((price: BigNumber, index: number) =>
|
||||||
BNCoin.fromDenomAndBigNumber(assets[index].denom, price),
|
BNCoin.fromDenomAndBigNumber(assets[index].denom, price),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function separateAssetsByPriceSources(assets: Asset[]) {
|
function separateAssetsByPriceSources(assets: Asset[]) {
|
||||||
// Only fetch Pyth prices for mainnet
|
const assetsWithoutPythPriceFeedId = assets.filter((asset) => !asset.pythPriceFeedId)
|
||||||
const [assetsWithPythPriceFeedId, assetsWithoutPythPriceFeedId] = partition(
|
|
||||||
assets,
|
|
||||||
(asset) => !!asset.pythPriceFeedId,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Don't get oracle price if it's not mainnet and there is a poolId
|
|
||||||
const [assetsWithOraclePrice, assetsWithoutOraclePrice] = partition(
|
const [assetsWithOraclePrice, assetsWithoutOraclePrice] = partition(
|
||||||
assetsWithoutPythPriceFeedId,
|
assetsWithoutPythPriceFeedId,
|
||||||
(asset) => asset.hasOraclePrice || !asset.poolId,
|
(asset) => asset.hasOraclePrice || !asset.poolId,
|
||||||
)
|
)
|
||||||
const assetsWithPoolId = assetsWithoutOraclePrice.filter((asset) => !!asset.poolId)
|
const assetsWithPoolId = assetsWithoutOraclePrice.filter((asset) => !!asset.poolId)
|
||||||
|
|
||||||
return [assetsWithPythPriceFeedId, assetsWithOraclePrice, assetsWithPoolId]
|
return [assetsWithOraclePrice, assetsWithPoolId]
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { cacheFn, pythPriceCache } from 'api/cache'
|
import { cacheFn, pythPriceCache } from 'api/cache'
|
||||||
|
import { pythEndpoints } from 'constants/pyth'
|
||||||
|
|
||||||
export default async function fetchPythPriceData(chainConfig: ChainConfig, priceFeedIds: string[]) {
|
export default async function fetchPythPriceData(priceFeedIds: string[]) {
|
||||||
try {
|
try {
|
||||||
const pricesUrl = new URL(`${chainConfig.endpoints.pyth}/latest_vaas`)
|
const pricesUrl = new URL(`${pythEndpoints.api}/latest_vaas`)
|
||||||
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
||||||
|
|
||||||
const pythDataResponse: string[] = await cacheFn(
|
const pythDataResponse: string[] = await cacheFn(
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { cacheFn, pythPriceCache } from 'api/cache'
|
import { cacheFn, pythPriceCache } from 'api/cache'
|
||||||
|
import { pythEndpoints } from 'constants/pyth'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
export default async function fetchPythPrices(chainConfig: ChainConfig, priceFeedIds: string[]) {
|
export default async function fetchPythPrices(priceFeedIds: string[], assets: Asset[]) {
|
||||||
try {
|
try {
|
||||||
const pricesUrl = new URL(`${chainConfig.endpoints.pyth}/latest_price_feeds`)
|
const pricesUrl = new URL(`${pythEndpoints.api}/latest_price_feeds`)
|
||||||
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
priceFeedIds.forEach((id) => pricesUrl.searchParams.append('ids[]', id))
|
||||||
|
|
||||||
const pythResponse: PythPriceData[] = await cacheFn(
|
const pythResponse: PythPriceData[] = await cacheFn(
|
||||||
@ -13,7 +15,18 @@ export default async function fetchPythPrices(chainConfig: ChainConfig, priceFee
|
|||||||
30,
|
30,
|
||||||
)
|
)
|
||||||
|
|
||||||
return pythResponse.map(({ price }) => BN(price.price).shiftedBy(price.expo))
|
const mappedPriceData = [] as BNCoin[]
|
||||||
|
|
||||||
|
assets.forEach((asset) => {
|
||||||
|
const price = pythResponse.find((pythPrice) => asset.pythPriceFeedId === pythPrice.id)?.price
|
||||||
|
if (price)
|
||||||
|
mappedPriceData.push(
|
||||||
|
BNCoin.fromDenomAndBigNumber(asset.denom, BN(price.price).shiftedBy(price.expo)),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
return mappedPriceData
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,17 @@ export default async function getAprs(chainConfig: ChainConfig) {
|
|||||||
const response = await cacheFn(
|
const response = await cacheFn(
|
||||||
() => fetch(chainConfig.endpoints.aprs.vaults),
|
() => fetch(chainConfig.endpoints.aprs.vaults),
|
||||||
aprsCacheResponse,
|
aprsCacheResponse,
|
||||||
'aprsResponse',
|
`${chainConfig.id}/aprsResponse`,
|
||||||
60,
|
60,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: AprResponse = await cacheFn(() => response.json(), aprsCache, 'aprs', 60)
|
const data: AprResponse = await cacheFn(
|
||||||
|
() => response.json(),
|
||||||
|
aprsCache,
|
||||||
|
`${chainConfig.id}/aprs`,
|
||||||
|
60,
|
||||||
|
)
|
||||||
|
|
||||||
return data.vaults.map((aprData) => {
|
return data.vaults.map((aprData) => {
|
||||||
const finalApr = aprData.apr.projected_apr * 100
|
const finalApr = aprData.apr.projected_apr * 100
|
||||||
|
@ -11,7 +11,7 @@ export const getVaultConfigs = async (
|
|||||||
return await cacheFn(
|
return await cacheFn(
|
||||||
() => iterateContractQuery(paramsQueryClient.allVaultConfigs, 'addr'),
|
() => iterateContractQuery(paramsQueryClient.allVaultConfigs, 'addr'),
|
||||||
vaultConfigsCache,
|
vaultConfigsCache,
|
||||||
'vaultConfigs',
|
`${chainConfig.id}/vaultConfigs`,
|
||||||
600,
|
600,
|
||||||
)
|
)
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
@ -15,7 +15,6 @@ export default async function getAccounts(
|
|||||||
.map((account) => getAccount(chainConfig, account.id))
|
.map((account) => getAccount(chainConfig, account.id))
|
||||||
|
|
||||||
const accounts = await Promise.all($accounts).then((accounts) => accounts)
|
const accounts = await Promise.all($accounts).then((accounts) => accounts)
|
||||||
|
|
||||||
if (accounts) {
|
if (accounts) {
|
||||||
return accounts.sort((a, b) => Number(a.id) - Number(b.id))
|
return accounts.sort((a, b) => Number(a.id) - Number(b.id))
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { defaultSymbolInfo } from 'components/Trade/TradeChart/constants'
|
import { defaultSymbolInfo } from 'components/Trade/TradeChart/constants'
|
||||||
import { MILLISECONDS_PER_MINUTE } from 'constants/math'
|
import { MILLISECONDS_PER_MINUTE } from 'constants/math'
|
||||||
|
import { pythEndpoints } from 'constants/pyth'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import {
|
import {
|
||||||
Bar,
|
Bar,
|
||||||
@ -74,7 +75,7 @@ export class DataFeed implements IDatafeedChartApi {
|
|||||||
chainConfig: ChainConfig,
|
chainConfig: ChainConfig,
|
||||||
) {
|
) {
|
||||||
if (debug) console.log('Start charting library datafeed')
|
if (debug) console.log('Start charting library datafeed')
|
||||||
this.candlesEndpoint = chainConfig.endpoints.pythCandles
|
this.candlesEndpoint = pythEndpoints.candles
|
||||||
this.candlesEndpointTheGraph = chainConfig.endpoints.graphCandles ?? ''
|
this.candlesEndpointTheGraph = chainConfig.endpoints.graphCandles ?? ''
|
||||||
this.assets = assets
|
this.assets = assets
|
||||||
this.debug = debug
|
this.debug = debug
|
||||||
|
@ -160,7 +160,7 @@ export const TVChartContainer = (props: Props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
contentClassName='px-0.5 pb-0.5 h-full bg-chart'
|
contentClassName='px-0.5 pb-0.5 h-full bg-chart w-[calc(100%-2px)] ml-[1px]'
|
||||||
className='h-[70dvh] max-h-[980px] min-h-[560px]'
|
className='h-[70dvh] max-h-[980px] min-h-[560px]'
|
||||||
>
|
>
|
||||||
<div ref={chartContainerRef} className='h-[calc(100%-32px)] overflow-hidden' />
|
<div ref={chartContainerRef} className='h-[calc(100%-32px)] overflow-hidden' />
|
||||||
|
@ -45,7 +45,7 @@ export default function TradeChart(props: Props) {
|
|||||||
<Loading className='h-4 mr-4 w-60' />
|
<Loading className='h-4 mr-4 w-60' />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
contentClassName='px-0.5 pb-0.5 h-full'
|
contentClassName='px-0.5 pb-0.5 h-full bg-chart w-[calc(100%-2px)] ml-[1px]'
|
||||||
className='h-[70dvh] max-h-[980px] min-h-[560px]'
|
className='h-[70dvh] max-h-[980px] min-h-[560px]'
|
||||||
>
|
>
|
||||||
<div className='flex items-center justify-center w-full h-[calc(100%-32px)] rounded-b-base bg-chart'>
|
<div className='flex items-center justify-center w-full h-[calc(100%-32px)] rounded-b-base bg-chart'>
|
||||||
|
@ -35,8 +35,6 @@ const Pion1: ChainConfig = {
|
|||||||
rest: 'https://rest-palvus.pion-1.ntrn.tech/',
|
rest: 'https://rest-palvus.pion-1.ntrn.tech/',
|
||||||
rpc: 'https://rpc-palvus.pion-1.ntrn.tech/',
|
rpc: 'https://rpc-palvus.pion-1.ntrn.tech/',
|
||||||
swap: 'https://testnet-neutron.astroport.fi/swap',
|
swap: 'https://testnet-neutron.astroport.fi/swap',
|
||||||
pyth: 'https://hermes.pyth.network/api',
|
|
||||||
pythCandles: 'https://benchmarks.pyth.network',
|
|
||||||
pools: '', //TODO: ⛓️ Implement this
|
pools: '', //TODO: ⛓️ Implement this
|
||||||
explorer: 'https://testnet.mintscan.io/neutron-testnet',
|
explorer: 'https://testnet.mintscan.io/neutron-testnet',
|
||||||
aprs: {
|
aprs: {
|
||||||
|
@ -134,8 +134,6 @@ const Osmosis1: ChainConfig = {
|
|||||||
rpc: 'https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-rpc-front/',
|
rpc: 'https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-rpc-front/',
|
||||||
rest: 'https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-lcd-front/',
|
rest: 'https://osmosis-node.marsprotocol.io/GGSFGSFGFG34/osmosis-lcd-front/',
|
||||||
swap: 'https://app.osmosis.zone',
|
swap: 'https://app.osmosis.zone',
|
||||||
pyth: 'https://hermes.pyth.network/api',
|
|
||||||
pythCandles: 'https://benchmarks.pyth.network',
|
|
||||||
graphCandles: 'https://osmosis-candles.marsprotocol.io',
|
graphCandles: 'https://osmosis-candles.marsprotocol.io',
|
||||||
explorer: 'https://www.mintscan.io/osmosis/transactions/',
|
explorer: 'https://www.mintscan.io/osmosis/transactions/',
|
||||||
pools:
|
pools:
|
||||||
|
4
src/constants/pyth.ts
Normal file
4
src/constants/pyth.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const pythEndpoints = {
|
||||||
|
api: 'https://hermes.pyth.network/api',
|
||||||
|
candles: 'https://benchmarks.pyth.network',
|
||||||
|
}
|
@ -7,7 +7,7 @@ import useStore from 'store'
|
|||||||
export default function usePricesData() {
|
export default function usePricesData() {
|
||||||
const assets = useStore((s) => s.chainConfig.assets)
|
const assets = useStore((s) => s.chainConfig.assets)
|
||||||
const chainConfig = useChainConfig()
|
const chainConfig = useChainConfig()
|
||||||
return useSWR(`chains/${chainConfig.id}/pricesData`, () => getPricesData(chainConfig, assets), {
|
return useSWR(`chains/${chainConfig.id}/pricesData`, () => getPricesData(assets), {
|
||||||
fallbackData: [],
|
fallbackData: [],
|
||||||
refreshInterval: 30_000,
|
refreshInterval: 30_000,
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
|
2
src/types/interfaces/chain.d.ts
vendored
2
src/types/interfaces/chain.d.ts
vendored
@ -27,8 +27,6 @@ interface ChainConfig {
|
|||||||
rest: string
|
rest: string
|
||||||
rpc: string
|
rpc: string
|
||||||
swap: string
|
swap: string
|
||||||
pyth: string
|
|
||||||
pythCandles: string
|
|
||||||
graphCandles?: string
|
graphCandles?: string
|
||||||
explorer: string
|
explorer: string
|
||||||
pools: string
|
pools: string
|
||||||
|
@ -45,3 +45,14 @@ export function sortAssetsOrPairs(
|
|||||||
return bMarketValue - aMarketValue
|
return bMarketValue - aMarketValue
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAllAssetsWithPythId(chains: { [key: string]: ChainConfig }) {
|
||||||
|
return Object.entries(chains)
|
||||||
|
.map(([_, chainConfig]) => chainConfig.assets)
|
||||||
|
.flatMap((assets) => assets)
|
||||||
|
.filter(
|
||||||
|
(item, index, array) =>
|
||||||
|
index === array.findIndex((foundItem) => foundItem['denom'] === item['denom']),
|
||||||
|
)
|
||||||
|
.filter((asset) => asset.pythPriceFeedId)
|
||||||
|
}
|
||||||
|
@ -78,6 +78,7 @@ export function resolveHLSStrategies(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resolvePerpsPositions(perpPositions: Positions['perps']): PerpsPosition[] {
|
export function resolvePerpsPositions(perpPositions: Positions['perps']): PerpsPosition[] {
|
||||||
|
if (!perpPositions) return []
|
||||||
return perpPositions.map((position) => {
|
return perpPositions.map((position) => {
|
||||||
return {
|
return {
|
||||||
denom: position.denom,
|
denom: position.denom,
|
||||||
|
67
yarn.lock
67
yarn.lock
@ -39,7 +39,7 @@
|
|||||||
tslib "^2.3.0"
|
tslib "^2.3.0"
|
||||||
zen-observable-ts "^1.2.5"
|
zen-observable-ts "^1.2.5"
|
||||||
|
|
||||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.21.4":
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.21.4":
|
||||||
version "7.21.4"
|
version "7.21.4"
|
||||||
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz"
|
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz"
|
||||||
integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==
|
integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==
|
||||||
@ -1103,7 +1103,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.11"
|
regenerator-runtime "^0.13.11"
|
||||||
|
|
||||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4":
|
"@babel/runtime@^7.1.2", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4":
|
||||||
version "7.21.5"
|
version "7.21.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz"
|
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz"
|
||||||
integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==
|
integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==
|
||||||
@ -3406,29 +3406,6 @@
|
|||||||
long "^4.0.0"
|
long "^4.0.0"
|
||||||
protobufjs "~6.11.2"
|
protobufjs "~6.11.2"
|
||||||
|
|
||||||
"@testing-library/dom@^9.0.0":
|
|
||||||
version "9.2.0"
|
|
||||||
resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz"
|
|
||||||
integrity sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==
|
|
||||||
dependencies:
|
|
||||||
"@babel/code-frame" "^7.10.4"
|
|
||||||
"@babel/runtime" "^7.12.5"
|
|
||||||
"@types/aria-query" "^5.0.1"
|
|
||||||
aria-query "^5.0.0"
|
|
||||||
chalk "^4.1.0"
|
|
||||||
dom-accessibility-api "^0.5.9"
|
|
||||||
lz-string "^1.5.0"
|
|
||||||
pretty-format "^27.0.2"
|
|
||||||
|
|
||||||
"@testing-library/react@^14.0.0":
|
|
||||||
version "14.0.0"
|
|
||||||
resolved "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz"
|
|
||||||
integrity sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.12.5"
|
|
||||||
"@testing-library/dom" "^9.0.0"
|
|
||||||
"@types/react-dom" "^18.0.0"
|
|
||||||
|
|
||||||
"@tippyjs/react@^4.2.6":
|
"@tippyjs/react@^4.2.6":
|
||||||
version "4.2.6"
|
version "4.2.6"
|
||||||
resolved "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz"
|
resolved "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz"
|
||||||
@ -3441,11 +3418,6 @@
|
|||||||
resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz"
|
resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz"
|
||||||
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
|
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
|
||||||
|
|
||||||
"@types/aria-query@^5.0.1":
|
|
||||||
version "5.0.1"
|
|
||||||
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz"
|
|
||||||
integrity sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==
|
|
||||||
|
|
||||||
"@types/bn.js@5.1.1", "@types/bn.js@^5.1.0":
|
"@types/bn.js@5.1.1", "@types/bn.js@^5.1.0":
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz"
|
resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz"
|
||||||
@ -3581,7 +3553,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz"
|
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz"
|
||||||
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
|
||||||
|
|
||||||
"@types/react-dom@18.2.15", "@types/react-dom@^18.0.0":
|
"@types/react-dom@18.2.15":
|
||||||
version "18.2.15"
|
version "18.2.15"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.15.tgz#921af67f9ee023ac37ea84b1bc0cc40b898ea522"
|
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.15.tgz#921af67f9ee023ac37ea84b1bc0cc40b898ea522"
|
||||||
integrity sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==
|
integrity sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==
|
||||||
@ -3958,11 +3930,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
|
|
||||||
ansi-styles@^5.0.0:
|
|
||||||
version "5.2.0"
|
|
||||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
|
|
||||||
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
|
|
||||||
|
|
||||||
ansi-styles@^6.0.0, ansi-styles@^6.2.1:
|
ansi-styles@^6.0.0, ansi-styles@^6.2.1:
|
||||||
version "6.2.1"
|
version "6.2.1"
|
||||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz"
|
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz"
|
||||||
@ -3991,7 +3958,7 @@ argparse@^2.0.1:
|
|||||||
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
|
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
|
||||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||||
|
|
||||||
aria-query@^5.0.0, aria-query@^5.1.3:
|
aria-query@^5.1.3:
|
||||||
version "5.1.3"
|
version "5.1.3"
|
||||||
resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz"
|
resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz"
|
||||||
integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==
|
integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==
|
||||||
@ -4429,7 +4396,7 @@ chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
chalk@^4.0.0, chalk@^4.1.0:
|
chalk@^4.0.0:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
||||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||||
@ -4968,11 +4935,6 @@ doctrine@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
dom-accessibility-api@^0.5.9:
|
|
||||||
version "0.5.16"
|
|
||||||
resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz"
|
|
||||||
integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
|
|
||||||
|
|
||||||
dom-helpers@^3.4.0:
|
dom-helpers@^3.4.0:
|
||||||
version "3.4.0"
|
version "3.4.0"
|
||||||
resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz"
|
resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz"
|
||||||
@ -6887,11 +6849,6 @@ lru-cache@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist "^4.0.0"
|
yallist "^4.0.0"
|
||||||
|
|
||||||
lz-string@^1.5.0:
|
|
||||||
version "1.5.0"
|
|
||||||
resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz"
|
|
||||||
integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==
|
|
||||||
|
|
||||||
magic-string@^0.27.0:
|
magic-string@^0.27.0:
|
||||||
version "0.27.0"
|
version "0.27.0"
|
||||||
resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz"
|
resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz"
|
||||||
@ -7516,15 +7473,6 @@ prettier@^3.0.3:
|
|||||||
resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz"
|
resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz"
|
||||||
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
|
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
|
||||||
|
|
||||||
pretty-format@^27.0.2:
|
|
||||||
version "27.5.1"
|
|
||||||
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz"
|
|
||||||
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^5.0.1"
|
|
||||||
ansi-styles "^5.0.0"
|
|
||||||
react-is "^17.0.1"
|
|
||||||
|
|
||||||
process-nextick-args@~2.0.0:
|
process-nextick-args@~2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
|
resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
|
||||||
@ -7670,11 +7618,6 @@ react-is@^16.10.2, react-is@^16.13.1, react-is@^16.7.0:
|
|||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
|
|
||||||
react-is@^17.0.1:
|
|
||||||
version "17.0.2"
|
|
||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
|
||||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
|
||||||
|
|
||||||
react-lifecycles-compat@^3.0.4:
|
react-lifecycles-compat@^3.0.4:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"
|
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user