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

refactor: use prices api for dao fees #635

Merged
merged 8 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const CrvStats: React.FC = () => {
}
}, [veCrvData.totalCrv, veCrvData.fetchStatus, getVeCrvData, provider])

const veCrvApr = aprLoading ? 0 : calculateApr(veCrvFees.fees[1].fees_usd, veCrvData.totalVeCrv, crv)
const veCrvApr = aprLoading ? 0 : calculateApr(veCrvFees.fees[1].feesUsd, veCrvData.totalVeCrv, crv)

const loading = Boolean(provider && veCrvLoading)
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react'
import { BarChart, Bar, Cell, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'

import { formatNumber } from 'ui/src/utils'
import { convertToLocaleTimestamp, formatDateFromTimestamp, formatNumber } from 'ui/src/utils'

import FeesBarChartTooltip from './FeesBarChartTooltip'
import { VeCrvFee } from '@/dao/types/dao.types'
import type { Distribution } from '@curvefi/prices-api/revenue'

type FeesBarChartProps = {
data: VeCrvFee[]
data: Distribution[]
height?: number
}

Expand All @@ -26,23 +26,24 @@ const FeesBarChart: React.FC<FeesBarChartProps> = ({ data, height = 500 }) => (
>
<CartesianGrid fillOpacity={0.6} strokeWidth={0.3} horizontal={true} vertical={false} />
<XAxis
dataKey="date"
dataKey="timestamp"
tick={{ fill: 'var(--page--text-color)', fontSize: 'var(--font-size-1)' }}
tickFormatter={(value: Date) => `${formatDateFromTimestamp(convertToLocaleTimestamp(value.getUTCTimestamp()))}`}
tickLine={{ opacity: 0.3, strokeWidth: 0.3 }}
axisLine={{ opacity: 0.3, strokeWidth: 0.3 }}
minTickGap={20}
allowDataOverflow={false}
/>
<YAxis
dataKey="fees_usd"
dataKey="feesUsd"
tick={{ fill: 'var(--page--text-color)', fontSize: 'var(--font-size-1)' }}
tickLine={{ opacity: 0.3, strokeWidth: 0.3 }}
axisLine={{ opacity: 0.3, strokeWidth: 0.3 }}
tickFormatter={(value) => `${formatNumber(value, { showDecimalIfSmallNumberOnly: true })}`}
tickCount={10}
/>
<Tooltip content={FeesBarChartTooltip} cursor={{ opacity: 0.3 }} />
<Bar dataKey="fees_usd" label={false} fill={'var(--primary-400)'} isAnimationActive={false}>
<Bar dataKey="feesUsd" label={false} fill={'var(--primary-400)'} isAnimationActive={false}>
{data.map((entry, index) => (
<Cell key={`$cell-${index}`} fill={'var(--primary-400)'} />
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,31 @@ import { TooltipProps } from 'recharts'
import styled from 'styled-components'
import { t } from '@lingui/macro'

import { formatNumber, convertToLocaleTimestamp } from '@ui/utils/utilsFormat'
import { convertToLocaleTimestamp, formatDateFromTimestamp, formatNumber } from '@ui/utils/utilsFormat'

import Box from '@ui/Box'
import type { Distribution } from '@curvefi/prices-api/revenue'

const FeesBarChartTooltip: React.FC<TooltipProps<ValueType, NameType>> = ({ active, payload }) => {
const currentTime = convertToLocaleTimestamp(new Date().getTime() / 1000)

if (active && payload && payload.length) {
const { date, fees_usd, timestamp } = payload[0].payload
const payloadTimestamp = convertToLocaleTimestamp(new Date(timestamp).getTime() / 1000)
const { feesUsd, timestamp } = payload[0].payload as Distribution

return (
<TooltipWrapper>
<Box flex flexColumn flexGap={'var(--spacing-1)'}>
<TooltipColumn>
<TooltipDataTitle>{t`Distribution Date`}</TooltipDataTitle>
{date ? (
<TooltipData>
{date}
{payloadTimestamp > currentTime && <strong> {t`(in progress)`}</strong>}
</TooltipData>
) : (
<TooltipDataNotAvailable>{t`N/A`}</TooltipDataNotAvailable>
)}
<TooltipData>
{formatDateFromTimestamp(convertToLocaleTimestamp(timestamp.getUTCTimestamp()))}
0xAlunara marked this conversation as resolved.
Show resolved Hide resolved
{timestamp.getTime() > Date.now() && <strong> {t`(in progress)`}</strong>}
</TooltipData>
</TooltipColumn>
</Box>

<Box flex flexColumn flexGap={'var(--spacing-1)'}>
<TooltipColumn>
<TooltipDataTitle>{t`veCRV Fees`}</TooltipDataTitle>
{fees_usd ? (
<TooltipData>{formatNumber(fees_usd, { currency: 'USD', notation: 'compact' })}</TooltipData>
) : (
<TooltipDataNotAvailable>{t`N/A`}</TooltipDataNotAvailable>
)}
<TooltipData>{formatNumber(feesUsd, { currency: 'USD', notation: 'compact' })}</TooltipData>
</TooltipColumn>
</Box>
</TooltipWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { t } from '@lingui/macro'
import { useEffect } from 'react'

import useStore from '@/dao/store/useStore'
import { formatNumber, convertToLocaleTimestamp } from '@ui/utils'
import { convertToLocaleTimestamp, formatDateFromTimestamp, formatNumber } from '@ui/utils'

import Box from '@ui/Box'
import Spinner from '../../Spinner'
Expand All @@ -17,8 +17,6 @@ const VeCrcFees: React.FC = () => {
const feesError = veCrvFees.fetchStatus === 'ERROR'
const feesReady = veCrvFees.fetchStatus === 'SUCCESS'

const currentTime = convertToLocaleTimestamp(new Date().getTime() / 1000)

useEffect(() => {
if (veCrvFees.fees.length === 0 && !feesError) {
getVeCrvFees()
Expand All @@ -43,13 +41,13 @@ const VeCrcFees: React.FC = () => {
<>
<FeesContainer>
{veCrvFees.fees.map((item) => (
<FeeRow key={item.date}>
<FeeRow key={item.timestamp.getTime()}>
<FeeDate>
{item.date}
{item.timestamp > currentTime && <span> {t`(in progress)`}</span>}
{formatDateFromTimestamp(convertToLocaleTimestamp(item.timestamp.getUTCTimestamp()))}
{item.timestamp.getTime() > Date.now() && <span> {t`(in progress)`}</span>}
0xAlunara marked this conversation as resolved.
Show resolved Hide resolved
</FeeDate>
<FeeData>
{formatNumber(item.fees_usd, {
{formatNumber(item.feesUsd, {
currency: 'USD',
notation: 'compact',
})}
Expand Down
32 changes: 5 additions & 27 deletions apps/main/src/dao/store/createAnalyticsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import { contractVeCRV, contractCrv } from '@/dao/store/contracts'
import { abiVeCrv } from '@/dao/store/abis'
import { convertToLocaleTimestamp, formatDateFromTimestamp } from 'ui/src/utils'
import {
VeCrvFeeRes,
VeCrvFee,
VeCrvFeesRes,
VeCrvDailyLock,
VeCrvDailyLockRes,
VeCrvHolder,
Expand All @@ -19,12 +16,13 @@ import {
AllHoldersSortBy,
} from '@/dao/types/dao.types'
import type { ContractRunner } from 'ethers/lib.commonjs/providers'
import { type Distribution, getDistributions } from '@curvefi/prices-api/revenue'

type StateKey = keyof typeof DEFAULT_STATE

type SliceState = {
veCrvFees: {
fees: VeCrvFee[]
fees: Distribution[]
veCrvTotalFees: number
fetchStatus: FetchingState
}
Expand Down Expand Up @@ -124,31 +122,11 @@ const createAnalyticsSlice = (set: SetState<State>, get: GetState<State>): Analy
})

try {
let page = 1
const pagination = 100
let results: VeCrvFeeRes[] = []

while (true) {
const veCrvFeesRes = await fetch(
`https://prices.curve.fi/v1/dao/fees/distributions?page=${page}&per_page=${pagination}`,
)
const data: VeCrvFeesRes = await veCrvFeesRes.json()
results = results.concat(data.distributions)
if (data.distributions.length < pagination) {
break
}
page++
}

const feesFormatted: VeCrvFee[] = results.map((item) => ({
...item,
timestamp: convertToLocaleTimestamp(new Date(item.timestamp).getTime() / 1000),
date: formatDateFromTimestamp(convertToLocaleTimestamp(new Date(item.timestamp).getTime() / 1000)),
}))
const totalFees = feesFormatted.reduce((acc, item) => acc + item.fees_usd, 0)
const distributions = await getDistributions()
const totalFees = distributions.reduce((acc, item) => acc + item.feesUsd, 0)

get()[sliceKey].setStateByKey('veCrvFees', {
fees: feesFormatted,
fees: distributions,
veCrvTotalFees: totalFees,
fetchStatus: 'SUCCESS',
})
Expand Down
15 changes: 0 additions & 15 deletions apps/main/src/dao/types/dao.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,21 +333,6 @@ export type ActiveProposal = {
startTimestamp: number
endTimestamp: number
}
export type VeCrvFeeRes = {
fees_usd: number
timestamp: string
}
export type VeCrvFee = {
fees_usd: number
timestamp: number
date: string
}

export interface VeCrvFeesRes {
distributions: VeCrvFeeRes[]
page: number
count: number
}

export type VeCrvDailyLock = {
day: string
Expand Down
2 changes: 1 addition & 1 deletion packages/external-rewards/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const campaigns = campaignList
const dateFilteredCampaign = {
...parsedCampaignsJsons[campaignName],
pools: parsedCampaignsJsons[campaignName].pools.filter((pool: any) => {
const currentTime = new Date().getTime() / 1000
const currentTime = Date.now() / 1000

// allow campaigns with no set period
if (pool.campaignStart === '0' || pool.campaignEnd === '0') {
Expand Down
8 changes: 4 additions & 4 deletions packages/prices-api/src/lending/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getHost, type Options, type Chain, type Address } from '..'
import { fetchJson as fetch } from '../fetch'
import { getTimeRange } from '../timestamp'
import type * as Responses from './responses'
import * as Parsers from './parsers'

Expand Down Expand Up @@ -29,14 +30,13 @@ export async function getOracle(
) {
const host = getHost(options)

end ??= Math.floor(new Date().getTime() / 1000)
start ??= end - 10 * 24 * 60 * 60 // Subtract 1 month worth of seconds.
const range = getTimeRange({ start, end })

const params = new URLSearchParams({
agg_number: interval.toString(),
agg_units: units,
...(start && { start: start.toString() }),
...(end && { end: end.toString() }),
start: range.start.toString(),
end: range.end.toString(),
})

const resp = await fetch<Responses.GetOracleResponse>(
Expand Down
8 changes: 4 additions & 4 deletions packages/prices-api/src/llamma/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getHost, type Address, type Options, type Chain } from '..'
import { fetchJson as fetch } from '../fetch'
import { getTimeRange } from '../timestamp'
import type * as Responses from './responses'
import * as Parsers from './parsers'

Expand Down Expand Up @@ -77,14 +78,13 @@ export async function getOHLC(
) {
const host = getHost(options)

end ??= Math.floor(new Date().getTime() / 1000)
start ??= end - 10 * 24 * 60 * 60 // Subtract 1 month worth of seconds.
const range = getTimeRange({ start, end })

const params = new URLSearchParams({
agg_number: interval.toString(),
agg_units: units,
...(start && { start: start.toString() }),
...(end && { end: end.toString() }),
start: range.start.toString(),
end: range.end.toString(),
})

const resp = await fetch<Responses.GetLlammaOHLCResponse>(
Expand Down
5 changes: 2 additions & 3 deletions packages/prices-api/src/ohlc/api.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { getHost, type Options, type Chain } from '..'
import { fetchJson as fetch } from '../fetch'
import { getTimeRange } from '../timestamp'
import type * as Responses from './responses'
import * as Parsers from './parsers'

export async function getOHLC(chain: Chain, poolAddr: string, tokenMain: string, tokenRef: string, options?: Options) {
const host = getHost(options)

const range = 120 * 60 * 1000
const end = Math.floor(new Date().getTime() / 1000)
const start = Math.floor(end - range)
const { start, end } = getTimeRange({ daysRange: 90 })

const url =
`${host}/v1/ohlc` +
Expand Down
9 changes: 3 additions & 6 deletions packages/prices-api/src/pools/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getHost, type Options, type Chain } from '..'
import { fetchJson as fetch } from '../fetch'
import { getTimeRange } from '../timestamp'
import type * as Responses from './responses'
import * as Parsers from './parsers'

Expand All @@ -24,9 +25,7 @@ export async function getPool(chain: Chain, poolAddr: string, options?: Options)
export async function getVolume(chain: Chain, poolAddr: string, options?: Options) {
const host = getHost(options)

const range = 120 * 60 * 1000
const end = Math.floor(new Date().getTime() / 1000)
const start = Math.floor(end - range)
const { start, end } = getTimeRange({ daysRange: 90 })

const resp = await fetch<Responses.GetVolumeResponse>(
`${host}/v1/volume/usd/${chain}/${poolAddr}?` + `interval=day&` + `start=${start}&` + `end=${end}`,
Expand All @@ -38,9 +37,7 @@ export async function getVolume(chain: Chain, poolAddr: string, options?: Option
export async function getTvl(chain: Chain, poolAddr: string, options?: Options) {
const host = getHost(options)

const range = 120 * 60 * 1000
const end = Math.floor(new Date().getTime() / 1000)
const start = Math.floor(end - range)
const { start, end } = getTimeRange({ daysRange: 90 })

const resp = await fetch<Responses.GetTvlResponse>(
`${host}/v1/snapshots/${chain}/${poolAddr}/tvl?` + `interval=day&` + `start=${start}&` + `end=${end}`,
Expand Down
2 changes: 1 addition & 1 deletion packages/prices-api/src/proposal/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function getStatus(proposal: Proposal): ProposalStatus {
return 'executed'
}

if (proposal.end > new Date().getTime() / 1000) {
if (proposal.end > Date.now() / 1000) {
return 'active'
}

Expand Down
4 changes: 2 additions & 2 deletions packages/prices-api/src/savings/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getHost, type Options } from '..'
import { fetchJson as fetch } from '../fetch'
import { getTimeRange } from '../timestamp'
import type * as Responses from './responses'
import * as Parsers from './parsers'

Expand All @@ -23,8 +24,7 @@ export async function getEvents(page: number, options?: Options) {
export async function getYield(options?: Options) {
const host = getHost(options)

const end = Math.floor(new Date().getTime() / 1000)
const start = end - 10 * 24 * 60 * 60 // Subtract 1 month worth of seconds.
const { start, end } = getTimeRange({ daysRange: 10 })

const resp = await fetch<Responses.GetYieldResponse>(
`${host}/v1/crvusd/savings/yield?agg_number=1&agg_units=hour&start=${start}&end=${end}`,
Expand Down
28 changes: 28 additions & 0 deletions packages/prices-api/src/timestamp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,31 @@ export function toUTC(timestamp: string | number): Date {

return new Date(utcTimestamp)
}

const ONE_DAY_IN_SECONDS = 24 * 60 * 60

type TimeRangeParams = {
end?: number
start?: number
daysRange?: number
}

/**
* Get start and end unix timestamps for a time range for the prices API.
* @param params - Configuration object
* @returns Object with start and end timestamps
* @example
* getTimeRange() // {end: <now>, start: <now - 10 days>}
* getTimeRange({ end: 1704067200 }) // {end: 1704067200, start: 1703203200}
* getTimeRange({ end: 1704067200, start: 1703203200 }) // {end: 1704067200, start: 1703203200}
* getTimeRange({ daysRange: 30 }) // {end: <now>, start: <now - 30 days>}
*/
export function getTimeRange({ end, start, daysRange = 10 }: TimeRangeParams = {}) {
end ??= Math.floor(Date.now() / 1000)
start ??= end - daysRange * ONE_DAY_IN_SECONDS

return {
end,
start,
}
}