Skip to content

Commit 13e0151

Browse files
authored
Leaderboard on GraphQL
* checkpoint * compiles * looks like it works * fix * fix
1 parent 0694869 commit 13e0151

File tree

11 files changed

+410
-69
lines changed

11 files changed

+410
-69
lines changed

packages/api/schema.graphql

+12
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ type MarketType {
3838
vaultAddress: String!
3939
}
4040

41+
type PnLType {
42+
epochId: Int!
43+
openPositionsPnL: String!
44+
owner: String!
45+
positionCount: Int!
46+
positions: [Int!]!
47+
totalDeposits: String!
48+
totalPnL: String!
49+
totalWithdrawals: String!
50+
}
51+
4152
type PositionType {
4253
baseToken: String!
4354
borrowedBaseToken: String
@@ -59,6 +70,7 @@ type PositionType {
5970

6071
type Query {
6172
epochs(marketId: Int): [EpochType!]!
73+
getEpochLeaderboard(address: String!, chainId: Int!, epochId: String!): [PnLType!]!
6274
indexCandles(address: String!, chainId: Int!, epochId: String!, from: Int!, interval: Int!, to: Int!): [CandleType!]!
6375
indexPriceAtTime(address: String!, chainId: Int!, epochId: String!, timestamp: Int!): CandleType
6476
legacyMarketCandles(address: String!, chainId: Int!, epochId: String!, from: Int!, interval: Int!, to: Int!): [CandleType!]!
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Resolver, Query, Arg, Int } from 'type-graphql';
2+
import { PnLType } from '../types';
3+
import { PnLPerformance } from '../../performance';
4+
5+
@Resolver(() => PnLType)
6+
export class PnLResolver {
7+
@Query(() => [PnLType])
8+
async getEpochLeaderboard(
9+
@Arg('chainId', () => Int) chainId: number,
10+
@Arg('address', () => String) address: string,
11+
@Arg('epochId', () => String) epochId: string
12+
): Promise<PnLType[]> {
13+
try {
14+
const pnlPerformance = PnLPerformance.getInstance();
15+
const pnlData = await pnlPerformance.getEpochPnLs(
16+
chainId,
17+
address,
18+
parseInt(epochId)
19+
);
20+
21+
return pnlData.map((pnl) => {
22+
return {
23+
epochId: parseInt(epochId),
24+
owner: pnl.owner,
25+
totalDeposits: pnl.totalDeposits.toString(),
26+
totalWithdrawals: pnl.totalWithdrawals.toString(),
27+
openPositionsPnL: pnl.openPositionsPnL.toString(),
28+
totalPnL: pnl.totalPnL.toString(),
29+
positions: Array.from(pnl.positionIds),
30+
positionCount: pnl.positionCount,
31+
};
32+
});
33+
} catch (error) {
34+
console.error('Error fetching epochs:', error);
35+
throw new Error('Failed to fetch epochs');
36+
}
37+
}
38+
}

packages/api/src/graphql/resolvers/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export { PositionResolver } from './PositionResolver';
44
export { TransactionResolver } from './TransactionResolver';
55
export { EpochResolver } from './EpochResolver';
66
export { CandleResolver } from './CandleResolver';
7+
export { PnLResolver } from './PnLResolver';

packages/api/src/graphql/startApolloServer.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ResourceResolver,
1010
TransactionResolver,
1111
CandleResolver,
12+
PnLResolver,
1213
} from './resolvers';
1314

1415
export const initializeApolloServer = async () => {
@@ -21,6 +22,7 @@ export const initializeApolloServer = async () => {
2122
TransactionResolver,
2223
EpochResolver,
2324
CandleResolver,
25+
PnLResolver,
2426
],
2527
emitSchemaFile: true,
2628
validate: false,
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Field, ObjectType, Int, Directive } from 'type-graphql';
2+
3+
@Directive('@cacheControl(maxAge: 3)')
4+
@ObjectType()
5+
export class PnLType {
6+
@Field(() => Int)
7+
epochId: number;
8+
9+
@Field(() => String)
10+
owner: string;
11+
12+
@Field(() => String)
13+
totalDeposits: string;
14+
15+
@Field(() => String)
16+
totalWithdrawals: string;
17+
18+
@Field(() => String)
19+
openPositionsPnL: string;
20+
21+
@Field(() => String)
22+
totalPnL: string;
23+
24+
@Field(() => [Int])
25+
positions: number[];
26+
27+
@Field(() => Int)
28+
positionCount: number;
29+
}

packages/api/src/graphql/types/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { TransactionType } from './TransactionType';
55
export { EpochType } from './EpochType';
66
export { ResourcePriceType } from './ResourcePriceType';
77
export { CandleType } from './CandleType';
8+
export { PnLType } from './PnLType';
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { PublicClient } from 'viem';
2+
3+
export const calculateOpenPositionValue = async (
4+
positionId: number,
5+
marketAddress: string,
6+
client: PublicClient
7+
): Promise<bigint> => {
8+
const collateralValue = await client.readContract({
9+
address: marketAddress as `0x${string}`,
10+
abi: [
11+
{
12+
type: 'function',
13+
name: 'getPositionCollateralValue',
14+
inputs: [
15+
{
16+
name: 'positionId',
17+
type: 'uint256',
18+
internalType: 'uint256',
19+
},
20+
],
21+
outputs: [
22+
{
23+
name: 'collateralValue',
24+
type: 'uint256',
25+
internalType: 'uint256',
26+
},
27+
],
28+
stateMutability: 'view',
29+
},
30+
{
31+
inputs: [
32+
{
33+
internalType: 'uint256',
34+
name: 'positionId',
35+
type: 'uint256',
36+
},
37+
],
38+
type: 'error',
39+
name: 'InvalidPositionId',
40+
},
41+
],
42+
functionName: 'getPositionCollateralValue',
43+
args: [BigInt(positionId)],
44+
});
45+
46+
return collateralValue;
47+
};

packages/api/src/performance/helper.ts

+21
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,24 @@ export function maxBigInt(a: bigint, b: bigint) {
148148
export function minBigInt(a: bigint, b: bigint) {
149149
return a < b ? a : b;
150150
}
151+
152+
export function startOfCurrentInterval(
153+
timestamp: number,
154+
interval: number
155+
): number {
156+
return Math.floor(timestamp / interval) * interval;
157+
}
158+
159+
export function startOfNextInterval(
160+
timestamp: number,
161+
interval: number
162+
): number {
163+
return (Math.floor(timestamp / interval) + 1) * interval;
164+
}
165+
166+
export function getTimeWindow(from: number, to: number, interval: number) {
167+
return {
168+
from: startOfCurrentInterval(from, interval),
169+
to: startOfNextInterval(to, interval),
170+
};
171+
}

packages/api/src/performance/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './resourcePerformance';
22
export * from './resourcePerformanceManager';
3+
export * from './pnlPerformance';

0 commit comments

Comments
 (0)