Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
24add24
[CT-1365] Safely Handle Exceptions to TWAP Suborders (backport #3039)…
mergify[bot] Aug 12, 2025
e69ea3d
[CT-1361] Add Support for TWAP Events in the Indexer (backport #2815)…
mergify[bot] Aug 13, 2025
d1effa6
Create new instance for fee calculation (backport #3051) (#3053)
mergify[bot] Aug 22, 2025
3b0e414
Update err to log (backport #3056) (#3057)
mergify[bot] Aug 22, 2025
0e878fa
upgrade cometbft and v9.1 (backport #3082) (#3084)
mergify[bot] Sep 18, 2025
fc042e1
TEMPORARY FIX: SKIP ALL LIQUIDATIONS FOR CLOB PAIR 181 (backport #313…
mergify[bot] Oct 11, 2025
eab3f04
upgrade cosmos-sdk and cometbft for security patch GHSA-hrhf-2vcr-ghc…
mergify[bot] Oct 14, 2025
41424eb
Revert "TEMPORARY FIX: SKIP ALL LIQUIDATIONS FOR CLOB PAIR 181 (#3137…
mergify[bot] Oct 15, 2025
03a1625
Transfer Insurance Fund Payment Before Subaccount Update + e2e test (…
mergify[bot] Oct 15, 2025
df0f3a2
v9.3 upgrade (backport #3156) (#3157)
mergify[bot] Oct 15, 2025
bf7418c
fix v9.3 upgrade handler setup (backport #3159) (#3160)
mergify[bot] Oct 16, 2025
2bca3bc
Create governance messages for sliding affiliate scheme (backport #30…
mergify[bot] Oct 22, 2025
fdaa144
Rename proto fields to be a bit more clear (#3112) (#3178)
jusbar23 Oct 22, 2025
418ce42
Retroactive pr (backport #3033) (#3034)
mergify[bot] Oct 23, 2025
da70b32
Change to warn instead of error for invalid ORRS (backport #3036) (#3…
mergify[bot] Oct 23, 2025
8928b2a
Change `insert *` and `update *` to declaring specific columns (backp…
mergify[bot] Oct 23, 2025
3e9b8ac
Dont attribute new revenue if user exceeds 30d max volume and depreca…
jusbar23 Oct 23, 2025
64ca450
Integrate commission and overrides to fee tier calculation (Backport)…
jusbar23 Oct 23, 2025
d6fa308
9.4 update (backport #3166) (#3172)
mergify[bot] Oct 23, 2025
f69ddbc
Set referree tier to 2 instead of 1
jusbar23 Oct 23, 2025
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
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ proto-gen:
@echo "Generating Protobuf files"
@$(protoImage) sh ./protocol/scripts/protocgen.sh

proto-clean:
@rm -rf ./proto/.proto-export
@rm -rf ./.proto-export

proto-gen-clean:
@echo "Cleaning old artifacts"
@rm -rf ./proto/.proto-export
@rm -rf ./.proto-export
@echo "Generating Protobuf files"
@$(protoImage) sh ./protocol/scripts/protocgen.sh
@cd proto && make proto-export-v4-proto-js

proto-check-bc-breaking:
@rm -rf ./.proto-export
@$(protoImage) buf breaking --against .git#branch=$$(git merge-base HEAD origin/main)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as Knex from 'knex';

import { formatAlterTableEnumSql } from '../helpers';

export async function up(knex: Knex): Promise<void> {
await knex.schema.alterTable('orders', (table) => {
table.string('duration').nullable();
table.string('interval').nullable();
table.string('priceTolerance').nullable();
});

await knex.raw(formatAlterTableEnumSql(
'orders',
'type',
[
'LIMIT',
'MARKET',
'STOP_LIMIT',
'STOP_MARKET',
'TRAILING_STOP',
'TAKE_PROFIT',
'TAKE_PROFIT_MARKET',
'LIQUIDATED',
'LIQUIDATION',
'HARD_TRADE',
'FAILED_HARD_TRADE',
'TRANSFER_PLACEHOLDER',
'TWAP',
'TWAP_SUBORDER',
],
));

await knex.raw(formatAlterTableEnumSql(
'fills',
'type',
['LIMIT', 'LIQUIDATED', 'LIQUIDATION', 'DELEVERAGED', 'OFFSETTING', 'TWAP_SUBORDER'],
));
}

export async function down(knex: Knex): Promise<void> {
await knex.schema.alterTable('orders', (table) => {
table.dropColumn('duration');
table.dropColumn('interval');
table.dropColumn('priceTolerance');
});

await knex.raw(formatAlterTableEnumSql(
'orders',
'type',
[
'LIMIT',
'MARKET',
'STOP_LIMIT',
'STOP_MARKET',
'TRAILING_STOP',
'TAKE_PROFIT',
'TAKE_PROFIT_MARKET',
'LIQUIDATED',
'LIQUIDATION',
'HARD_TRADE',
'FAILED_HARD_TRADE',
'TRANSFER_PLACEHOLDER',
],
));

await knex.raw(formatAlterTableEnumSql(
'fills',
'type',
['LIMIT', 'LIQUIDATED', 'LIQUIDATION', 'DELEVERAGED', 'OFFSETTING'],
));
}
42 changes: 38 additions & 4 deletions indexer/packages/postgres/src/lib/protocol-translations.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { bytesToBigInt } from '@dydxprotocol-indexer/v4-proto-parser';
import {
bytesToBigInt,
ORDER_FLAG_CONDITIONAL,
ORDER_FLAG_LONG_TERM,
ORDER_FLAG_SHORT_TERM,
ORDER_FLAG_TWAP,
ORDER_FLAG_TWAP_SUBORDER,
} from '@dydxprotocol-indexer/v4-proto-parser';
import {
ClobPairStatus,
IndexerOrder,
IndexerOrder_ConditionType,
IndexerOrder_Side,
IndexerOrder_TimeInForce,
IndexerOrder_ConditionType,
ClobPairStatus,
} from '@dydxprotocol-indexer/v4-protos';
import Big from 'big.js';
import { DateTime } from 'luxon';
Expand Down Expand Up @@ -64,6 +71,9 @@ const ORDER_TYPE_TO_CONDITION_TYPE_MAP: Record<OrderType, IndexerOrder_Condition
// Unused order types
[OrderType.MARKET]: IndexerOrder_ConditionType.CONDITION_TYPE_UNSPECIFIED,
[OrderType.TRAILING_STOP]: IndexerOrder_ConditionType.CONDITION_TYPE_UNSPECIFIED,

[OrderType.TWAP]: IndexerOrder_ConditionType.CONDITION_TYPE_UNSPECIFIED,
[OrderType.TWAP_SUBORDER]: IndexerOrder_ConditionType.CONDITION_TYPE_UNSPECIFIED,
};

/**
Expand Down Expand Up @@ -318,12 +328,36 @@ export function getGoodTilBlockTime(order: IndexerOrder): IsoString | undefined
*/
export function protocolConditionTypeToOrderType(
protocolConditionType: IndexerOrder_ConditionType,
orderFlag: number = 32,
): OrderType {
if (!(protocolConditionType in CONDITION_TYPE_TO_ORDER_TYPE_MAP)) {
throw new Error(`Unexpected ConditionType: ${protocolConditionType}`);
}

return CONDITION_TYPE_TO_ORDER_TYPE_MAP[protocolConditionType];
switch (orderFlag) {
case ORDER_FLAG_SHORT_TERM:
return OrderType.LIMIT;
case ORDER_FLAG_CONDITIONAL:
switch (protocolConditionType) {
case IndexerOrder_ConditionType.UNRECOGNIZED:
case IndexerOrder_ConditionType.CONDITION_TYPE_UNSPECIFIED:
return OrderType.LIMIT;
case IndexerOrder_ConditionType.CONDITION_TYPE_STOP_LOSS:
return OrderType.STOP_LIMIT;
case IndexerOrder_ConditionType.CONDITION_TYPE_TAKE_PROFIT:
return OrderType.TAKE_PROFIT;
default:
throw new Error(`Unexpected ConditionType: ${protocolConditionType}`);
}
case ORDER_FLAG_LONG_TERM:
return OrderType.LIMIT;
case ORDER_FLAG_TWAP:
return OrderType.TWAP;
case ORDER_FLAG_TWAP_SUBORDER:
return OrderType.TWAP_SUBORDER;
default:
throw new Error(`Unexpected OrderFlags: ${orderFlag}`);
}
Comment on lines 329 to +360
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Make orderFlag explicit; audit call sites.

Defaulting orderFlag to 32 (CONDITIONAL) can misclassify orders if callers forget to pass the flag. Prefer making it required or validating non-conditional flags.

Search for callers that omit the second param:

If any exist, thread through the real orderFlags.


🏁 Script executed:

#!/bin/bash
rg -nP 'protocolConditionTypeToOrderType\s*\([^,)]*\)' --type=ts --glob 'indexer/**/*.ts' -C2

Length of output: 2804


Let me expand the search to check if production code (non-test files) also has this pattern:Now let me search for production code calls only:


🏁 Script executed:

#!/bin/bash
rg -nP 'protocolConditionTypeToOrderType\s*\([^,)]*\)' --type=ts -g '!**/test/**' -g '!**/__tests__/**' --glob 'indexer/**/*.ts' -C2

Length of output: 148


Let me try a broader search approach:


🏁 Script executed:

#!/bin/bash
# Search for all calls to protocolConditionTypeToOrderType
rg -nP 'protocolConditionTypeToOrderType\s*\(' --type=ts -C2 | grep -v '__tests__\|\.test\.ts'

Length of output: 1488


Let me examine the context around these production call sites to determine if they have access to orderFlag:


🏁 Script executed:

#!/bin/bash
# Check order-remove-handler.ts context
echo "=== order-remove-handler.ts context ===" && \
sed -n '680,695p' git/indexer/services/vulcan/src/handlers/order-remove-handler.ts && \
echo "" && \
echo "=== websocket-helper.ts context ===" && \
sed -n '65,85p' git/indexer/packages/kafka/src/websocket-helper.ts

Length of output: 147


Let me find the correct file paths:


🏁 Script executed:

#!/bin/bash
# Find the correct paths
fd -type f 'order-remove-handler.ts' && \
fd -type f 'websocket-helper.ts'

Length of output: 170


Let me fix the search syntax:


🏁 Script executed:

#!/bin/bash
# Find the correct paths using correct fd syntax
fd 'order-remove-handler.ts' && \
fd 'websocket-helper.ts'

Length of output: 107


Now let me examine the context around these call sites:


🏁 Script executed:

#!/bin/bash
# Check order-remove-handler.ts context around line 689
echo "=== order-remove-handler.ts context (lines 680-700) ===" && \
sed -n '680,700p' indexer/services/vulcan/src/handlers/order-remove-handler.ts && \
echo "" && \
echo "=== websocket-helper.ts context (lines 60-85) ===" && \
sed -n '60,85p' indexer/packages/kafka/src/websocket-helper.ts

Length of output: 2556


Thread actual orderFlags through call sites; don't rely on default.

Found 2 production call sites that omit the orderFlag parameter despite having access to the actual orderFlags:

  • indexer/services/vulcan/src/handlers/order-remove-handler.ts line 689: Should pass redisOrder.order!.orderId!.orderFlags
  • indexer/packages/kafka/src/websocket-helper.ts line 75: Should pass redisOrder.order!.orderId!.orderFlags

Both currently use the default 32 (CONDITIONAL), which can misclassify orders. Update these calls to pass the actual orderFlags value as the second argument.

🤖 Prompt for AI Agents
In indexer/packages/postgres/src/lib/protocol-translations.ts around lines 329
to 360, the protocolConditionTypeToOrderType function accepts an orderFlag but
callers are relying on its default (32) which can misclassify orders; update the
two production call sites to pass the actual orderFlags value: in
indexer/services/vulcan/src/handlers/order-remove-handler.ts at line ~689, pass
redisOrder.order!.orderId!.orderFlags as the second argument; and in
indexer/packages/kafka/src/websocket-helper.ts at line ~75, pass
redisOrder.order!.orderId!.orderFlags as the second argument; keep existing
behavior for null/undefined orderFlags only if handled elsewhere, otherwise
propagate the raw value through to this function.

}

/**
Expand Down
16 changes: 16 additions & 0 deletions indexer/packages/postgres/src/models/order-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ export default class OrderModel extends BaseModel {
'triggerPrice',
'updatedAt',
'updatedAtHeight',
'orderRouterAddress',
'duration',
'interval',
'priceTolerance',
],
properties: {
id: { type: 'string', format: 'uuid' },
Expand All @@ -99,6 +103,9 @@ export default class OrderModel extends BaseModel {
builderAddress: { type: ['string', 'null'], default: null },
feePpm: { type: ['string', 'null'], default: null },
orderRouterAddress: { type: ['string', 'null'], default: null },
duration: { type: ['string', 'null'], default: null, pattern: NonNegativeNumericPattern },
interval: { type: ['string', 'null'], default: null, pattern: NonNegativeNumericPattern },
priceTolerance: { type: ['string', 'null'], default: null, pattern: NonNegativeNumericPattern },
},
};
}
Expand Down Expand Up @@ -131,6 +138,9 @@ export default class OrderModel extends BaseModel {
triggerPrice: 'string',
updatedAt: 'date-time',
updatedAtHeight: 'string',
duration: 'string',
interval: 'string',
priceTolerance: 'string',
builderAddress: 'string',
feePpm: 'string',
orderRouterAddress: 'string',
Expand Down Expand Up @@ -184,4 +194,10 @@ export default class OrderModel extends BaseModel {
feePpm?: string;

orderRouterAddress?: string;

duration?: string;

interval?: string;

priceTolerance?: string;
}
4 changes: 4 additions & 0 deletions indexer/packages/postgres/src/types/db-model-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export interface OrderFromDatabase extends IdBasedModelFromDatabase {
builderAddress?: string,
feePpm?: string,
orderRouterAddress?: string,
// these fields only exist for twap orders
duration?: string,
interval?: string,
priceTolerance?: string,
}

export interface PerpetualMarketFromDatabase {
Expand Down
2 changes: 2 additions & 0 deletions indexer/packages/postgres/src/types/fill-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export enum FillType {
// OFFSETTING is for the offsetting subaccount in a deleveraging event.
// The fill type will be set to maker.
OFFSETTING = 'OFFSETTING',
// TWAP is for a TWAP fill.
TWAP_SUBORDER = 'TWAP_SUBORDER',
}

export interface FillCreateObject {
Expand Down
12 changes: 12 additions & 0 deletions indexer/packages/postgres/src/types/order-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export enum OrderStatus {
CANCELED = 'CANCELED',
BEST_EFFORT_CANCELED = 'BEST_EFFORT_CANCELED',
UNTRIGGERED = 'UNTRIGGERED',
ERROR = 'ERROR',
}

export enum OrderType {
Expand All @@ -23,6 +24,8 @@ export enum OrderType {
TRAILING_STOP = 'TRAILING_STOP',
TAKE_PROFIT = 'TAKE_PROFIT',
TAKE_PROFIT_MARKET = 'TAKE_PROFIT_MARKET',
TWAP = 'TWAP',
TWAP_SUBORDER = 'TWAP_SUBORDER',
}

export enum TimeInForce {
Expand Down Expand Up @@ -66,6 +69,9 @@ export interface OrderCreateObject {
builderAddress?: string,
feePpm?: string,
orderRouterAddress?: string,
duration?: string,
interval?: string,
priceTolerance?: string,
}

export interface OrderUpdateObject {
Expand All @@ -87,6 +93,9 @@ export interface OrderUpdateObject {
clientMetadata?: string,
triggerPrice?: string,
orderRouterAddress?: string,
duration?: string | null,
interval?: string | null,
priceTolerance?: string | null,
}

export enum OrderColumns {
Expand All @@ -112,4 +121,7 @@ export enum OrderColumns {
createdAtHeight = 'createdAtHeight',
clientMetadata = 'clientMetadata',
triggerPrice = 'triggerPrice',
duration = 'duration',
interval = 'interval',
priceTolerance = 'priceTolerance',
}
4 changes: 4 additions & 0 deletions indexer/packages/postgres/src/types/trade-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export enum TradeType {
LIQUIDATED = 'LIQUIDATED',
// DELEVERAGED is the trade type for a fill with a deleveraged taker order.
DELEVERAGED = 'DELEVERAGED',
// TWAP_SUBORDER is the trade type for a fill with a twap suborder.
TWAP_SUBORDER = 'TWAP_SUBORDER',
}

export function fillTypeToTradeType(fillType: FillType): TradeType {
Expand All @@ -17,6 +19,8 @@ export function fillTypeToTradeType(fillType: FillType): TradeType {
return TradeType.LIQUIDATED;
case FillType.DELEVERAGED:
return TradeType.DELEVERAGED;
case FillType.TWAP_SUBORDER:
return TradeType.TWAP_SUBORDER;
default:
throw new Error(`Unknown fill type: ${fillType}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ export interface OrderSubaccountMessageContents {
// This will only be set for stateful orders
createdAtHeight?: string,
clientMetadata?: string,
// This will only be set for twap orders
duration?: string,
interval?: string,
priceTolerance?: string,
}

export interface FillSubaccountMessageContents {
Expand Down
2 changes: 2 additions & 0 deletions indexer/packages/v4-proto-parser/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
export const ORDER_FLAG_SHORT_TERM: number = 0;
export const ORDER_FLAG_LONG_TERM: number = 64;
export const ORDER_FLAG_CONDITIONAL: number = 32;
export const ORDER_FLAG_TWAP: number = 128;
export const ORDER_FLAG_TWAP_SUBORDER: number = 256;
2 changes: 1 addition & 1 deletion indexer/packages/v4-protos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"build:prod": "rm -rf build/ && tsc",
"build:watch": "pnpm run build -- --watch",
"test": "echo \"Error: no test specified\"",
"build:proto": "(cd ../../.. && make proto-export) && rm -rf src/codegen && telescope transpile --protoDirs ../../../.proto-export --outPath ./src/codegen --no-includeAminos --includeLCDClients --includeRPCClients",
"build:proto": "(cd ../../../proto && rm -rf .proto-export && cd ../ && rm -rf .proto-export && make proto-export) && rm -rf src/codegen && telescope transpile --protoDirs ../../../.proto-export --outPath ./src/codegen --no-includeAminos --includeLCDClients --includeRPCClients",
"build:verify-proto": "pnpm run build:proto && git diff --exit-code src/codegen",
"postinstall": "patch-package"
},
Expand Down
Loading