Skip to content

Commit

Permalink
Revert "Emergency patch to handle invalid TimeInForce. (#942)"
Browse files Browse the repository at this point in the history
This reverts commit 7a027e4.
  • Loading branch information
dydxwill committed Jan 9, 2024
1 parent 7a027e4 commit eee6900
Show file tree
Hide file tree
Showing 4 changed files with 5 additions and 223 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,6 @@ describe('protocolTranslations', () => {
['IOC', IndexerOrder_TimeInForce.TIME_IN_FORCE_IOC, TimeInForce.IOC],
['UNSPECIFIED', IndexerOrder_TimeInForce.TIME_IN_FORCE_UNSPECIFIED, TimeInForce.GTT],
['POST_ONLY', IndexerOrder_TimeInForce.TIME_IN_FORCE_POST_ONLY, TimeInForce.POST_ONLY],
// Test case for emergency patch
['INVALID', (100 as IndexerOrder_TimeInForce), TimeInForce.GTT],
])('successfully gets TimeInForce given protocol order TIF: %s', (
_name: string,
protocolTIF: IndexerOrder_TimeInForce,
Expand All @@ -178,14 +176,13 @@ describe('protocolTranslations', () => {
expect(protocolOrderTIFToTIF(protocolTIF)).toEqual(expectedTimeInForce);
});

// Commented out for emergency patch
/* it('throws error if unrecognized protocolTIF given', () => {
it('throws error if unrecognized protocolTIF given', () => {
expect(
() => {
protocolOrderTIFToTIF(100 as IndexerOrder_TimeInForce);
},
).toThrow(new Error('Unexpected TimeInForce from protocol: 100'));
});*/
});
});

describe('tifToProtocolOrderTIF', () => {
Expand Down
4 changes: 1 addition & 3 deletions indexer/packages/postgres/src/lib/protocol-translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,7 @@ export function protocolOrderTIFToTIF(
protocolOrderTIF: IndexerOrder_TimeInForce,
): TimeInForce {
if (!(protocolOrderTIF in PROTOCOL_TIF_TO_INDEXER_TIF_MAP)) {
return TimeInForce.GTT;
// Removed for emergency patch
// throw new Error(`Unexpected TimeInForce from protocol: ${protocolOrderTIF}`);
throw new Error(`Unexpected TimeInForce from protocol: ${protocolOrderTIF}`);
}

return PROTOCOL_TIF_TO_INDEXER_TIF_MAP[protocolOrderTIF];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1451,223 +1451,12 @@ describe('OrderHandler', () => {
]);
});

// Testing emergency patch
it('handles invalid TimeInForce (%s)', async () => {
const transactionIndex: number = 0;
const eventIndex: number = 0;
const makerQuantums: number = 100;
const makerSubticks: number = 1_000_000;

const makerOrderProto: IndexerOrder = createOrder({
subaccountId: defaultSubaccountId,
clientId: 0,
side: IndexerOrder_Side.SIDE_BUY,
quantums: makerQuantums,
subticks: makerSubticks,
goodTilOneof: {
goodTilBlock: 10,
},
clobPairId: testConstants.defaultPerpetualMarket3.clobPairId,
orderFlags: ORDER_FLAG_SHORT_TERM.toString(),
// Invalid TIF
timeInForce: (4 as IndexerOrder_TimeInForce),
reduceOnly: false,
clientMetadata: 0,
});

const takerSubticks: number = 150_000;
const takerQuantums: number = 10;
const takerOrderProto: IndexerOrder = createOrder({
subaccountId: defaultSubaccountId2,
clientId: 0,
side: IndexerOrder_Side.SIDE_SELL,
quantums: takerQuantums,
subticks: takerSubticks,
goodTilOneof: {
goodTilBlock: 10,
},
clobPairId: testConstants.defaultPerpetualMarket3.clobPairId,
orderFlags: ORDER_FLAG_LONG_TERM.toString(),
// Invalid TIF
timeInForce: (17 as IndexerOrder_TimeInForce),
reduceOnly: true,
clientMetadata: 0,
});

// create initial PerpetualPositions with closed previous positions
await Promise.all([
// previous position for subaccount 1
PerpetualPositionTable.create({
...defaultPerpetualPosition,
perpetualId: testConstants.defaultPerpetualMarket3.id,
createdAtHeight: '1',
size: '0',
status: PerpetualPositionStatus.CLOSED,
openEventId: testConstants.defaultTendermintEventId2,
}),
// previous position for subaccount 2
PerpetualPositionTable.create({
...defaultPerpetualPosition,
perpetualId: testConstants.defaultPerpetualMarket3.id,
subaccountId: testConstants.defaultSubaccountId2,
createdAtHeight: '1',
size: '0',
status: PerpetualPositionStatus.CLOSED,
openEventId: testConstants.defaultTendermintEventId2,
}),
// initial position for subaccount 2
PerpetualPositionTable.create({
...defaultPerpetualPosition,
perpetualId: testConstants.defaultPerpetualMarket3.id,
}),
PerpetualPositionTable.create({
...defaultPerpetualPosition,
perpetualId: testConstants.defaultPerpetualMarket3.id,
subaccountId: testConstants.defaultSubaccountId2,
}),
]);

const fillAmount: number = 10;
const orderFillEvent: OrderFillEventV1 = createOrderFillEvent(
makerOrderProto,
takerOrderProto,
fillAmount,
fillAmount,
fillAmount,
);
const kafkaMessage: KafkaMessage = createKafkaMessageFromOrderFillEvent({
orderFillEvent,
transactionIndex,
eventIndex,
height: parseInt(defaultHeight, 10),
time: defaultTime,
txHash: defaultTxHash,
});

const producerSendMock: jest.SpyInstance = jest.spyOn(producer, 'send');
await onMessage(kafkaMessage);

// This price should be in fixed-point notation rather than exponential notation (1e-8)
const makerOrderSize: string = '1'; // quantums in human = 1e2 * 1e-2 = 1
const makerPrice: string = '0.00000000000001'; // quote currency / base currency = 1e6 * 1e-16 * 1e-6 / 1e-2 = 1e-14
const takerPrice: string = '0.0000000000000015'; // quote currency / base currency = 1.5e5 * 1e-16 * 1e-6 / 1e-2 = 1.5e-15
const totalFilled: string = '0.1'; // fillAmount in human = 1e1 * 1e-2 = 1e-1
await expectOrderInDatabase({
subaccountId: testConstants.defaultSubaccountId,
clientId: '0',
size: makerOrderSize,
totalFilled,
price: makerPrice,
status: OrderStatus.OPEN, // orderSize > totalFilled so status is open
clobPairId: testConstants.defaultPerpetualMarket3.clobPairId,
side: protocolTranslations.protocolOrderSideToOrderSide(makerOrderProto.side),
orderFlags: makerOrderProto.orderId!.orderFlags.toString(),
// Invalid TIF in order is treated as GTT
timeInForce: TimeInForce.GTT,
reduceOnly: false,
goodTilBlock: protocolTranslations.getGoodTilBlock(makerOrderProto)?.toString(),
goodTilBlockTime: protocolTranslations.getGoodTilBlockTime(makerOrderProto),
clientMetadata: makerOrderProto.clientMetadata.toString(),
updatedAt: defaultDateTime.toISO(),
updatedAtHeight: defaultHeight.toString(),
});

const takerOrderSize: string = '0.1'; // quantums in human = 1e1 * 1e-2 = 1e-1
await expectOrderInDatabase({
subaccountId: testConstants.defaultSubaccountId2,
clientId: '0',
size: takerOrderSize,
totalFilled,
price: takerPrice,
status: OrderStatus.FILLED, // orderSize == totalFilled so status is filled
clobPairId: testConstants.defaultPerpetualMarket3.clobPairId,
side: protocolTranslations.protocolOrderSideToOrderSide(takerOrderProto.side),
orderFlags: takerOrderProto.orderId!.orderFlags.toString(),
// Invalid TIF in order is treated as GTT
timeInForce: TimeInForce.GTT,
reduceOnly: true,
goodTilBlock: protocolTranslations.getGoodTilBlock(takerOrderProto)?.toString(),
goodTilBlockTime: protocolTranslations.getGoodTilBlockTime(takerOrderProto),
clientMetadata: takerOrderProto.clientMetadata.toString(),
updatedAt: defaultDateTime.toISO(),
updatedAtHeight: defaultHeight.toString(),
});

const eventId: Buffer = TendermintEventTable.createEventId(
defaultHeight,
transactionIndex,
eventIndex,
);

const quoteAmount: string = '0.000000000000001'; // quote amount is price * fillAmount = 1e-14 * 1e-1 = 1e-15
await expectFillInDatabase({
subaccountId: testConstants.defaultSubaccountId,
clientId: '0',
liquidity: Liquidity.MAKER,
size: totalFilled,
price: makerPrice,
quoteAmount,
eventId,
transactionHash: defaultTxHash,
createdAt: defaultDateTime.toISO(),
createdAtHeight: defaultHeight,
type: FillType.LIMIT,
clobPairId: testConstants.defaultPerpetualMarket3.clobPairId,
side: protocolTranslations.protocolOrderSideToOrderSide(makerOrderProto.side),
orderFlags: makerOrderProto.orderId!.orderFlags.toString(),
clientMetadata: makerOrderProto.clientMetadata.toString(),
fee: defaultMakerFee,
});
await expectFillInDatabase({
subaccountId: testConstants.defaultSubaccountId2,
clientId: '0',
liquidity: Liquidity.TAKER,
size: totalFilled,
price: makerPrice,
quoteAmount,
eventId,
transactionHash: defaultTxHash,
createdAt: defaultDateTime.toISO(),
createdAtHeight: defaultHeight,
type: FillType.LIMIT,
clobPairId: testConstants.defaultPerpetualMarket3.clobPairId,
side: protocolTranslations.protocolOrderSideToOrderSide(takerOrderProto.side),
orderFlags: takerOrderProto.orderId!.orderFlags.toString(),
clientMetadata: takerOrderProto.clientMetadata.toString(),
fee: defaultTakerFee,
});

await Promise.all([
expectDefaultOrderAndFillSubaccountKafkaMessages(
producerSendMock,
eventId,
ORDER_FLAG_SHORT_TERM,
ORDER_FLAG_LONG_TERM,
testConstants.defaultPerpetualMarket3.id,
testConstants.defaultPerpetualMarket3.clobPairId,
),
expectDefaultTradeKafkaMessageFromTakerFillId(
producerSendMock,
eventId,
),
expectCandlesUpdated(),
expectStateFilledQuantums(
OrderTable.orderIdToUuid(makerOrderProto.orderId!),
orderFillEvent.totalFilledMaker.toString(),
),
expectStateFilledQuantums(
OrderTable.orderIdToUuid(takerOrderProto.orderId!),
orderFillEvent.totalFilledTaker.toString(),
),
]);
});

it.each([
[
undefined, // no maker order
],
[
IndexerOrder.fromPartial({
IndexerOrder.fromPartial({ // no orderId
orderId: undefined,
side: IndexerOrder_Side.SIDE_BUY,
quantums: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ BEGIN
WHEN '1'::jsonb THEN RETURN 'IOC'; /** TIME_IN_FORCE_IOC */
WHEN '2'::jsonb THEN RETURN 'POST_ONLY'; /** TIME_IN_FORCE_POST_ONLY */
WHEN '3'::jsonb THEN RETURN 'FOK'; /** TIME_IN_FORCE_FILL_OR_KILL */
ELSE RETURN 'GTT';
-- Removed for an emergency patch
-- ELSE RAISE EXCEPTION 'Unexpected TimeInForce from protocol %', tif;
ELSE RAISE EXCEPTION 'Unexpected TimeInForce from protocol %', tif;
END CASE;
END;
$$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;

0 comments on commit eee6900

Please sign in to comment.