diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 68cf966d2..aeb7b33ad 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -23,13 +23,14 @@ jobs: upload: runs-on: ubuntu-latest + permissions: write-all steps: - name: Checkout uses: actions/checkout@v2 - name: Install Vercel CLI run: npm install -g vercel@22.0.1 - name: Deploy to Vercel Action - uses: BetaHuhn/deploy-to-vercel-action@v1 + uses: BetaHuhn/deploy-to-vercel-action@latest with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} diff --git a/src/components/NewPosition/NewPosition.tsx b/src/components/NewPosition/NewPosition.tsx index ac830f6c8..b1f40a69e 100644 --- a/src/components/NewPosition/NewPosition.tsx +++ b/src/components/NewPosition/NewPosition.tsx @@ -718,6 +718,8 @@ export const NewPosition: React.FC = ({ getTicksInsideRange={getTicksInsideRange} shouldResetPlot={shouldResetPlot} setShouldResetPlot={setShouldResetPlot} + tokenAPriceData={tokenAPriceData} + tokenBPriceData={tokenBPriceData} /> ) : ( void + tokenAPriceData?: TokenPriceData + tokenBPriceData?: TokenPriceData } export const RangeSelector: React.FC = ({ @@ -87,7 +90,9 @@ export const RangeSelector: React.FC = ({ setConcentrationIndex, getTicksInsideRange, shouldResetPlot, - setShouldResetPlot + setShouldResetPlot, + tokenAPriceData, + tokenBPriceData }) => { const classes = useStyles() @@ -388,6 +393,7 @@ export const RangeSelector: React.FC = ({ Current price Global price + Buy/sell price @@ -420,6 +426,8 @@ export const RangeSelector: React.FC = ({ hasError={hasTicksError} reloadHandler={reloadHandler} volumeRange={volumeRange} + tokenAPriceData={tokenAPriceData} + tokenBPriceData={tokenBPriceData} /> Set price range diff --git a/src/components/NewPosition/RangeSelector/style.ts b/src/components/NewPosition/RangeSelector/style.ts index 89e157fb4..ed951b9eb 100644 --- a/src/components/NewPosition/RangeSelector/style.ts +++ b/src/components/NewPosition/RangeSelector/style.ts @@ -218,6 +218,13 @@ const useStyles = makeStyles((theme: Theme) => ({ ...typography.caption2, textAlign: 'right', marginLeft: 4 + }, + buySellPrice: { + display: 'inline-block', + color: colors.white.main, + ...typography.caption2, + textAlign: 'right', + marginLeft: 4 } })) diff --git a/src/components/PriceRangePlot/PriceRangePlot.tsx b/src/components/PriceRangePlot/PriceRangePlot.tsx index 8d3942f79..c57ff0433 100644 --- a/src/components/PriceRangePlot/PriceRangePlot.tsx +++ b/src/components/PriceRangePlot/PriceRangePlot.tsx @@ -8,7 +8,7 @@ import classNames from 'classnames' import ZoomInIcon from '@static/svg/zoom-in-icon.svg' import ZoomOutIcon from '@static/svg/zoom-out-icon.svg' import Brush from './Brush/Brush' -import { nearestTickIndex } from '@consts/utils' +import { nearestTickIndex, TokenPriceData } from '@consts/utils' import { PlotTickData } from '@reducers/positions' import loader from '@static/gif/loader.gif' import useStyles from './style' @@ -42,6 +42,8 @@ export interface IPriceRangePlot { min: number max: number } + tokenAPriceData?: TokenPriceData + tokenBPriceData?: TokenPriceData } export const PriceRangePlot: React.FC = ({ @@ -67,7 +69,9 @@ export const PriceRangePlot: React.FC = ({ coverOnLoading = false, hasError = false, reloadHandler, - volumeRange + volumeRange, + tokenAPriceData, + tokenBPriceData }) => { const classes = useStyles() @@ -315,6 +319,52 @@ export const PriceRangePlot: React.FC = ({ ) } + const buyPriceLayer: Layer = ({ innerWidth, innerHeight }) => { + if (typeof tokenAPriceData === 'undefined' || typeof tokenBPriceData === 'undefined') { + return null + } + + const unitLen = innerWidth / (plotMax - plotMin) + return ( + + + + + + + + + + ) + } + + const sellPriceLayer: Layer = ({ innerWidth, innerHeight }) => { + if (typeof tokenAPriceData === 'undefined' || typeof tokenBPriceData === 'undefined') { + return null + } + + const unitLen = innerWidth / (plotMax - plotMin) + return ( + + + + + + + + + + ) + } + const volumeRangeLayer: Layer = ({ innerWidth, innerHeight }) => { if (typeof volumeRange === 'undefined') { return null @@ -504,6 +554,8 @@ export const PriceRangePlot: React.FC = ({ 'areas', 'lines', globalPriceLayer, + buyPriceLayer, + sellPriceLayer, currentLayer, volumeRangeLayer, brushLayer, diff --git a/src/store/consts/utils.ts b/src/store/consts/utils.ts index c6226d9e9..9ae10d74c 100644 --- a/src/store/consts/utils.ts +++ b/src/store/consts/utils.ts @@ -776,10 +776,13 @@ interface RawJupApiResponse { string, { id: string - mintSymbol: string - vsToken: string - vsTokenSymbol: string - price: number + price: string + extraInfo?: { + quotedPrice: { + buyPrice: string + sellPrice: string + } + } } > timeTaken: number @@ -797,11 +800,13 @@ export interface CoingeckoApiPriceData { export interface TokenPriceData { price: number + buyPrice: number + sellPrice: number } export const getCoingeckoPricesData = async ( ids: string[] -): Promise> => { +): Promise>> => { const maxTokensPerRequest = 250 const chunkedIds = [] for (let i = 0; i < ids.length; i += maxTokensPerRequest) { @@ -822,10 +827,13 @@ export const getCoingeckoPricesData = async ( Object.values(response.data).map(({ id, current_price: price }) => ({ id, price })) ) - return concatRes.reduce>((acc, { id, price }) => { - acc[id] = { price: price ?? 0 } - return acc - }, {}) + return concatRes.reduce>>( + (acc, { id, price }) => { + acc[id] = { price: price ?? 0 } + return acc + }, + {} + ) } export const getJupPricesData = async (ids: string[]): Promise> => { @@ -838,16 +846,22 @@ export const getJupPricesData = async (ids: string[]): Promise - await axios.get(`https://price.jup.ag/v4/price?ids=${idsChunk.join(',')}`) + await axios.get( + `https://api.jup.ag/price/v2?ids=${idsChunk.join(',')}&showExtraInfo=true` + ) ) const responses = await Promise.all(requests) const concatRes = responses.flatMap(response => - Object.values(response.data.data).map(({ id, price }) => ({ id, price })) + Object.values(response.data.data).map(({ id, price, extraInfo }) => ({ id, price, extraInfo })) ) - return concatRes.reduce>((acc, { id, price }) => { - acc[id] = { price: price ?? 0 } + return concatRes.reduce>((acc, { id, price, extraInfo }) => { + acc[id] = { + price: Number(price), + buyPrice: Number(extraInfo?.quotedPrice.buyPrice ?? 0), + sellPrice: Number(extraInfo?.quotedPrice.sellPrice ?? 0) + } return acc }, {}) } @@ -1106,16 +1120,27 @@ export const thresholdsWithTokenDecimal = (decimals: number): FormatNumberThresh ] export const getJupTokenPrice = async (id: string): Promise => { - const response = await axios.get(`https://price.jup.ag/v4/price?ids=${id}&vsToken=USDC`) + const response = await axios.get( + `https://api.jup.ag/price/v2?ids=${id}&showExtraInfo=true` + ) + return { - price: response.data.data[id].price ?? 0 + price: Number(response.data.data[id].price), + buyPrice: Number(response.data.data[id].extraInfo?.quotedPrice.buyPrice ?? 0), + sellPrice: Number(response.data.data[id].extraInfo?.quotedPrice.sellPrice ?? 0) } } -export const getJupTokensRatioPrice = async (id: string, vsId: string): Promise => { - const response = await axios.get(`https://price.jup.ag/v4/price?ids=${id}&vsToken=${vsId}`) +export const getJupTokensRatioPrice = async ( + id: string, + vsId: string +): Promise> => { + const response = await axios.get( + `https://api.jup.ag/price/v2?ids=${id}&vsToken=${vsId}` + ) + return { - price: response.data.data[id].price ?? 0 + price: Number(response.data.data[id].price) } }