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

feat: add prices api #630

Merged
merged 13 commits into from
Jan 28, 2025
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ This repository is organized as follows:
- `/apps/lend`: Lend [React](https://react.dev/) application.
- `/tests`: DApp tests
- `/packages/curve-ui-kit`: Shared UI kit created using Material UI, mapped as `@ui-kit`
- `/packages/prices-api`: Package for consuming the Prices API, mapped as `@curvefi/prices-api`
0xAlunara marked this conversation as resolved.
Show resolved Hide resolved

## Development Guide

Expand Down
53 changes: 0 additions & 53 deletions apps/main/src/loan/entities/crvusd.ts

This file was deleted.

3 changes: 2 additions & 1 deletion apps/main/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"@ui": ["../../../packages/ui/src/index.ts"],
"@ui/*": ["../../../packages/ui/src/*"],
"@ui-kit/*": ["../../../packages/curve-ui-kit/src/*"],
"@external-rewards": ["../../../packages/external-rewards/src/index.ts"]
"@external-rewards": ["../../../packages/external-rewards/src/index.ts"],
"@curvefi/prices-api/*": ["../../../packages/prices-api/src/*"]
0xAlunara marked this conversation as resolved.
Show resolved Hide resolved
}
},
"exclude": ["node_modules", "cypress"],
Expand Down
21 changes: 21 additions & 0 deletions packages/prices-api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@curvefi/prices-api",
"version": "1.0.0",
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "MIT",
"private": true,
"scripts": {
"lint": "eslint \"**/*.ts*\"",
"typecheck": "tsc --noEmit"
},
"peerDependencies": {
"typescript": "*"
},
"devDependencies": {
0xAlunara marked this conversation as resolved.
Show resolved Hide resolved
"eslint": "*",
"eslint-config-custom": "*",
"typescript": "*"
}
}
32 changes: 32 additions & 0 deletions packages/prices-api/src/chains/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getHost, type Options, type Chain } from '..'
import { fetchJson as fetch } from '../fetch'
import type * as Responses from './responses'
import * as Parsers from './parsers'

export async function getSupportedChains(options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetSupportedChainsResponse>(`${host}/v1/chains/`)

return Parsers.parseSupportedChains(resp)
}

export async function getChainInfo(chain: Chain, options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetChainInfoResponse>(`${host}/v1/chains/${chain}?page=1&per_page=1`)

return Parsers.parseChainInfo(resp)
}

export async function getTxs(options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetTransactionsResponse>(`${host}/v1/chains/activity/transactions`)

return Parsers.parseTxs(resp)
}

export async function getUsers(options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetUsersResponse>(`${host}/v1/chains/activity/users`)

return Parsers.parseUsers(resp)
}
2 changes: 2 additions & 0 deletions packages/prices-api/src/chains/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './models'
export * from './api'
29 changes: 29 additions & 0 deletions packages/prices-api/src/chains/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Chain } from '..'

export type ChainInfo = {
chain: string
total: {
tvl: number
tradingVolume24h: number
tradingFee24h: number
liquidityVolume24h: number
liquidityFee24h: number
}
}

export const activityTypes = ['crvusd', 'lending', 'pools', 'router', 'dao'] as const
export type ActivityType = (typeof activityTypes)[number]

export type Activity = {
timestamp: number
chain: Chain
type: ActivityType
}

export type Transactions = Activity & {
transactions: number
}

export type Users = Activity & {
users: number
}
38 changes: 38 additions & 0 deletions packages/prices-api/src/chains/parsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { chains, type Chain } from '..'
import { toUTC } from '../timestamp'
import type * as Responses from './responses'
import type * as Models from './models'

export const parseSupportedChains = (x: Responses.GetSupportedChainsResponse): Chain[] =>
x.data.map((y) => y.name as Chain).filter((y) => chains.includes(y))

export const parseChainInfo = (x: Responses.GetChainInfoResponse): Models.ChainInfo => ({
chain: x.chain,
total: {
tvl: x.total.total_tvl,
tradingVolume24h: x.total.trading_volume_24h,
tradingFee24h: x.total.trading_fee_24h,
liquidityVolume24h: x.total.liquidity_volume_24h,
liquidityFee24h: x.total.liquidity_fee_24h,
},
})

export const parseTxs = (x: Responses.GetTransactionsResponse): Models.Transactions[] =>
x.data.flatMap((data) =>
data.transactions.map((tx) => ({
chain: data.chain,
timestamp: toUTC(tx.timestamp),
type: tx.type,
transactions: tx.transactions,
})),
)

export const parseUsers = (x: Responses.GetUsersResponse): Models.Users[] =>
x.data.flatMap((data) =>
data.users.map((tx) => ({
chain: data.chain,
timestamp: toUTC(tx.timestamp),
type: tx.type,
users: tx.users,
})),
)
39 changes: 39 additions & 0 deletions packages/prices-api/src/chains/responses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Chain } from '..'
import type { ActivityType } from './models'

export type GetSupportedChainsResponse = {
data: { name: string }[]
}

export type GetChainInfoResponse = {
chain: Chain
total: {
total_tvl: number
trading_volume_24h: number
trading_fee_24h: number
liquidity_volume_24h: number
liquidity_fee_24h: number
}
}

export type GetTransactionsResponse = {
data: {
chain: Chain
transactions: {
type: ActivityType
transactions: number
timestamp: string
}[]
}[]
}

export type GetUsersResponse = {
data: {
chain: Chain
users: {
type: ActivityType
users: number
timestamp: string
}[]
}[]
}
82 changes: 82 additions & 0 deletions packages/prices-api/src/crvusd/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { getHost, type Options, type Chain } from '..'
import { fetchJson as fetch } from '../fetch'
import type * as Responses from './responses'
import * as Parsers from './parsers'

export async function getMarkets(chain: Chain, page: number, options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetMarketsResponse>(
`${host}/v1/crvusd/markets/${chain}?fetch_on_chain=true&page=${page}&per_page=10`,
)

return resp.data.map(Parsers.parseMarket)
}

export async function getSnapshots(chain: Chain, marketAddr: string, options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetSnapshotsResponse>(
`${host}/v1/crvusd/markets/${chain}/${marketAddr}/snapshots?fetch_on_chain=true&agg=day`,
)

return resp.data.map(Parsers.parseSnapshot)
}

export async function getCrvUsdSupply(chain: Chain, options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetSupplyResponse>(`${host}/v1/crvusd/markets/${chain}/supply`)

return resp.data.map(Parsers.parseSupply)
}

export async function getKeepers(chain: Chain, options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetKeepersResponse>(`${host}/v1/crvusd/pegkeepers/${chain}`)

return resp.keepers.map(Parsers.parseKeeper)
}

export async function getUserMarkets(userAddr: string, chain: Chain, options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetUserMarketsResponse>(
`${host}/v1/crvusd/users/${chain}/${userAddr}?page=1&per_page=100`,
)

return Parsers.parseUserMarkets(resp)
}

export async function getUserMarketStats(userAddr: string, chain: Chain, marketController: string, options?: Options) {
const host = await getHost(options)
const resp = await fetch<Responses.GetUserMarketStatsResponse>(
`${host}/v1/crvusd/users/${chain}/${userAddr}/${marketController}/stats?page=1&per_page=100`,
)

return Parsers.parseUserMarketStats(resp)
}

export async function getUserMarketSnapshots(
userAddr: string,
chain: Chain,
marketController: string,
options?: Options,
) {
const host = await getHost(options)
const resp = await fetch<Responses.GetUserMarketSnapshotsResponse>(
`${host}/v1/crvusd/users/${chain}/${userAddr}/${marketController}/snapshots?page=1&per_page=100`,
)

return Parsers.parseUserMarketSnapshots(resp)
}

export async function getUserMarketCollateralEvents(
userAddr: string,
chain: Chain,
marketController: string,
options?: Options,
) {
const host = await getHost(options)
const resp = await fetch<Responses.GetUserCollateralEventsResponse>(
`${host}/v1/crvusd/collateral_events/${chain}/${marketController}/${userAddr}`,
)

return Parsers.parseUserCollateralEvents(resp)
}
2 changes: 2 additions & 0 deletions packages/prices-api/src/crvusd/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './models'
export * from './api'
Loading
Loading