Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip:returns-v1 #1374

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions src/api/categories/protocols/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from '~/api/categories/adaptors'
import { getPeggedAssets } from '../stablecoins'
import { formatProtocolsList } from '~/hooks/data/defi'
import { stringify } from 'querystring'

export const getProtocolsRaw = () => fetch(PROTOCOLS_API).then((r) => r.json())

Expand Down Expand Up @@ -735,3 +736,99 @@ export async function getLSDPageData() {
}
}
}

export async function getROIData() {
const dateNow = Math.floor(Date.now() / 1000)
const secPerDay = 60 * 60 * 24
const date1d = dateNow - secPerDay
const date7d = dateNow - secPerDay * 7
const date30d = dateNow - secPerDay * 30

const dates = [dateNow, date1d, date7d, date30d]

const url = 'https://coins.llama.fi/batchHistorical'

// top 1k cg tokens
const tokenList = (await fetch('https://api.llama.fi/sortedTokenlist?a').then((r) => r.json())).map(
(t) => `coingecko:${t.id}`
)

// pull prices
const size = 80
const pages = Math.ceil(tokenList.length / size)

const prices = await Promise.all(
[...Array(pages)].map(async (p, i) => {
const tokens = tokenList.slice(i * size, size * (i + 1))

const query = tokens.reduce((acc, t) => {
acc[t] = dates
return acc
}, {})

const queryString = stringify({
coins: JSON.stringify(query),
searchWidth: 600
})

return (await fetch(`${url}?${queryString}`).then((r) => r.json())).coins
})
)
// pull btc and eth separately
const queryStringBtcEth = stringify({
coins: JSON.stringify({ 'coingecko:bitcoin': dates, 'coingecko:ethereum': dates }),
searchWidth: 600
})
const pricesBtcEth = (await fetch(`${url}?${queryStringBtcEth}`).then((r) => r.json())).coins

// flatten
const data = { ...pricesBtcEth, ...Object.assign({}, ...prices.flat()) }

const [btc, eth] = [data['coingecko:bitcoin']?.prices, data['coingecko:ethereum']?.prices].map((p) =>
p?.sort((a, b) => b.timestamp - a.timestamp)
)
const [btcNow, ethNow] = [btc[0]?.price, eth[0]?.price]

const res = Object.values(data).map(({ prices, symbol }) => {
const sortedPrices = prices.sort((a, b) => b.timestamp - a.timestamp)
const priceNow = sortedPrices[0]?.price

const [usdDeltas, btcDeltas, ethDeltas] = [[], [], []]

for (let i = 0; i < sortedPrices.length - 1; i++) {
const priceOld = sortedPrices[i + 1]?.price
const usdDelta = ((priceNow - priceOld) / priceOld) * 100

const btcRatioOld = priceOld / btc[i + 1]?.price
const btcRatioNow = priceNow / btcNow
const btcDelta = ((btcRatioNow - btcRatioOld) / btcRatioOld) * 100

const ethRatioOld = priceOld / eth[i + 1]?.price
const ethRatioNow = priceNow / ethNow
const ethDelta = ((ethRatioNow - ethRatioOld) / ethRatioOld) * 100

usdDeltas.push(usdDelta)
btcDeltas.push(btcDelta)
ethDeltas.push(ethDelta)
}

return {
symbol,
usd1d: usdDeltas[0] ?? null,
usd7d: usdDeltas[1] ?? null,
usd30d: usdDeltas[2] ?? null,
btc1d: btcDeltas[0] ?? null,
btc7d: btcDeltas[1] ?? null,
btc30d: btcDeltas[2] ?? null,
eth1d: ethDeltas[0] ?? null,
eth7d: ethDeltas[1] ?? null,
eth30d: ethDeltas[2] ?? null
}
})

return {
props: {
priceData: res
}
}
}
19 changes: 10 additions & 9 deletions src/components/ECharts/BarChart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ export default function BarChart({
itemStyle: {
color: chartColor
},
data: []
data: chartData.map((i) => i[1])
}

chartData.forEach(([date, value]) => {
series.data.push([getUtcDateObject(date), value])
})
// chartData.forEach(([date, value]) => {
// series.data.push([getUtcDateObject(date), value])
// })

return series
} else {
Expand Down Expand Up @@ -100,11 +100,12 @@ export default function BarChart({
}
})

chartData.forEach(({ date, ...item }) => {
selectedStacks.forEach((stack) => {
series.find((t) => t.name === stack)?.data.push([getUtcDateObject(date), item[stack] || 0])
})
})
// chartData.forEach(({ date, ...item }) => {
// selectedStacks.forEach((stack) => {
// series.find((t) => t.name === stack)?.data.push([getUtcDateObject(date), item[stack] || 0])
// // series.find((t) => t.name === stack)?.data.push([item[stack] || 0])
// })
// })

return series
}
Expand Down
102 changes: 101 additions & 1 deletion src/components/Table/Defi/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from '~/utils'
import { AccordionButton, Name } from '../shared'
import { formatColumnOrder } from '../utils'
import type { ICategoryRow, IChainsRow, IForksRow, IOraclesRow, ILSDRow } from './types'
import type { ICategoryRow, IChainsRow, IForksRow, IOraclesRow, ILSDRow, IROIRow } from './types'

export const oraclesColumn: ColumnDef<IOraclesRow>[] = [
{
Expand Down Expand Up @@ -782,6 +782,106 @@ export const LSDColumn: ColumnDef<ILSDRow>[] = [
}
]

export const ROIColumn: ColumnDef<IROIRow>[] = [
{
header: 'Coin',
accessorKey: 'symbol',
enableSorting: false,
cell: ({ getValue, row, table }) => {
const index = row.depth === 0 ? table.getSortedRowModel().rows.findIndex((x) => x.id === row.id) : row.index

return (
<Name>
<span>{index + 1}</span>
{getValue()}
</Name>
)
},
size: 280
},
{
header: '1d USD',
accessorKey: 'usd1d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '7d USD',
accessorKey: 'usd7d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '30d USD',
accessorKey: 'usd30d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '1d ETH',
accessorKey: 'eth1d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '7d ETH',
accessorKey: 'eth7d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '30d ETH',
accessorKey: 'eth30d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '1d BTC',
accessorKey: 'btc1d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '7d BTC',
accessorKey: 'btc7d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
},
{
header: '30d BTC',
accessorKey: 'btc30d',
cell: ({ getValue }) => <>{formattedPercent(getValue())}</>,
meta: {
align: 'end'
},
size: 110
}
]

function formatCexInflows(value) {
let x = value
let isNegative = false
Expand Down
6 changes: 4 additions & 2 deletions src/components/Table/Defi/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import {
chainsTableColumnOrders,
forksColumn,
oraclesColumn,
LSDColumn
LSDColumn,
ROIColumn
} from './columns'
import type { IOraclesRow, IForksRow, ICategoryRow, IChainsRow, ILSDRow } from './types'
import type { IOraclesRow, IForksRow, ICategoryRow, IChainsRow, ILSDRow, IROIRow } from './types'
import useWindowSize from '~/hooks/useWindowSize'

export default function DefiProtocolsTable({ data, columns }) {
Expand Down Expand Up @@ -53,6 +54,7 @@ export const ProtocolsCategoriesTable = ({ data }: { data: Array<ICategoryRow> }
)

export const LSDTable = ({ data }: { data: Array<ILSDRow> }) => <DefiProtocolsTable data={data} columns={LSDColumn} />
export const ROITable = ({ data }: { data: Array<IROIRow> }) => <DefiProtocolsTable data={data} columns={ROIColumn} />

export function DefiChainsTable({ data }) {
const [sorting, setSorting] = React.useState<SortingState>([])
Expand Down
8 changes: 8 additions & 0 deletions src/components/Table/Defi/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ export interface ILSDRow {
logo: string
mcap: number
}

export interface IROIRow {
symbol: string
usd7d: number
btc7d: number
eth7d: number
logo: string
}
2 changes: 1 addition & 1 deletion src/components/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export {
NftChainsTable,
NftMarketplacesTable
} from './Nfts/ChainsAndMarketplaces'
export { OraclesTable, ForksTable, ProtocolsCategoriesTable, LSDTable } from './Defi'
export { OraclesTable, ForksTable, ProtocolsCategoriesTable, LSDTable, ROITable } from './Defi'
export { FeesTable } from './Fees'
export { DexsTable, VolumeByChainsTable } from './Dexs'
export { OverviewTable } from './Adaptors'
Expand Down
51 changes: 51 additions & 0 deletions src/pages/prices.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react'
import dynamic from 'next/dynamic'
import Layout from '~/layout'
import { ROITable } from '~/components/Table'
import { ProtocolsChainsSearch } from '~/components/Search'
import { maxAgeForNext } from '~/api'
import { getROIData } from '~/api/categories/protocols'

import type { IBarChartProps } from '~/components/ECharts/types'

const BarChart = dynamic(() => import('~/components/ECharts/BarChart'), {
ssr: false
}) as React.FC<IBarChartProps>

export async function getStaticProps() {
const data = await getROIData()

return {
...data,
revalidate: maxAgeForNext([22])
}
}

const PageView = ({ priceData }) => {
const chartData = priceData.map((p) => [p.symbol, p?.usd1d]).sort((a, b) => b[1] - a[1])

const options = {
xAxis: {
type: 'category',
data: chartData.map((i) => i[0])
}
}

return (
<>
<ProtocolsChainsSearch step={{ category: 'Home', name: 'Price ROI' }} />

<BarChart chartData={chartData} title="ROI" valueSymbol="%" chartOptions={options} color="#4f8fea" />

<ROITable data={priceData} />
</>
)
}

export default function PriceROI(props) {
return (
<Layout title={`Price ROI - DefiLlama`} defaultSEO>
<PageView {...props} />
</Layout>
)
}