lev-stake-sol/apis/birdeye/helpers.ts

201 lines
4.9 KiB
TypeScript

import Decimal from 'decimal.js'
import { BirdeyePriceResponse } from 'types'
import { DAILY_SECONDS } from 'utils/constants'
/* eslint-disable @typescript-eslint/no-explicit-any */
export const NEXT_PUBLIC_BIRDEYE_API_KEY =
process.env.NEXT_PUBLIC_BIRDEYE_API_KEY ||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NzM0NTE4MDF9.KTEqB1hrmZTMzk19rZNx9aesh2bIHj98Cb8sg5Ikz-Y'
export const API_URL = 'https://public-api.birdeye.so/'
export const socketUrl = `wss://public-api.birdeye.so/socket?x-api-key=${NEXT_PUBLIC_BIRDEYE_API_KEY}`
// Make requests to Birdeye API
export async function makeApiRequest(path: string) {
const response = await fetch(`${API_URL}${path}`, {
headers: {
'X-API-KEY': NEXT_PUBLIC_BIRDEYE_API_KEY,
},
})
return response.json()
}
const RESOLUTION_MAPPING: Record<string, string> = {
'1': '1m',
'3': '3m',
'5': '5m',
'15': '15m',
'30': '30m',
'60': '1H',
'120': '2H',
'240': '4H',
'1D': '1D',
'1W': '1W',
}
export function parseResolution(resolution: string) {
if (!resolution || !RESOLUTION_MAPPING[resolution])
return RESOLUTION_MAPPING[0]
return RESOLUTION_MAPPING[resolution]
}
export function getNextBarTime(lastBar: any, resolution = '1D') {
if (!lastBar) return
const lastCharacter = resolution.slice(-1)
let nextBarTime
switch (true) {
case lastCharacter === 'W':
nextBarTime = 7 * 24 * 60 * 60 * 1000 + lastBar.time
break
case lastCharacter === 'D':
nextBarTime = 1 * 24 * 60 * 60 * 1000 + lastBar.time
break
default:
nextBarTime = 1 * 60 * 1000 + lastBar.time
break
}
return nextBarTime
}
export const SUBSCRIPT_NUMBER_MAP: Record<number, string> = {
4: '₄',
5: '₅',
6: '₆',
7: '₇',
8: '₈',
9: '₉',
10: '₁₀',
11: '₁₁',
12: '₁₂',
13: '₁₃',
14: '₁₄',
15: '₁₅',
}
export const calcPricePrecision = (num: number | string) => {
if (!num) return 8
switch (true) {
case Math.abs(+num) < 0.00000000001:
return 16
case Math.abs(+num) < 0.000000001:
return 14
case Math.abs(+num) < 0.0000001:
return 12
case Math.abs(+num) < 0.00001:
return 10
case Math.abs(+num) < 0.05:
return 6
case Math.abs(+num) < 1:
return 4
case Math.abs(+num) < 20:
return 3
default:
return 2
}
}
export const formatPrice = (
num: number,
precision?: number,
gr0 = true,
): string => {
if (!num) {
return num.toString()
}
if (!precision) {
precision = calcPricePrecision(+num)
}
let formated: string = new Decimal(num).toFixed(precision)
if (formated.match(/^0\.[0]+$/g)) {
formated = formated.replace(/\.[0]+$/g, '')
}
if (gr0 && formated.match(/\.0{4,15}[1-9]+/g)) {
const match = formated.match(/\.0{4,15}/g)
if (!match) return ''
const matchString: string = match[0].slice(1)
formated = formated.replace(
/\.0{4,15}/g,
`.0${SUBSCRIPT_NUMBER_MAP[matchString.length]}`,
)
}
return formated
}
export type SwapChartDataItem = {
time: number
price: number
inputTokenPrice: number
outputTokenPrice: number
}
export const fetchSwapChartPrices = async (
inputMint: string | undefined,
outputMint: string | undefined,
daysToShow: string,
) => {
if (!inputMint || !outputMint) return []
const interval = daysToShow === '1' ? '30m' : daysToShow === '7' ? '1H' : '1D'
const queryEnd = Math.floor(Date.now() / 1000)
const queryStart = queryEnd - parseInt(daysToShow) * DAILY_SECONDS
const inputQuery = `defi/history_price?address=${inputMint}&address_type=token&type=${interval}&time_from=${queryStart}&time_to=${queryEnd}`
const outputQuery = `defi/history_price?address=${outputMint}&address_type=token&type=${interval}&time_from=${queryStart}&time_to=${queryEnd}`
try {
const [inputResponse, outputResponse] = await Promise.all([
makeApiRequest(inputQuery),
makeApiRequest(outputQuery),
])
if (
inputResponse.success &&
inputResponse?.data?.items?.length &&
outputResponse.success &&
outputResponse?.data?.items?.length
) {
const parsedData: SwapChartDataItem[] = []
const inputData = inputResponse.data.items
const outputData = outputResponse.data.items
for (const item of inputData) {
const outputDataItem = outputData.find(
(data: BirdeyePriceResponse) => data.unixTime === item.unixTime,
)
const curentTimestamp = Date.now() / 1000
if (outputDataItem && item.unixTime <= curentTimestamp) {
parsedData.push({
time: Math.floor(item.unixTime * 1000),
price: item.value / outputDataItem.value,
inputTokenPrice: item.value,
outputTokenPrice: outputDataItem.value,
})
}
}
return parsedData
} else return []
} catch (e) {
console.log('failed to fetch swap chart data from birdeye', e)
return []
}
}