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

feat: abacus-ts calculations flow #1365

Draft
wants to merge 13 commits into
base: tu/abacus-ts-types
Choose a base branch
from
21 changes: 21 additions & 0 deletions src/abacus-ts/calculators/blockRewards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IndexerHistoricalBlockTradingReward } from '@/types/indexer/indexerApiGen';
import { keyBy, maxBy } from 'lodash';

import { MustBigNumber } from '@/lib/numbers';

import { Loadable } from '../lib/loadable';
import { mapLoadableData } from '../lib/mapLoadable';
import { mergeObjects } from '../lib/mergeObjects';

function calculateBlockRewards(

Check failure on line 10 in src/abacus-ts/calculators/blockRewards.ts

View workflow job for this annotation

GitHub Actions / lint

'calculateBlockRewards' is defined but never used
liveTransfers: Loadable<IndexerHistoricalBlockTradingReward[]>,
restTransfers: Loadable<IndexerHistoricalBlockTradingReward[]>
) {
const getRewardsById = (data: Loadable<IndexerHistoricalBlockTradingReward[]>) =>
mapLoadableData(data, (d) => keyBy(d, (reward) => reward.createdAtHeight));
return mergeObjects(
getRewardsById(liveTransfers).data ?? {},
getRewardsById(restTransfers).data ?? {},
(first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())!
);
}
21 changes: 21 additions & 0 deletions src/abacus-ts/calculators/fills.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IndexerCompositeFillObject } from '@/types/indexer/indexerManual';
import { keyBy, maxBy } from 'lodash';

import { MustBigNumber } from '@/lib/numbers';

import { Loadable } from '../lib/loadable';
import { mapLoadableData } from '../lib/mapLoadable';
import { mergeObjects } from '../lib/mergeObjects';

function calculateFills(

Check failure on line 10 in src/abacus-ts/calculators/fills.ts

View workflow job for this annotation

GitHub Actions / lint

'calculateFills' is defined but never used
liveFills: Loadable<IndexerCompositeFillObject[]>,
restFills: Loadable<IndexerCompositeFillObject[]>
) {
const getFillsById = (data: Loadable<IndexerCompositeFillObject[]>) =>
mapLoadableData(data, (d) => keyBy(d, (fill) => fill.id ?? ''));
return mergeObjects(
getFillsById(liveFills).data ?? {},
getFillsById(restFills).data ?? {},
(first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())!
);
}
130 changes: 130 additions & 0 deletions src/abacus-ts/calculators/orders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { IndexerBestEffortOpenedStatus, IndexerOrderStatus } from '@/types/indexer/indexerApiGen';
import { IndexerCompositeOrderObject } from '@/types/indexer/indexerManual';
import { maxBy, pickBy } from 'lodash';

import { SubaccountOrder } from '@/constants/abacus';

import { assertNever } from '@/lib/assertNever';
import { MustBigNumber } from '@/lib/numbers';

import { Loadable } from '../lib/loadable';
import { mapLoadableData } from '../lib/mapLoadable';
import { mergeObjects } from '../lib/mergeObjects';
import { OrdersData } from '../rawTypes';
import { OrderStatus } from '../summaryTypes';

// todo these are calculating the same thing twice pasically
function calculateOpenOrders(liveOrders: Loadable<OrdersData>, restOrders: Loadable<OrdersData>) {

Check failure on line 17 in src/abacus-ts/calculators/orders.ts

View workflow job for this annotation

GitHub Actions / lint

'calculateOpenOrders' is defined but never used
const getOpenOrders = (data: Loadable<OrdersData>) =>
mapLoadableData(data, (d) =>
pickBy(
d,
(order) =>
getSimpleOrderStatus(calculateOrderStatus(order) ?? OrderStatus.Open) === OrderStatus.Open
)
);
return calculateMergedOrders(getOpenOrders(liveOrders), getOpenOrders(restOrders));
}

function calculateOrderHistory(liveOrders: Loadable<OrdersData>, restOrders: Loadable<OrdersData>) {

Check failure on line 29 in src/abacus-ts/calculators/orders.ts

View workflow job for this annotation

GitHub Actions / lint

'calculateOrderHistory' is defined but never used
const getNonOpenOrders = (data: Loadable<OrdersData>) =>
mapLoadableData(data, (d) =>
pickBy(
d,
(order) =>
getSimpleOrderStatus(calculateOrderStatus(order) ?? OrderStatus.Open) !== OrderStatus.Open
)
);
return calculateMergedOrders(getNonOpenOrders(liveOrders), getNonOpenOrders(restOrders));
}

function calculateSubaccountOrder(

Check failure on line 41 in src/abacus-ts/calculators/orders.ts

View workflow job for this annotation

GitHub Actions / lint

'calculateSubaccountOrder' is defined but never used
order: IndexerCompositeOrderObject,

Check failure on line 42 in src/abacus-ts/calculators/orders.ts

View workflow job for this annotation

GitHub Actions / lint

'order' is defined but never used. Allowed unused args must match /^_/u
protocolHeight: number

Check failure on line 43 in src/abacus-ts/calculators/orders.ts

View workflow job for this annotation

GitHub Actions / lint

'protocolHeight' is defined but never used. Allowed unused args must match /^_/u
): SubaccountOrder {}

function getSimpleOrderStatus(status: OrderStatus) {
switch (status) {
case OrderStatus.Open:
case OrderStatus.Pending:
case OrderStatus.PartiallyFilled:
case OrderStatus.Untriggered:
case OrderStatus.Canceling:
return OrderStatus.Open;
case OrderStatus.Canceled:
case OrderStatus.PartiallyCanceled:
return OrderStatus.Canceled;
case OrderStatus.Filled:
return OrderStatus.Filled;
default:
assertNever(status);
// should never happen since we made OrderStatus manually
return OrderStatus.Open;
}
}

function calculateBaseOrderStatus(order: IndexerCompositeOrderObject): OrderStatus | undefined {

Check failure on line 66 in src/abacus-ts/calculators/orders.ts

View workflow job for this annotation

GitHub Actions / lint

'calculateBaseOrderStatus' is defined but never used
const status = order.status;
if (status == null) {
return undefined;
}

if (status === IndexerBestEffortOpenedStatus.BESTEFFORTOPENED) {
return OrderStatus.Pending;
}

// Calculate filled amounts
const size = MustBigNumber(order.size);
const totalFilled = MustBigNumber(order.totalFilled);
const remainingSize = size.minus(totalFilled);
const hasPartialFill = totalFilled.gt(0) && remainingSize.gt(0);

// Handle partial fills
if (hasPartialFill) {
if (status === IndexerOrderStatus.OPEN) {
return OrderStatus.PartiallyFilled;
}
if (status === IndexerOrderStatus.CANCELED) {
return OrderStatus.PartiallyCanceled;
}
}

// Handle short-term order edge case
const isShortTermOrder = order.orderFlags === '0';
const isBestEffortCanceled = status === IndexerOrderStatus.BESTEFFORTCANCELED;
const isUserCanceled =
order.removalReason === 'USER_CANCELED' ||
order.removalReason === 'ORDER_REMOVAL_REASON_USER_CANCELED';

if (isShortTermOrder && isBestEffortCanceled && !isUserCanceled) {
return OrderStatus.Pending;
}

// Direct mapping for remaining cases
switch (status) {
case IndexerOrderStatus.OPEN:
return OrderStatus.Open;
case IndexerOrderStatus.FILLED:
return OrderStatus.Filled;
case IndexerOrderStatus.CANCELED:
return OrderStatus.Canceled;
case IndexerOrderStatus.BESTEFFORTCANCELED:
return OrderStatus.Canceling;
case IndexerOrderStatus.UNTRIGGERED:
return OrderStatus.Untriggered;
default:
assertNever(status);
return undefined;
}
}

function calculateMergedOrders(liveOrders: Loadable<OrdersData>, restOrders: Loadable<OrdersData>) {
const liveData = liveOrders.data ?? {};
const restData = restOrders.data ?? {};
return mergeObjects(
liveData,
restData,
(a, b) =>
maxBy([a, b], (o) => MustBigNumber(o.updatedAtHeight ?? o.createdAtHeight).toNumber())!
);
}
Loading
Loading