Skip to content
Open
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
369 changes: 368 additions & 1 deletion indexer/packages/postgres/__tests__/stores/transfer-table.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
BlockCreateObject,
Ordering,
SubaccountAssetNetTransferMap,
TendermintEventCreateObject,
TransferColumns,
TransferCreateObject,
TransferFromDatabase,
Expand Down Expand Up @@ -29,11 +31,12 @@ import {
defaultTransfer3,
defaultWalletAddress,
defaultWithdrawal,
isolatedSubaccountId,
} from '../helpers/constants';
import Big from 'big.js';
import { CheckViolationError } from 'objection';
import { DateTime } from 'luxon';
import { USDC_ASSET_ID } from '../../src';
import { BlockTable, TendermintEventTable, USDC_ASSET_ID } from '../../src';

describe('Transfer store', () => {
beforeEach(async () => {
Expand Down Expand Up @@ -661,4 +664,368 @@ describe('Transfer store', () => {
expect(netTransfers).toEqual('0');
});
});

describe('findAllToOrFromParentSubaccount', () => {
it('Successfully excludes transfers between child subaccounts of the same parent', async () => {
// defaultSubaccount (subaccount 0) -> isolatedSubaccount (subaccount 128)
// Both have parent subaccount 0 (0 % 128 = 0, 128 % 128 = 0)
const sameParentTransfer: TransferCreateObject = {
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: isolatedSubaccountId,
assetId: defaultAsset.id,
size: '100',
eventId: defaultTendermintEventId,
transactionHash: '',
createdAt: createdDateTime.toISO(),
createdAtHeight: createdHeight,
};

// defaultSubaccount (parent 0) -> defaultSubaccount2 (parent 1)
const differentParentTransfer: TransferCreateObject = {
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: defaultSubaccountId2,
assetId: defaultAsset.id,
size: '200',
eventId: defaultTendermintEventId2,
transactionHash: '',
createdAt: createdDateTime.toISO(),
createdAtHeight: createdHeight,
};

await Promise.all([
TransferTable.create(sameParentTransfer),
TransferTable.create(differentParentTransfer),
]);

const { results: transfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId, isolatedSubaccountId],
limit: 100,
},
[],
);

expect(transfers.length).toEqual(1);
expect(transfers[0]).toEqual(expect.objectContaining(differentParentTransfer));
});

it('Successfully includes transfers from different addresses', async () => {
const crossAddressTransfer: TransferCreateObject = {
senderSubaccountId: defaultSubaccountId2,
recipientSubaccountId: defaultSubaccountId,
assetId: defaultAsset.id,
size: '150',
eventId: defaultTendermintEventId,
transactionHash: '',
createdAt: createdDateTime.toISO(),
createdAtHeight: createdHeight,
};

await TransferTable.create(crossAddressTransfer);

const { results: transfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId],
limit: 100,
},
[],
);

expect(transfers.length).toEqual(1);
expect(transfers[0]).toEqual(expect.objectContaining(crossAddressTransfer));
});

it('Successfully includes deposits to child subaccounts', async () => {
await WalletTable.create({
address: defaultWalletAddress,
totalTradingRewards: '0',
totalVolume: '0',
});

const deposit: TransferCreateObject = {
senderWalletAddress: defaultWalletAddress,
recipientSubaccountId: isolatedSubaccountId,
assetId: defaultAsset.id,
size: '500',
eventId: defaultTendermintEventId,
transactionHash: '',
createdAt: createdDateTime.toISO(),
createdAtHeight: createdHeight,
};

await TransferTable.create(deposit);

const { results: transfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [isolatedSubaccountId],
limit: 100,
},
[],
);

expect(transfers.length).toEqual(1);
expect(transfers[0]).toEqual(expect.objectContaining(deposit));
});

it('Successfully includes withdrawals from child subaccounts', async () => {
await WalletTable.create({
address: defaultWalletAddress,
totalTradingRewards: '0',
totalVolume: '0',
});

const withdrawal: TransferCreateObject = {
senderSubaccountId: isolatedSubaccountId,
recipientWalletAddress: defaultWalletAddress,
assetId: defaultAsset.id,
size: '300',
eventId: defaultTendermintEventId,
transactionHash: '',
createdAt: createdDateTime.toISO(),
createdAtHeight: createdHeight,
};

await TransferTable.create(withdrawal);

const { results: transfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [isolatedSubaccountId],
limit: 100,
},
[],
);

expect(transfers.length).toEqual(1);
expect(transfers[0]).toEqual(expect.objectContaining(withdrawal));
});

it('Successfully respects limit parameter', async () => {
// Create 5 blocks first
const blocks: BlockCreateObject[] = [];
for (let i = 0; i < 5; i++) {
blocks.push({
blockHeight: (3 + i).toString(),
time: createdDateTime.plus({ minutes: i }).toISO(),
});
}
await Promise.all(blocks.map((b) => BlockTable.create(b)));

// Create 5 TendermintEvents
const events: TendermintEventCreateObject[] = [];
for (let i = 0; i < 5; i++) {
events.push({
blockHeight: (3 + i).toString(),
transactionIndex: 0,
eventIndex: 0,
});
}
await Promise.all(events.map((e) => TendermintEventTable.create(e)));

// Create 5 transfers
const transfers: TransferCreateObject[] = [];
for (let i = 0; i < 5; i++) {
const eventId = TendermintEventTable.createEventId(
events[i].blockHeight,
events[i].transactionIndex,
events[i].eventIndex,
);

transfers.push({
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: defaultSubaccountId2,
assetId: defaultAsset.id,
size: `${i + 1}`,
eventId,
transactionHash: `hash${i}`,
createdAt: createdDateTime.plus({ minutes: i }).toISO(),
createdAtHeight: (parseInt(createdHeight, 10) + i).toString(),
});
}

await Promise.all(transfers.map((t) => TransferTable.create(t)));

const { results: resultTransfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId],
limit: 3,
},
[],
);

expect(resultTransfers.length).toEqual(3);
});

it('Successfully finds all transfers to and from parent subaccount using pagination', async () => {
// Create 4 blocks first
const blocks: BlockCreateObject[] = [];
for (let i = 0; i < 4; i++) {
blocks.push({
blockHeight: (3 + i).toString(),
time: createdDateTime.plus({ minutes: i }).toISO(),
});
}
await Promise.all(blocks.map((b) => BlockTable.create(b)));

// Create 4 TendermintEvents
const events: TendermintEventCreateObject[] = [];
for (let i = 0; i < 4; i++) {
events.push({
blockHeight: (3 + i).toString(),
transactionIndex: 0,
eventIndex: 0,
});
}
await Promise.all(events.map((e) => TendermintEventTable.create(e)));

// Create 4 transfers
const transfers: TransferCreateObject[] = [];
for (let i = 0; i < 4; i++) {
const eventId = TendermintEventTable.createEventId(
events[i].blockHeight,
events[i].transactionIndex,
events[i].eventIndex,
);

transfers.push({
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: defaultSubaccountId2,
assetId: defaultAsset.id,
size: `${i + 1}`,
eventId,
transactionHash: `hash${i}`,
createdAt: createdDateTime.plus({ minutes: i }).toISO(),
createdAtHeight: (parseInt(createdHeight, 10) + i).toString(),
});
}

await Promise.all(transfers.map((t) => TransferTable.create(t)));

const responsePageOne = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId],
limit: 2,
page: 1,
},
[],
{ orderBy: [[TransferColumns.id, Ordering.ASC]] },
);

expect(responsePageOne.results.length).toEqual(2);
expect(responsePageOne.offset).toEqual(0);
expect(responsePageOne.total).toEqual(4);
expect(responsePageOne.limit).toEqual(2);

const responsePageTwo = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId],
limit: 2,
page: 2,
},
[],
{ orderBy: [[TransferColumns.id, Ordering.ASC]] },
);

expect(responsePageTwo.results.length).toEqual(2);
expect(responsePageTwo.offset).toEqual(2);
expect(responsePageTwo.total).toEqual(4);
expect(responsePageTwo.limit).toEqual(2);
});

it('Successfully finds all transfers before or at the height', async () => {
const transfer1: TransferCreateObject = {
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: defaultSubaccountId2,
assetId: defaultAsset.id,
size: '100',
eventId: defaultTendermintEventId,
transactionHash: '',
createdAt: createdDateTime.toISO(),
createdAtHeight: '10',
};

const transfer2: TransferCreateObject = {
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: defaultSubaccountId2,
assetId: defaultAsset.id,
size: '200',
eventId: defaultTendermintEventId2,
transactionHash: '',
createdAt: createdDateTime.plus({ minutes: 1 }).toISO(),
createdAtHeight: '20',
};

await Promise.all([
TransferTable.create(transfer1),
TransferTable.create(transfer2),
]);

const { results: transfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId],
limit: 100,
createdBeforeOrAtHeight: '10',
},
[],
);

expect(transfers.length).toEqual(1);
expect(transfers[0]).toEqual(expect.objectContaining(transfer1));
});

it('Successfully finds all transfers before or at the time', async () => {
const createdAt1 = '2000-01-01T00:00:00.000Z';
const createdAt2 = '2000-01-02T00:00:00.000Z';

const transfer1: TransferCreateObject = {
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: defaultSubaccountId2,
assetId: defaultAsset.id,
size: '100',
eventId: defaultTendermintEventId,
transactionHash: '',
createdAt: createdAt1,
createdAtHeight: createdHeight,
};

const transfer2: TransferCreateObject = {
senderSubaccountId: defaultSubaccountId,
recipientSubaccountId: defaultSubaccountId2,
assetId: defaultAsset.id,
size: '200',
eventId: defaultTendermintEventId2,
transactionHash: '',
createdAt: createdAt2,
createdAtHeight: (parseInt(createdHeight, 10) + 1).toString(),
};

await Promise.all([
TransferTable.create(transfer1),
TransferTable.create(transfer2),
]);

const { results: transfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId],
limit: 100,
createdBeforeOrAt: createdAt1,
},
[],
);

expect(transfers.length).toEqual(1);
expect(transfers[0]).toEqual(expect.objectContaining(transfer1));
});

it('Successfully returns empty results when no transfers match criteria', async () => {
const { results: transfers } = await TransferTable.findAllToOrFromParentSubaccount(
{
subaccountId: [defaultSubaccountId],
limit: 100,
},
[],
);

expect(transfers.length).toEqual(0);
});
});
});
Loading
Loading