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

[TRA-571] Add vault table and vault event version/subtype. #2263

Merged
merged 2 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { seedData } from '../helpers/mock-generators';

// NOTE: If a model is modified for a migration then these
// tests must be skipped until the following migration
describe.skip('Test new migration', () => {
describe('Test new migration', () => {
beforeEach(async () => {
await migrate();
});
Expand Down
14 changes: 14 additions & 0 deletions indexer/packages/postgres/__tests__/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ import {
TransferCreateObject,
WalletCreateObject,
PersistentCacheCreateObject,
VaultCreateObject,
VaultStatus,
} from '../../src/types';
import { denomToHumanReadableConversion } from './conversion-helpers';

Expand Down Expand Up @@ -991,3 +993,15 @@ export const defaultFirebaseNotificationToken = {
language: 'en',
updatedAt: createdDateTime.toISO(),
};

// ============== Vaults =============

export const defaultVaultAddress: string = 'dydx1pzaql7h3tkt9uet8yht80me5td6gh0aprf58yk';

export const defaultVault: VaultCreateObject = {
address: defaultVaultAddress,
clobPairId: '0',
status: VaultStatus.QUOTING,
createdAt: createdDateTime.toISO(),
updatedAt: createdDateTime.toISO(),
};
81 changes: 81 additions & 0 deletions indexer/packages/postgres/__tests__/stores/vault-table.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as VaultTable from '../../src/stores/vault-table';
import {
clearData,
migrate,
teardown,
} from '../../src/helpers/db-helpers';
import { defaultVault, defaultAddress } from '../helpers/constants';
import { VaultFromDatabase, VaultStatus } from '../../src/types';

describe('Vault store', () => {
beforeAll(async () => {
await migrate();
});

afterEach(async () => {
await clearData();
});

afterAll(async () => {
await teardown();
});

it('Successfully creates a vault', async () => {
await VaultTable.create(defaultVault);
});
Comment on lines +23 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add assertions to verify the vault creation.

The test case ensures that the create method can be called without errors. However, it does not verify that the vault is actually created with the correct data.

Consider adding assertions to verify that the created vault matches the input data:

  it('Successfully creates a vault', async () => {
    await VaultTable.create(defaultVault);
+   const createdVault = await VaultTable.findAll({}, [], { readReplica: true });
+   expect(createdVault.length).toEqual(1);
+   expect(createdVault[0]).toEqual(expect.objectContaining(defaultVault));
  });
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('Successfully creates a vault', async () => {
await VaultTable.create(defaultVault);
});
it('Successfully creates a vault', async () => {
await VaultTable.create(defaultVault);
const createdVault = await VaultTable.findAll({}, [], { readReplica: true });
expect(createdVault.length).toEqual(1);
expect(createdVault[0]).toEqual(expect.objectContaining(defaultVault));
});


it('Successfully finds all vaults', async () => {
await Promise.all([
VaultTable.create(defaultVault),
VaultTable.create({
...defaultVault,
address: defaultAddress,
clobPairId: '1',
}),
]);

const vaults: VaultFromDatabase[] = await VaultTable.findAll(
{},
[],
{ readReplica: true },
);

expect(vaults.length).toEqual(2);
expect(vaults[0]).toEqual(expect.objectContaining(defaultVault));
expect(vaults[1]).toEqual(expect.objectContaining({
...defaultVault,
address: defaultAddress,
clobPairId: '1',
}));
});

it('Succesfully upserts a vault', async () => {
await VaultTable.create(defaultVault);

let vaults: VaultFromDatabase[] = await VaultTable.findAll(
{},
[],
{ readReplica: true },
);

expect(vaults.length).toEqual(1);
expect(vaults[0]).toEqual(expect.objectContaining(defaultVault));

await VaultTable.upsert({
...defaultVault,
status: VaultStatus.CLOSE_ONLY,
});

vaults = await VaultTable.findAll(
{},
[],
{ readReplica: true },
);

expect(vaults.length).toEqual(1);
expect(vaults[0]).toEqual(expect.objectContaining({
...defaultVault,
status: VaultStatus.CLOSE_ONLY,
}));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as Knex from 'knex';

export async function up(knex: Knex): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for my understanding, this logic is run when indexer is upgraded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

return knex.schema.createTable('vaults', (table) => {
table.string('address').primary().notNullable(); // address of vault
table.bigInteger('clobPairId').notNullable(); // clob pair id for vault
table.enum('status', [
'DEACTIVATED',
'STANDBY',
'QUOTING',
'CLOSE_ONLY',
]).notNullable(); // quoting status of vault
table.timestamp('createdAt').notNullable();
table.timestamp('updatedAt').notNullable();
});
}

export async function down(knex: Knex): Promise<void> {
return knex.schema.dropTable('vaults');
}
1 change: 1 addition & 0 deletions indexer/packages/postgres/src/helpers/db-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const layer1Tables = [
'affiliate_referred_users',
'persistent_cache',
'affiliate_info',
'vaults',
];

/**
Expand Down
44 changes: 44 additions & 0 deletions indexer/packages/postgres/src/models/vault-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { IntegerPattern } from '../lib/validators';
import { IsoString, VaultStatus } from '../types';
import BaseModel from './base-model';

export default class VaultModel extends BaseModel {

static get tableName() {
return 'vaults';
}

static get idColumn() {
return ['address'];
}

static get jsonSchema() {
return {
type: 'object',
required: [
'address',
'clobPairId',
'status',
'createdAt',
'updatedAt',
],
properties: {
address: { type: 'string' },
clobPairId: { type: 'string', pattern: IntegerPattern },
status: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' },
},
};
}

address!: string;

clobPairId!: string;

status!: VaultStatus;

createdAt!: IsoString;

updatedAt!: IsoString;
}
100 changes: 100 additions & 0 deletions indexer/packages/postgres/src/stores/vault-table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { QueryBuilder } from 'objection';

import { DEFAULT_POSTGRES_OPTIONS } from '../constants';
import {
verifyAllRequiredFields,
setupBaseQuery,
} from '../helpers/stores-helpers';
import Transaction from '../helpers/transaction';
import VaultModel from '../models/vault-model';
import {
QueryConfig,
VaultQueryConfig,
VaultColumns,
Options,
Ordering,
QueryableField,
VaultFromDatabase,
VaultCreateObject,
} from '../types';

export async function findAll(
{
address,
clobPairId,
status,
limit,
}: VaultQueryConfig,
requiredFields: QueryableField[],
options: Options = DEFAULT_POSTGRES_OPTIONS,
): Promise<VaultFromDatabase[]> {
verifyAllRequiredFields(
{
address,
clobPairId,
status,
limit,
} as QueryConfig,
requiredFields,
);

let baseQuery: QueryBuilder<VaultModel> = setupBaseQuery<VaultModel>(
VaultModel,
options,
);

if (address) {
baseQuery = baseQuery.whereIn(VaultColumns.address, address);
}

if (clobPairId) {
baseQuery = baseQuery.whereIn(VaultColumns.clobPairId, clobPairId);
}

if (status) {
baseQuery = baseQuery.whereIn(VaultColumns.status, status);
}

if (options.orderBy !== undefined) {
for (const [column, order] of options.orderBy) {
baseQuery = baseQuery.orderBy(
column,
order,
);
}
} else {
baseQuery = baseQuery.orderBy(
VaultColumns.clobPairId,
Ordering.ASC,
);
}

if (limit) {
baseQuery = baseQuery.limit(limit);
}

return baseQuery.returning('*');
}

export async function create(
vaultToCreate: VaultCreateObject,
options: Options = { txId: undefined },
): Promise<VaultFromDatabase> {
return VaultModel.query(
Transaction.get(options.txId),
).insert({
...vaultToCreate,
});
}

export async function upsert(
vaultToUpsert: VaultCreateObject,
options: Options = { txId: undefined },
): Promise<VaultFromDatabase> {
const vaults: VaultModel[] = await VaultModel.query(
Transaction.get(options.txId),
).upsert({
...vaultToUpsert,
}).returning('*');
return vaults[0];
}
9 changes: 9 additions & 0 deletions indexer/packages/postgres/src/types/db-model-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { PerpetualMarketStatus, PerpetualMarketType } from './perpetual-market-t
import { PerpetualPositionStatus } from './perpetual-position-types';
import { PositionSide } from './position-types';
import { TradingRewardAggregationPeriod } from './trading-reward-aggregation-types';
import { VaultStatus } from './vault-types';

type IsoString = string;

Expand Down Expand Up @@ -301,6 +302,14 @@ export interface FirebaseNotificationTokenFromDatabase {
language: string,
}

export interface VaultFromDatabase {
address: string,
clobPairId: string,
status: VaultStatus,
createdAt: IsoString,
updatedAt: IsoString,
}

export type SubaccountAssetNetTransferMap = { [subaccountId: string]:
{ [assetId: string]: string }, };
export type SubaccountToPerpetualPositionsMap = { [subaccountId: string]:
Expand Down
1 change: 1 addition & 0 deletions indexer/packages/postgres/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ export * from './affiliate-referred-users-types';
export * from './persistent-cache-types';
export * from './affiliate-info-types';
export * from './firebase-notification-token-types';
export * from './vault-types';
export { PositionSide } from './position-types';
6 changes: 6 additions & 0 deletions indexer/packages/postgres/src/types/query-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,9 @@ export interface FirebaseNotificationTokenQueryConfig extends QueryConfig {
[QueryableField.TOKEN]?: string,
[QueryableField.UPDATED_BEFORE_OR_AT]?: IsoString,
}

export interface VaultQueryConfig extends QueryConfig {
[QueryableField.ADDRESS]?: string[],
[QueryableField.CLOB_PAIR_ID]?: string[],
[QueryableField.STATUS]?: string[],
}
24 changes: 24 additions & 0 deletions indexer/packages/postgres/src/types/vault-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IsoString } from './utility-types';

export interface VaultCreateObject {
address: string,
clobPairId: string,
status: VaultStatus,
createdAt: IsoString,
updatedAt: IsoString,
}

export enum VaultStatus {
DEACTIVATED = 'DEACTIVATED',
STAND_BY = 'STAND_BY',
QUOTING = 'QUOTING',
CLOSE_ONLY = 'CLOSE_ONLY',
}

export enum VaultColumns {
address = 'address',
clobPairId = 'clobPairId',
status = 'status',
createdAt = 'createdAt',
updatedAt = 'updatedAt',
}
3 changes: 3 additions & 0 deletions protocol/indexer/events/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
SubtypeTradingReward = "trading_reward"
SubtypeOpenInterestUpdate = "open_interest_update"
SubtypeRegisterAffiliate = "register_affiliate"
SubtypeUpsertVault = "upsert_vault"
)

const (
Expand All @@ -39,6 +40,7 @@ const (
TradingRewardVersion uint32 = 1
OpenInterestUpdateVersion uint32 = 1
RegisterAffiliateEventVersion uint32 = 1
UpsertVaultEventVersion uint32 = 1
)

var OnChainEventSubtypes = []string{
Expand All @@ -56,4 +58,5 @@ var OnChainEventSubtypes = []string{
SubtypeDeleveraging,
SubtypeTradingReward,
SubtypeRegisterAffiliate,
SubtypeUpsertVault,
}
Loading