From f102d8d3d99d648cdd2ea46751d58c9846c82358 Mon Sep 17 00:00:00 2001 From: Vincent Chau <99756290+vincentwschau@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:55:04 -0400 Subject: [PATCH 1/2] [TRA-571] Add resolution argument to vault PnL endpoint. --- .../api/v4/vault-controller.test.ts | 285 +++++++++--------- .../comlink/public/api-documentation.md | 51 ++++ indexer/services/comlink/public/swagger.json | 29 +- indexer/services/comlink/src/config.ts | 3 + .../controllers/api/v4/vault-controller.ts | 85 ++++-- indexer/services/comlink/src/types.ts | 7 + 6 files changed, 297 insertions(+), 163 deletions(-) diff --git a/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts b/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts index e75deb31ff..50daa133ae 100644 --- a/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts +++ b/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts @@ -2,7 +2,6 @@ import { dbHelpers, testConstants, testMocks, - PnlTicksCreateObject, PnlTicksTable, perpetualMarketRefresher, BlockTable, @@ -12,16 +11,23 @@ import { PerpetualPositionTable, AssetPositionTable, FundingIndexUpdatesTable, + PnlTicksFromDatabase, } from '@dydxprotocol-indexer/postgres'; -import { PnlTicksResponseObject, RequestMethod, VaultHistoricalPnl } from '../../../../src/types'; +import { RequestMethod, VaultHistoricalPnl } from '../../../../src/types'; import request from 'supertest'; import { getFixedRepresentation, sendRequest } from '../../../helpers/helpers'; import config from '../../../../src/config'; +import { DateTime } from 'luxon'; describe('vault-controller#V4', () => { const experimentVaultsPrevVal: string = config.EXPERIMENT_VAULTS; const experimentVaultMarketsPrevVal: string = config.EXPERIMENT_VAULT_MARKETS; - const blockHeight: string = '3'; + const currentBlockHeight: string = '7'; + const twoHourBlockHeight: string = '5'; + const twoDayBlockHeight: string = '3'; + const currentTime: DateTime = DateTime.utc(); + const twoHoursAgo: DateTime = currentTime.minus({ hour: 2 }); + const twoDaysAgo: DateTime = currentTime.minus({ day: 2 }); const initialFundingIndex: string = '10000'; beforeAll(async () => { @@ -39,10 +45,23 @@ describe('vault-controller#V4', () => { await testMocks.seedData(); await perpetualMarketRefresher.updatePerpetualMarkets(); await liquidityTierRefresher.updateLiquidityTiers(); - await BlockTable.create({ - ...testConstants.defaultBlock, - blockHeight, - }); + await Promise.all([ + BlockTable.create({ + ...testConstants.defaultBlock, + time: twoDaysAgo.toISO(), + blockHeight: twoDayBlockHeight, + }), + BlockTable.create({ + ...testConstants.defaultBlock, + time: twoHoursAgo.toISO(), + blockHeight: twoHourBlockHeight, + }), + BlockTable.create({ + ...testConstants.defaultBlock, + time: currentTime.toISO(), + blockHeight: currentBlockHeight, + }), + ]); await SubaccountTable.create(testConstants.vaultSubaccount); }); @@ -64,54 +83,40 @@ describe('vault-controller#V4', () => { expect(response.body.megavaultPnl).toEqual([]); }); - it('Get /megavault/historicalPnl with single vault subaccount', async () => { - const createdAt: string = '2000-05-25T00:00:00.000Z'; - const pnlTick2: PnlTicksCreateObject = { - ...testConstants.defaultPnlTick, - createdAt, - blockHeight, - }; - await Promise.all([ - PnlTicksTable.create(testConstants.defaultPnlTick), - PnlTicksTable.create(pnlTick2), - ]); + it.each([ + ['no resolution', '', [1, 2]], + ['daily resolution', '?resolution=day', [1, 2]], + ['hourly resolution', '?resolution=hour', [1, 2, 3]], + ])('Get /megavault/historicalPnl with single vault subaccount (%s)', async ( + _name: string, + queryParam: string, + expectedTicksIndex: number[], + ) => { + const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const response: request.Response = await sendRequest({ type: RequestMethod.GET, - path: '/v4/vault/v1/megavault/historicalPnl', + path: `/v4/vault/v1/megavault/historicalPnl${queryParam}`, }); - const expectedPnlTickResponse: PnlTicksResponseObject = { - ...testConstants.defaultPnlTick, - id: PnlTicksTable.uuid( - testConstants.defaultPnlTick.subaccountId, - testConstants.defaultPnlTick.createdAt, - ), - }; - - const expectedPnlTick2Response: any = { - ...testConstants.defaultPnlTick, - createdAt, - blockHeight, - id: PnlTicksTable.uuid( - testConstants.defaultPnlTick.subaccountId, - createdAt, - ), - }; - expect(response.body.megavaultPnl).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - ...expectedPnlTick2Response, - }), - expect.objectContaining({ - ...expectedPnlTickResponse, + expect.arrayContaining( + expectedTicksIndex.map((index: number) => { + return expect.objectContaining(createdPnlTicks[index]); }), - ]), + ), ); }); - it('Get /megavault/historicalPnl with 2 vault subaccounts', async () => { + it.each([ + ['no resolution', '', [1, 2]], + ['daily resolution', '?resolution=day', [1, 2]], + ['hourly resolution', '?resolution=hour', [1, 2, 3]], + ])('Get /megavault/historicalPnl with 2 vault subaccounts (%s)', async ( + _name: string, + queryParam: string, + expectedTicksIndex: number[], + ) => { config.EXPERIMENT_VAULTS = [ testConstants.defaultPnlTick.subaccountId, testConstants.vaultSubaccountId, @@ -121,39 +126,30 @@ describe('vault-controller#V4', () => { testConstants.defaultPerpetualMarket2.clobPairId, ].join(','); - const pnlTick2: PnlTicksCreateObject = { - ...testConstants.defaultPnlTick, - subaccountId: testConstants.vaultSubaccountId, - }; - await Promise.all([ - PnlTicksTable.create(testConstants.defaultPnlTick), - PnlTicksTable.create(pnlTick2), - ]); + const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const response: request.Response = await sendRequest({ type: RequestMethod.GET, - path: '/v4/vault/v1/megavault/historicalPnl', + path: `/v4/vault/v1/megavault/historicalPnl${queryParam}`, }); - const expectedPnlTickResponse: any = { - // id and subaccountId don't matter - equity: (parseFloat(testConstants.defaultPnlTick.equity) + - parseFloat(pnlTick2.equity)).toString(), - totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) + - parseFloat(pnlTick2.totalPnl)).toString(), - netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) + - parseFloat(pnlTick2.netTransfers)).toString(), - createdAt: testConstants.defaultPnlTick.createdAt, - blockHeight: testConstants.defaultPnlTick.blockHeight, - blockTime: testConstants.defaultPnlTick.blockTime, + const expectedPnlTickBase: any = { + equity: (parseFloat(testConstants.defaultPnlTick.equity) * 2).toString(), + totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 2).toString(), + netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 2).toString(), }; expect(response.body.megavaultPnl).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - ...expectedPnlTickResponse, + expect.arrayContaining( + expectedTicksIndex.map((index: number) => { + return expect.objectContaining({ + ...expectedPnlTickBase, + createdAt: createdPnlTicks[index].createdAt, + blockHeight: createdPnlTicks[index].blockHeight, + blockTime: createdPnlTicks[index].blockTime, + }); }), - ]), + ), ); }); @@ -169,57 +165,44 @@ describe('vault-controller#V4', () => { expect(response.body.vaultsPnl).toEqual([]); }); - it('Get /vaults/historicalPnl with single vault subaccount', async () => { - const createdAt: string = '2000-05-25T00:00:00.000Z'; - const pnlTick2: PnlTicksCreateObject = { - ...testConstants.defaultPnlTick, - createdAt, - blockHeight, - }; - await Promise.all([ - PnlTicksTable.create(testConstants.defaultPnlTick), - PnlTicksTable.create(pnlTick2), - ]); + it.each([ + ['no resolution', '', [1, 2]], + ['daily resolution', '?resolution=day', [1, 2]], + ['hourly resolution', '?resolution=hour', [1, 2, 3]], + ])('Get /vaults/historicalPnl with single vault subaccount (%s)', async ( + _name: string, + queryParam: string, + expectedTicksIndex: number[], + ) => { + const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const response: request.Response = await sendRequest({ type: RequestMethod.GET, - path: '/v4/vault/v1/vaults/historicalPnl', + path: `/v4/vault/v1/vaults/historicalPnl${queryParam}`, }); - const expectedPnlTickResponse: PnlTicksResponseObject = { - ...testConstants.defaultPnlTick, - id: PnlTicksTable.uuid( - testConstants.defaultPnlTick.subaccountId, - testConstants.defaultPnlTick.createdAt, - ), - }; - - const expectedPnlTick2Response: any = { - ...testConstants.defaultPnlTick, - createdAt, - blockHeight, - id: PnlTicksTable.uuid( - testConstants.defaultPnlTick.subaccountId, - createdAt, - ), - }; - expect(response.body.vaultsPnl).toHaveLength(1); expect(response.body.vaultsPnl[0]).toEqual({ ticker: testConstants.defaultPerpetualMarket.ticker, - historicalPnl: expect.arrayContaining([ - expect.objectContaining({ - ...expectedPnlTick2Response, - }), - expect.objectContaining({ - ...expectedPnlTickResponse, + historicalPnl: expect.arrayContaining( + expectedTicksIndex.map((index: number) => { + return expect.objectContaining(createdPnlTicks[index]); }), - ]), + ), }); }); - it('Get /vaults/historicalPnl with 2 vault subaccounts', async () => { + it.each([ + ['no resolution', '', [1, 2], [5, 6]], + ['daily resolution', '?resolution=day', [1, 2], [5, 6]], + ['hourly resolution', '?resolution=hour', [1, 2, 3], [5, 6, 7]], + ])('Get /vaults/historicalPnl with 2 vault subaccounts (%s)', async ( + _name: string, + queryParam: string, + expectedTicksIndex1: number[], + expectedTicksIndex2: number[], + ) => { config.EXPERIMENT_VAULTS = [ testConstants.defaultPnlTick.subaccountId, testConstants.vaultSubaccountId, @@ -229,44 +212,25 @@ describe('vault-controller#V4', () => { testConstants.defaultPerpetualMarket2.clobPairId, ].join(','); - const pnlTick2: PnlTicksCreateObject = { - ...testConstants.defaultPnlTick, - subaccountId: testConstants.vaultSubaccountId, - }; - await Promise.all([ - PnlTicksTable.create(testConstants.defaultPnlTick), - PnlTicksTable.create(pnlTick2), - ]); + const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(); const response: request.Response = await sendRequest({ type: RequestMethod.GET, - path: '/v4/vault/v1/vaults/historicalPnl', + path: `/v4/vault/v1/vaults/historicalPnl${queryParam}`, }); const expectedVaultPnl: VaultHistoricalPnl = { ticker: testConstants.defaultPerpetualMarket.ticker, - historicalPnl: [ - { - ...testConstants.defaultPnlTick, - id: PnlTicksTable.uuid( - testConstants.defaultPnlTick.subaccountId, - testConstants.defaultPnlTick.createdAt, - ), - }, - ], + historicalPnl: expectedTicksIndex1.map((index: number) => { + return createdPnlTicks[index]; + }), }; const expectedVaultPnl2: VaultHistoricalPnl = { ticker: testConstants.defaultPerpetualMarket2.ticker, - historicalPnl: [ - { - ...pnlTick2, - id: PnlTicksTable.uuid( - pnlTick2.subaccountId, - pnlTick2.createdAt, - ), - }, - ], + historicalPnl: expectedTicksIndex2.map((index: number) => { + return createdPnlTicks[index]; + }), }; expect(response.body.vaultsPnl).toEqual( @@ -309,7 +273,7 @@ describe('vault-controller#V4', () => { FundingIndexUpdatesTable.create({ ...testConstants.defaultFundingIndexUpdate, eventId: testConstants.defaultTendermintEventId2, - effectiveAtHeight: blockHeight, + effectiveAtHeight: twoDayBlockHeight, }), ]); @@ -387,7 +351,7 @@ describe('vault-controller#V4', () => { FundingIndexUpdatesTable.create({ ...testConstants.defaultFundingIndexUpdate, eventId: testConstants.defaultTendermintEventId2, - effectiveAtHeight: blockHeight, + effectiveAtHeight: twoDayBlockHeight, }), ]); @@ -446,4 +410,53 @@ describe('vault-controller#V4', () => { }); }); }); + + async function createPnlTicks(): Promise { + return Promise.all([ + PnlTicksTable.create(testConstants.defaultPnlTick), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + blockTime: twoDaysAgo.toISO(), + createdAt: twoDaysAgo.toISO(), + blockHeight: twoDayBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + blockTime: twoHoursAgo.toISO(), + createdAt: twoHoursAgo.toISO(), + blockHeight: twoHourBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + blockTime: currentTime.toISO(), + createdAt: currentTime.toISO(), + blockHeight: currentBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: testConstants.vaultSubaccountId, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: testConstants.vaultSubaccountId, + blockTime: twoDaysAgo.toISO(), + createdAt: twoDaysAgo.toISO(), + blockHeight: twoDayBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: testConstants.vaultSubaccountId, + blockTime: twoHoursAgo.toISO(), + createdAt: twoHoursAgo.toISO(), + blockHeight: twoHourBlockHeight, + }), + PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + subaccountId: testConstants.vaultSubaccountId, + blockTime: currentTime.toISO(), + createdAt: currentTime.toISO(), + blockHeight: currentBlockHeight, + }), + ]); + } }); diff --git a/indexer/services/comlink/public/api-documentation.md b/indexer/services/comlink/public/api-documentation.md index 0439c0e85f..6dda7eef95 100644 --- a/indexer/services/comlink/public/api-documentation.md +++ b/indexer/services/comlink/public/api-documentation.md @@ -3441,6 +3441,19 @@ fetch(`${baseURL}/vault/v1/megavault/historicalPnl`, `GET /vault/v1/megavault/historicalPnl` +### Parameters + +|Name|In|Type|Required|Description| +|---|---|---|---|---| +|resolution|query|[PnlTickInterval](#schemapnltickinterval)|false|none| + +#### Enumerated Values + +|Parameter|Value| +|---|---| +|resolution|hour| +|resolution|day| + > Example responses > 200 Response @@ -3520,6 +3533,19 @@ fetch(`${baseURL}/vault/v1/vaults/historicalPnl`, `GET /vault/v1/vaults/historicalPnl` +### Parameters + +|Name|In|Type|Required|Description| +|---|---|---|---|---| +|resolution|query|[PnlTickInterval](#schemapnltickinterval)|false|none| + +#### Enumerated Values + +|Parameter|Value| +|---|---| +|resolution|hour| +|resolution|day| + > Example responses > 200 Response @@ -5941,6 +5967,31 @@ or |---|---|---|---|---| |megavaultPnl|[[PnlTicksResponseObject](#schemapnlticksresponseobject)]|true|none|none| +## PnlTickInterval + + + + + + +```json +"hour" + +``` + +### Properties + +|Name|Type|Required|Restrictions|Description| +|---|---|---|---|---| +|*anonymous*|string|false|none|none| + +#### Enumerated Values + +|Property|Value| +|---|---| +|*anonymous*|hour| +|*anonymous*|day| + ## VaultHistoricalPnl diff --git a/indexer/services/comlink/public/swagger.json b/indexer/services/comlink/public/swagger.json index 5fc7a5cff8..c485b6831c 100644 --- a/indexer/services/comlink/public/swagger.json +++ b/indexer/services/comlink/public/swagger.json @@ -1496,6 +1496,13 @@ "type": "object", "additionalProperties": false }, + "PnlTickInterval": { + "enum": [ + "hour", + "day" + ], + "type": "string" + }, "VaultHistoricalPnl": { "properties": { "ticker": { @@ -3424,7 +3431,16 @@ } }, "security": [], - "parameters": [] + "parameters": [ + { + "in": "query", + "name": "resolution", + "required": false, + "schema": { + "$ref": "#/components/schemas/PnlTickInterval" + } + } + ] } }, "/vault/v1/vaults/historicalPnl": { @@ -3443,7 +3459,16 @@ } }, "security": [], - "parameters": [] + "parameters": [ + { + "in": "query", + "name": "resolution", + "required": false, + "schema": { + "$ref": "#/components/schemas/PnlTickInterval" + } + } + ] } }, "/vault/v1/megavault/positions": { diff --git a/indexer/services/comlink/src/config.ts b/indexer/services/comlink/src/config.ts index e2c85ade2f..9591c64eb0 100644 --- a/indexer/services/comlink/src/config.ts +++ b/indexer/services/comlink/src/config.ts @@ -63,6 +63,9 @@ export const configSchema = { // Affiliates config VOLUME_ELIGIBILITY_THRESHOLD: parseInteger({ default: 10_000 }), + + // Vaults config + VAULT_PNL_HISTORY_DAYS: parseInteger({ default: 90 }), }; //////////////////////////////////////////////////////////////////////////////// diff --git a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts index 73810f25bf..0403242ca4 100644 --- a/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts +++ b/indexer/services/comlink/src/controllers/api/v4/vault-controller.ts @@ -1,10 +1,7 @@ import { stats } from '@dydxprotocol-indexer/base'; import { - DEFAULT_POSTGRES_OPTIONS, - Ordering, PaginationFromDatabase, PnlTicksFromDatabase, PnlTicksTable, - QueryableField, perpetualMarketRefresher, PerpetualMarketFromDatabase, USDC_ASSET_ID, @@ -24,11 +21,13 @@ import { MarketFromDatabase, BlockFromDatabase, FundingIndexUpdatesTable, + PnlTickInterval, } from '@dydxprotocol-indexer/postgres'; import express from 'express'; +import { checkSchema, matchedData } from 'express-validator'; import _ from 'lodash'; import { - Controller, Get, Route, + Controller, Get, Query, Route, } from 'tsoa'; import { getReqRateLimiter } from '../../../caches/rate-limiters'; @@ -39,6 +38,7 @@ import { handleControllerError, } from '../../../lib/helpers'; import { rateLimiterMiddleware } from '../../../lib/rate-limit'; +import { handleValidationErrors } from '../../../request-helpers/error-handler'; import ExportResponseCodeStats from '../../../request-helpers/export-response-code-stats'; import { pnlTicksToResponseObject } from '../../../request-helpers/request-transformer'; import { @@ -49,6 +49,8 @@ import { AssetById, MegavaultPositionResponse, SubaccountResponseObject, + MegavaultHistoricalPnlRequest, + VaultsHistoricalPnlRequest, } from '../../../types'; const router: express.Router = express.Router(); @@ -63,8 +65,10 @@ interface VaultMapping { @Route('vault/v1') class VaultController extends Controller { @Get('/megavault/historicalPnl') - async getMegavaultHistoricalPnl(): Promise { - const vaultPnlTicks: PnlTicksFromDatabase[] = await getVaultSubaccountPnlTicks(); + async getMegavaultHistoricalPnl( + @Query() resolution?: PnlTickInterval, + ): Promise { + const vaultPnlTicks: PnlTicksFromDatabase[] = await getVaultSubaccountPnlTicks(resolution); // aggregate pnlTicks for all vault subaccounts grouped by blockHeight const aggregatedPnlTicks: Map = aggregatePnlTicks(vaultPnlTicks); @@ -78,9 +82,11 @@ class VaultController extends Controller { } @Get('/vaults/historicalPnl') - async getVaultsHistoricalPnl(): Promise { + async getVaultsHistoricalPnl( + @Query() resolution?: PnlTickInterval, + ): Promise { const vaultSubaccounts: VaultMapping = getVaultSubaccountsFromConfig(); - const vaultPnlTicks: PnlTicksFromDatabase[] = await getVaultSubaccountPnlTicks(); + const vaultPnlTicks: PnlTicksFromDatabase[] = await getVaultSubaccountPnlTicks(resolution); const groupedVaultPnlTicks: VaultHistoricalPnl[] = _(vaultPnlTicks) .groupBy('subaccountId') @@ -232,15 +238,29 @@ class VaultController extends Controller { router.get( '/v1/megavault/historicalPnl', + ...checkSchema({ + resolution: { + in: 'query', + isIn: { + options: [Object.values(PnlTickInterval)], + errorMessage: `type must be one of ${Object.values(PnlTickInterval)}`, + }, + optional: true, + }, + }), + handleValidationErrors, rateLimiterMiddleware(getReqRateLimiter), ExportResponseCodeStats({ controllerName }), async (req: express.Request, res: express.Response) => { const start: number = Date.now(); + const { + resolution, + }: MegavaultHistoricalPnlRequest = matchedData(req) as MegavaultHistoricalPnlRequest; try { const controllers: VaultController = new VaultController(); const response: MegavaultHistoricalPnlResponse = await controllers - .getMegavaultHistoricalPnl(); + .getMegavaultHistoricalPnl(resolution); return res.send(response); } catch (error) { return handleControllerError( @@ -261,14 +281,29 @@ router.get( router.get( '/v1/vaults/historicalPnl', + ...checkSchema({ + resolution: { + in: 'query', + isIn: { + options: [Object.values(PnlTickInterval)], + errorMessage: `type must be one of ${Object.values(PnlTickInterval)}`, + }, + optional: true, + }, + }), + handleValidationErrors, rateLimiterMiddleware(getReqRateLimiter), ExportResponseCodeStats({ controllerName }), async (req: express.Request, res: express.Response) => { const start: number = Date.now(); + const { + resolution, + }: VaultsHistoricalPnlRequest = matchedData(req) as VaultsHistoricalPnlRequest; try { const controllers: VaultController = new VaultController(); - const response: VaultsHistoricalPnlResponse = await controllers.getVaultsHistoricalPnl(); + const response: VaultsHistoricalPnlResponse = await controllers + .getVaultsHistoricalPnl(resolution); return res.send(response); } catch (error) { return handleControllerError( @@ -313,26 +348,26 @@ router.get( } }); -async function getVaultSubaccountPnlTicks(): Promise { +async function getVaultSubaccountPnlTicks( + resolution?: PnlTickInterval, +): Promise { const vaultSubaccountIds: string[] = _.keys(getVaultSubaccountsFromConfig()); if (vaultSubaccountIds.length === 0) { return []; } - const { - results: pnlTicks, - }: PaginationFromDatabase = await - PnlTicksTable.findAll( - { - subaccountId: vaultSubaccountIds, - // TODO(TRA-571): Configure limits based on hourly vs daily resolution and # of vaults. - limit: config.API_LIMIT_V4, - }, - [QueryableField.LIMIT], - { - ...DEFAULT_POSTGRES_OPTIONS, - orderBy: [[QueryableField.BLOCK_HEIGHT, Ordering.DESC]], - }, + let pnlTickInterval: PnlTickInterval; + if (resolution === undefined) { + pnlTickInterval = PnlTickInterval.day; + } else { + pnlTickInterval = resolution; + } + + const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getPnlTicksAtIntervals( + pnlTickInterval, + config.VAULT_PNL_HISTORY_DAYS * 24 * 60 * 60, + vaultSubaccountIds, ); + return pnlTicks; } diff --git a/indexer/services/comlink/src/types.ts b/indexer/services/comlink/src/types.ts index ce204a95a3..35a97a7c37 100644 --- a/indexer/services/comlink/src/types.ts +++ b/indexer/services/comlink/src/types.ts @@ -18,6 +18,7 @@ import { PerpetualMarketType, PerpetualPositionFromDatabase, PerpetualPositionStatus, + PnlTickInterval, PositionSide, SubaccountFromDatabase, TradeType, @@ -679,6 +680,12 @@ export interface MegavaultPositionResponse { positions: VaultPosition[], } +export interface MegavaultHistoricalPnlRequest { + resolution: PnlTickInterval, +} + +export interface VaultsHistoricalPnlRequest extends MegavaultHistoricalPnlRequest {} + /* ------- Affiliates Types ------- */ export interface AffiliateMetadataRequest{ address: string, From f636b7b17f6220d63aa507aaea27b0201331810d Mon Sep 17 00:00:00 2001 From: Vincent Chau <99756290+vincentwschau@users.noreply.github.com> Date: Tue, 17 Sep 2024 17:02:58 -0400 Subject: [PATCH 2/2] Make sure tests won't flake. --- .../__tests__/controllers/api/v4/vault-controller.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts b/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts index 50daa133ae..c0a9fe6c6e 100644 --- a/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts +++ b/indexer/services/comlink/__tests__/controllers/api/v4/vault-controller.test.ts @@ -25,7 +25,7 @@ describe('vault-controller#V4', () => { const currentBlockHeight: string = '7'; const twoHourBlockHeight: string = '5'; const twoDayBlockHeight: string = '3'; - const currentTime: DateTime = DateTime.utc(); + const currentTime: DateTime = DateTime.utc().startOf('day').minus({ hour: 5 }); const twoHoursAgo: DateTime = currentTime.minus({ hour: 2 }); const twoDaysAgo: DateTime = currentTime.minus({ day: 2 }); const initialFundingIndex: string = '10000';