Skip to content
5 changes: 5 additions & 0 deletions .changeset/public-moments-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@venusprotocol/evm": minor
---

Added Stats page - Overview tab
11 changes: 11 additions & 0 deletions apps/evm/src/clients/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,14 @@ export * from './queries/getRawTradePositions/useGetRawTradePositions';

export * from './queries/getTradeReduceSwapQuotes';
export * from './queries/getTradeReduceSwapQuotes/useGetTradeReduceSwapQuotes';

export * from './queries/getRiskDashboardMarketAggregates';
export * from './queries/getRiskDashboardMarketAggregates/useGetRiskDashboardMarketAggregates';
export * from './queries/getRiskDashboardMarketSnapshots';
export * from './queries/getRiskDashboardMarketSnapshots/useGetRiskDashboardMarketSnapshots';
export * from './queries/getRiskDashboardWalletAggregates';
export * from './queries/getRiskDashboardWalletAggregates/useGetRiskDashboardWalletAggregates';
export * from './queries/getRiskDashboardTopWallets';
export * from './queries/getRiskDashboardTopWallets/useGetRiskDashboardTopWallets';
export * from './queries/getRiskDashboardTransactionsVolume';
export * from './queries/getRiskDashboardTransactionsVolume/useGetRiskDashboardTransactionsVolume';
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { VError } from 'libs/errors';
import type { ChainId } from 'types';
import { restService } from 'utilities';

export interface ApiRiskDashboardAsOf {
blockNumber: string;
blockTimestamp: string;
}

export interface GetRiskDashboardMarketAggregatesInput {
chainId: ChainId;
}

export interface GetRiskDashboardMarketAggregatesResponse {
chainId: string;
asOf: ApiRiskDashboardAsOf;
totalSupplyUsdCents: string;
totalBorrowsUsdCents: string;
liquidityUsdCents: string;
utilization: number;
}

export async function getRiskDashboardMarketAggregates({
chainId,
}: GetRiskDashboardMarketAggregatesInput) {
const response = await restService<GetRiskDashboardMarketAggregatesResponse>({
endpoint: '/risk-dashboard/market-aggregates',
method: 'GET',
params: { chainId },
});

const payload = response.data;

if (payload && 'error' in payload) {
throw new VError({
type: 'unexpected',
code: 'somethingWentWrong',
data: { exception: payload.error },
});
}

if (!payload) {
throw new VError({ type: 'unexpected', code: 'somethingWentWrong' });
}

return payload;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { type QueryObserverOptions, useQuery } from '@tanstack/react-query';

import FunctionKey from 'constants/functionKey';
import { useChainId } from 'libs/wallet';
import type { ChainId } from 'types';
import { type GetRiskDashboardMarketAggregatesResponse, getRiskDashboardMarketAggregates } from '.';

export type UseGetRiskDashboardMarketAggregatesQueryKey = [
FunctionKey.GET_RISK_DASHBOARD_MARKET_AGGREGATES,
{ chainId: ChainId },
];

type Options = QueryObserverOptions<
GetRiskDashboardMarketAggregatesResponse,
Error,
GetRiskDashboardMarketAggregatesResponse,
GetRiskDashboardMarketAggregatesResponse,
UseGetRiskDashboardMarketAggregatesQueryKey
>;

export const useGetRiskDashboardMarketAggregates = (options?: Partial<Options>) => {
const { chainId } = useChainId();

return useQuery({
queryKey: [FunctionKey.GET_RISK_DASHBOARD_MARKET_AGGREGATES, { chainId }],
queryFn: () => getRiskDashboardMarketAggregates({ chainId }),
...options,
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { VError } from 'libs/errors';
import type { ChainId } from 'types';
import { restService } from 'utilities';

export type RiskDashboardMarketSnapshotKind = 'day' | 'week' | 'month' | 'year';

export interface ApiRiskDashboardMarketSnapshotPoint {
marketAddress: string;
supplyUsdCents: string;
borrowsUsdCents: string;
}

export interface ApiRiskDashboardMarketSnapshotSlot {
blockNumber: string;
blockTimestamp: string;
totalSupplyUsdCents: string;
totalBorrowsUsdCents: string;
byMarket: ApiRiskDashboardMarketSnapshotPoint[];
}

export interface GetRiskDashboardMarketSnapshotsInput {
chainId: ChainId;
kind: RiskDashboardMarketSnapshotKind;
}

export interface GetRiskDashboardMarketSnapshotsResponse {
chainId: string;
kind: RiskDashboardMarketSnapshotKind;
series: ApiRiskDashboardMarketSnapshotSlot[];
}

export async function getRiskDashboardMarketSnapshots({
chainId,
kind,
}: GetRiskDashboardMarketSnapshotsInput) {
const response = await restService<GetRiskDashboardMarketSnapshotsResponse>({
endpoint: '/risk-dashboard/market-snapshots',
method: 'GET',
params: { chainId, kind },
});

const payload = response.data;

if (payload && 'error' in payload) {
throw new VError({
type: 'unexpected',
code: 'somethingWentWrong',
data: { exception: payload.error },
});
}

if (!payload) {
throw new VError({ type: 'unexpected', code: 'somethingWentWrong' });
}

return payload;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { type QueryObserverOptions, useQuery } from '@tanstack/react-query';

import FunctionKey from 'constants/functionKey';
import { useChainId } from 'libs/wallet';
import type { ChainId } from 'types';
import {
type GetRiskDashboardMarketSnapshotsResponse,
type RiskDashboardMarketSnapshotKind,
getRiskDashboardMarketSnapshots,
} from '.';

export type UseGetRiskDashboardMarketSnapshotsQueryKey = [
FunctionKey.GET_RISK_DASHBOARD_MARKET_SNAPSHOTS,
{ chainId: ChainId; kind: RiskDashboardMarketSnapshotKind },
];

type Options = QueryObserverOptions<
GetRiskDashboardMarketSnapshotsResponse,
Error,
GetRiskDashboardMarketSnapshotsResponse,
GetRiskDashboardMarketSnapshotsResponse,
UseGetRiskDashboardMarketSnapshotsQueryKey
>;

export const useGetRiskDashboardMarketSnapshots = (
{ kind }: { kind: RiskDashboardMarketSnapshotKind },
options?: Partial<Options>,
) => {
const { chainId } = useChainId();

return useQuery({
queryKey: [FunctionKey.GET_RISK_DASHBOARD_MARKET_SNAPSHOTS, { chainId, kind }],
queryFn: () => getRiskDashboardMarketSnapshots({ chainId, kind }),
...options,
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { VError } from 'libs/errors';
import type { ChainId } from 'types';
import { restService } from 'utilities';
import type { ApiRiskDashboardAsOf } from '../getRiskDashboardMarketAggregates';

export type RiskDashboardTopWalletsKind = 'suppliers' | 'borrowers';

export interface ApiRiskDashboardTopWalletPosition {
marketAddress: string;
supplyUsdCents: string;
borrowUsdCents: string;
isCollateral: boolean;
}

export interface ApiRiskDashboardTopWallet {
address: string;
totalSupplyUsdCents: string;
totalBorrowUsdCents: string;
healthFactorMantissa: string;
positions: ApiRiskDashboardTopWalletPosition[];
}

export interface GetRiskDashboardTopWalletsInput {
chainId: ChainId;
kind: RiskDashboardTopWalletsKind;
limit?: number;
}

export interface GetRiskDashboardTopWalletsResponse {
chainId: string;
kind: RiskDashboardTopWalletsKind;
asOf: ApiRiskDashboardAsOf | null;
wallets: ApiRiskDashboardTopWallet[];
}

export async function getRiskDashboardTopWallets({
chainId,
kind,
limit,
}: GetRiskDashboardTopWalletsInput) {
const response = await restService<GetRiskDashboardTopWalletsResponse>({
endpoint: '/risk-dashboard/top-wallets',
method: 'GET',
params: { chainId, kind, limit },
});

const payload = response.data;

if (payload && 'error' in payload) {
throw new VError({
type: 'unexpected',
code: 'somethingWentWrong',
data: { exception: payload.error },
});
}

if (!payload) {
throw new VError({ type: 'unexpected', code: 'somethingWentWrong' });
}

return payload;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { type QueryObserverOptions, useQuery } from '@tanstack/react-query';

import FunctionKey from 'constants/functionKey';
import { useChainId } from 'libs/wallet';
import type { ChainId } from 'types';
import {
type GetRiskDashboardTopWalletsResponse,
type RiskDashboardTopWalletsKind,
getRiskDashboardTopWallets,
} from '.';

export interface UseGetRiskDashboardTopWalletsInput {
kind: RiskDashboardTopWalletsKind;
limit?: number;
}

export type UseGetRiskDashboardTopWalletsQueryKey = [
FunctionKey.GET_RISK_DASHBOARD_TOP_WALLETS,
{ chainId: ChainId; kind: RiskDashboardTopWalletsKind; limit?: number },
];

type Options = QueryObserverOptions<
GetRiskDashboardTopWalletsResponse,
Error,
GetRiskDashboardTopWalletsResponse,
GetRiskDashboardTopWalletsResponse,
UseGetRiskDashboardTopWalletsQueryKey
>;

export const useGetRiskDashboardTopWallets = (
{ kind, limit }: UseGetRiskDashboardTopWalletsInput,
options?: Partial<Options>,
) => {
const { chainId } = useChainId();

return useQuery({
queryKey: [FunctionKey.GET_RISK_DASHBOARD_TOP_WALLETS, { chainId, kind, limit }],
queryFn: () => getRiskDashboardTopWallets({ chainId, kind, limit }),
...options,
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { VError } from 'libs/errors';
import type { ChainId } from 'types';
import { restService } from 'utilities';

export interface ApiRiskDashboardTransactionsVolumeMarketBreakdown {
marketAddress: string;
mintUsdCents: string;
redeemUsdCents: string;
borrowUsdCents: string;
repayUsdCents: string;
liquidateUsdCents: string;
totalUsdCents: string;
}

export interface ApiRiskDashboardTransactionsVolumeDay {
day: string;
mintUsdCents: string;
redeemUsdCents: string;
borrowUsdCents: string;
repayUsdCents: string;
liquidateUsdCents: string;
totalUsdCents: string;
byMarket: ApiRiskDashboardTransactionsVolumeMarketBreakdown[];
}

export interface GetRiskDashboardTransactionsVolumeInput {
chainId: ChainId;
days?: number;
}

export interface GetRiskDashboardTransactionsVolumeResponse {
chainId: string;
days: number;
totalUsdCents: string;
series: ApiRiskDashboardTransactionsVolumeDay[];
}

export async function getRiskDashboardTransactionsVolume({
chainId,
days,
}: GetRiskDashboardTransactionsVolumeInput) {
const response = await restService<GetRiskDashboardTransactionsVolumeResponse>({
endpoint: '/risk-dashboard/transactions-volume',
method: 'GET',
params: { chainId, days },
});

const payload = response.data;

if (payload && 'error' in payload) {
throw new VError({
type: 'unexpected',
code: 'somethingWentWrong',
data: { exception: payload.error },
});
}

if (!payload) {
throw new VError({ type: 'unexpected', code: 'somethingWentWrong' });
}

return payload;
}
Loading
Loading