Skip to content

Commit

Permalink
Include getting main subaccount equity / pnl for megavault PnL query.…
Browse files Browse the repository at this point in the history
… (backport #2376) (#2378)

Co-authored-by: vincentwschau <[email protected]>
  • Loading branch information
mergify[bot] and vincentwschau authored Sep 26, 2024
1 parent 8b933c6 commit 0502f73
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 14 deletions.
5 changes: 5 additions & 0 deletions indexer/packages/postgres/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,8 @@ export const DEFAULT_POSTGRES_OPTIONS : Options = config.USE_READ_REPLICA
export const MAX_PARENT_SUBACCOUNTS: number = 128;

export const CHILD_SUBACCOUNT_MULTIPLIER: number = 1000;

// From https://github.com/dydxprotocol/v4-chain/blob/protocol/v7.0.0-dev0/protocol/app/module_accounts_test.go#L41
export const MEGAVAULT_MODULE_ADDRESS: string = 'dydx18tkxrnrkqc2t0lr3zxr5g6a4hdvqksylxqje4r';
// Generated from the module address + subaccount number 0.
export const MEGAVAULT_SUBACCOUNT_ID: string = 'c7169f81-0c80-54c5-a41f-9cbb6a538fdf';
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
FundingIndexUpdatesTable,
PnlTicksFromDatabase,
VaultTable,
MEGAVAULT_MODULE_ADDRESS,
MEGAVAULT_SUBACCOUNT_ID,
} from '@dydxprotocol-indexer/postgres';
import { RequestMethod, VaultHistoricalPnl } from '../../../../src/types';
import request from 'supertest';
Expand All @@ -32,6 +34,7 @@ describe('vault-controller#V4', () => {
const initialFundingIndex: string = '10000';
const vault1Equity: number = 159500;
const vault2Equity: number = 10000;
const mainVaultEquity: number = 10000;

beforeAll(async () => {
await dbHelpers.migrate();
Expand Down Expand Up @@ -69,6 +72,12 @@ describe('vault-controller#V4', () => {
}),
]);
await SubaccountTable.create(testConstants.vaultSubaccount);
await SubaccountTable.create({
address: MEGAVAULT_MODULE_ADDRESS,
subaccountNumber: 0,
updatedAt: latestTime.toISO(),
updatedAtHeight: latestBlockHeight,
});
await Promise.all([
PerpetualPositionTable.create(
testConstants.defaultPerpetualPosition,
Expand Down Expand Up @@ -146,7 +155,7 @@ describe('vault-controller#V4', () => {
['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 (
])('Get /megavault/historicalPnl with 2 vault subaccounts and main subaccount (%s)', async (
_name: string,
queryParam: string,
expectedTicksIndex: number[],
Expand All @@ -162,22 +171,28 @@ describe('vault-controller#V4', () => {
address: testConstants.vaultAddress,
clobPairId: testConstants.defaultPerpetualMarket2.clobPairId,
}),
AssetPositionTable.upsert({
...testConstants.defaultAssetPosition,
subaccountId: MEGAVAULT_SUBACCOUNT_ID,
}),
]);

const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks();
const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks(
true, // createMainSubaccounPnlTicks
);
const response: request.Response = await sendRequest({
type: RequestMethod.GET,
path: `/v4/vault/v1/megavault/historicalPnl${queryParam}`,
});

const expectedPnlTickBase: any = {
equity: (parseFloat(testConstants.defaultPnlTick.equity) * 2).toString(),
totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 2).toString(),
netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 2).toString(),
equity: (parseFloat(testConstants.defaultPnlTick.equity) * 3).toString(),
totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 3).toString(),
netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 3).toString(),
};
const finalTick: PnlTicksFromDatabase = {
...expectedPnlTickBase,
equity: Big(vault1Equity).add(vault2Equity).toFixed(),
equity: Big(vault1Equity).add(vault2Equity).add(mainVaultEquity).toFixed(),
blockHeight: latestBlockHeight,
blockTime: latestTime.toISO(),
createdAt: latestTime.toISO(),
Expand Down Expand Up @@ -449,8 +464,10 @@ describe('vault-controller#V4', () => {
});
});

async function createPnlTicks(): Promise<PnlTicksFromDatabase[]> {
return Promise.all([
async function createPnlTicks(
createMainSubaccountPnlTicks: boolean = false,
): Promise<PnlTicksFromDatabase[]> {
const createdTicks: PnlTicksFromDatabase[] = await Promise.all([
PnlTicksTable.create(testConstants.defaultPnlTick),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
Expand Down Expand Up @@ -496,5 +513,38 @@ describe('vault-controller#V4', () => {
blockHeight: currentBlockHeight,
}),
]);

if (createMainSubaccountPnlTicks) {
const mainSubaccountTicks: PnlTicksFromDatabase[] = await Promise.all([
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: MEGAVAULT_SUBACCOUNT_ID,
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: MEGAVAULT_SUBACCOUNT_ID,
blockTime: twoDaysAgo.toISO(),
createdAt: twoDaysAgo.toISO(),
blockHeight: twoDayBlockHeight,
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: MEGAVAULT_SUBACCOUNT_ID,
blockTime: twoHoursAgo.toISO(),
createdAt: twoHoursAgo.toISO(),
blockHeight: twoHourBlockHeight,
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: MEGAVAULT_SUBACCOUNT_ID,
blockTime: currentTime.toISO(),
createdAt: currentTime.toISO(),
blockHeight: currentBlockHeight,
}),
]);
createdTicks.push(...mainSubaccountTicks);
}

return createdTicks;
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
PnlTickInterval,
VaultTable,
VaultFromDatabase,
MEGAVAULT_SUBACCOUNT_ID,
} from '@dydxprotocol-indexer/postgres';
import Big from 'big.js';
import express from 'express';
Expand Down Expand Up @@ -70,18 +71,24 @@ class VaultController extends Controller {
@Query() resolution?: PnlTickInterval,
): Promise<MegavaultHistoricalPnlResponse> {
const vaultSubaccounts: VaultMapping = await getVaultMapping();
const vaultSubaccountIdsWithMainSubaccount: string[] = _
.keys(vaultSubaccounts)
.concat([MEGAVAULT_SUBACCOUNT_ID]);
const [
vaultPnlTicks,
vaultPositions,
latestBlock,
mainSubaccountEquity,
] : [
PnlTicksFromDatabase[],
Map<string, VaultPosition>,
BlockFromDatabase,
string,
] = await Promise.all([
getVaultSubaccountPnlTicks(vaultSubaccounts, resolution),
getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, resolution),
getVaultPositions(vaultSubaccounts),
BlockTable.getLatest(),
getMainSubaccountEquity(),
]);

// aggregate pnlTicks for all vault subaccounts grouped by blockHeight
Expand All @@ -92,15 +99,15 @@ class VaultController extends Controller {
return position.equity;
}).reduce((acc: string, curr: string): string => {
return (Big(acc).add(Big(curr))).toFixed();
}, '0');
}, mainSubaccountEquity);
const pnlTicksWithCurrentTick: PnlTicksFromDatabase[] = getPnlTicksWithCurrentTick(
currentEquity,
Array.from(aggregatedPnlTicks.values()),
latestBlock,
);

return {
megavaultPnl: pnlTicksWithCurrentTick.map(
megavaultPnl: _.sortBy(pnlTicksWithCurrentTick, 'blockTime').map(
(pnlTick: PnlTicksFromDatabase) => {
return pnlTicksToResponseObject(pnlTick);
}),
Expand All @@ -121,7 +128,7 @@ class VaultController extends Controller {
Map<string, VaultPosition>,
BlockFromDatabase,
] = await Promise.all([
getVaultSubaccountPnlTicks(vaultSubaccounts, resolution),
getVaultSubaccountPnlTicks(_.keys(vaultSubaccounts), resolution),
getVaultPositions(vaultSubaccounts),
BlockTable.getLatest(),
]);
Expand Down Expand Up @@ -286,10 +293,9 @@ router.get(
});

async function getVaultSubaccountPnlTicks(
vaultSubaccounts: VaultMapping,
vaultSubaccountIds: string[],
resolution?: PnlTickInterval,
): Promise<PnlTicksFromDatabase[]> {
const vaultSubaccountIds: string[] = _.keys(vaultSubaccounts);
if (vaultSubaccountIds.length === 0) {
return [];
}
Expand Down Expand Up @@ -437,6 +443,15 @@ async function getVaultPositions(
));
}

async function getMainSubaccountEquity(): Promise<string> {
// Main vault subaccount should only ever hold a USDC and never any perpetuals.
const usdcBalance: {[subaccountId: string]: Big} = await AssetPositionTable
.findUsdcPositionForSubaccounts(
[MEGAVAULT_SUBACCOUNT_ID],
);
return usdcBalance[MEGAVAULT_SUBACCOUNT_ID]?.toFixed() || '0';
}

function getPnlTicksWithCurrentTick(
equity: string,
pnlTicks: PnlTicksFromDatabase[],
Expand Down

0 comments on commit 0502f73

Please sign in to comment.