Skip to content

Commit

Permalink
Merge pull request #347 from drift-labs/sina/trigger-and-fill
Browse files Browse the repository at this point in the history
  • Loading branch information
SinaKhalili authored Jan 23, 2025
2 parents 2794afb + cc6d3c8 commit 82bac7b
Show file tree
Hide file tree
Showing 5 changed files with 326 additions and 94 deletions.
113 changes: 99 additions & 14 deletions src/bots/filler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import {
QUOTE_PRECISION,
ClockSubscriber,
DriftEnv,
OraclePriceData,
StateAccount,
getUserStatsAccountPublicKey,
PositionDirection,
PerpMarkets,
} from '@drift-labs/sdk';
import { Mutex, tryAcquire, E_ALREADY_LOCKED } from 'async-mutex';
Expand Down Expand Up @@ -97,6 +101,7 @@ import { LRUCache } from 'lru-cache';
import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes';
import { PythPriceFeedSubscriber } from '../pythPriceFeedSubscriber';
import { TxThreaded } from './common/txThreaded';
import { NodeToTriggerWithMakers } from '../experimental-bots/filler-common/types';
import { PythLazerSubscriber } from '../pythLazerSubscriber';

const TX_COUNT_COOLDOWN_ON_BURST = 10; // send this many tx before resetting burst mode
Expand All @@ -118,6 +123,7 @@ export const CACHED_BLOCKHASH_OFFSET = 5;
const DUMP_TXS_IN_SIM = false;

const EXPIRE_ORDER_BUFFER_SEC = 60; // add extra time before trying to expire orders (want to avoid 6252 error due to clock drift)
const NUM_MAKERS = 4; // number of makers to pull for triggerable orders

const errorCodesToSuppress = [
6004, // 0x1774 Error Number: 6004. Error Message: SufficientCollateral.
Expand Down Expand Up @@ -775,7 +781,7 @@ export class FillerBot extends TxThreaded implements Bot {
dlob: DLOB
): {
nodesToFill: Array<NodeToFill>;
nodesToTrigger: Array<NodeToTrigger>;
nodesToTrigger: Array<NodeToTriggerWithMakers>;
} {
const marketIndex = market.marketIndex;

Expand All @@ -786,6 +792,14 @@ export class FillerBot extends TxThreaded implements Bot {
const vBid = calculateBidPrice(market, oraclePriceData);

const fillSlot = this.getMaxSlot();
const nodesToTrigger = this.findTriggerableNodesWithMakers(
dlob,
marketIndex,
fillSlot,
oraclePriceData,
MarketType.PERP,
this.driftClient.getStateAccount()
);

return {
nodesToFill: dlob.findNodesToFill(
Expand All @@ -799,13 +813,7 @@ export class FillerBot extends TxThreaded implements Bot {
this.driftClient.getStateAccount(),
this.driftClient.getPerpMarketAccount(marketIndex)!
),
nodesToTrigger: dlob.findNodesToTrigger(
marketIndex,
fillSlot,
oraclePriceData.price,
MarketType.PERP,
this.driftClient.getStateAccount()
),
nodesToTrigger,
};
}

Expand Down Expand Up @@ -1881,10 +1889,10 @@ export class FillerBot extends TxThreaded implements Bot {

protected filterPerpNodesForMarket(
fillableNodes: Array<NodeToFill>,
triggerableNodes: Array<NodeToTrigger>
triggerableNodes: Array<NodeToTriggerWithMakers>
): {
filteredFillableNodes: Array<NodeToFill>;
filteredTriggerableNodes: Array<NodeToTrigger>;
filteredTriggerableNodes: Array<NodeToTriggerWithMakers>;
} {
const seenFillableNodes = new Set<string>();
const filteredFillableNodes = fillableNodes.filter((node) => {
Expand Down Expand Up @@ -1920,7 +1928,7 @@ export class FillerBot extends TxThreaded implements Bot {
}

protected async executeTriggerablePerpNodesForMarket(
triggerableNodes: Array<NodeToTrigger>,
triggerableNodes: Array<NodeToTriggerWithMakers>,
buildForBundle: boolean
) {
for (const nodeToTrigger of triggerableNodes) {
Expand All @@ -1929,9 +1937,11 @@ export class FillerBot extends TxThreaded implements Bot {
nodeToTrigger.node.userAccount.toString()
);
logger.info(
`trying to trigger (account: ${nodeToTrigger.node.userAccount.toString()}, slot: ${
`Processing node: account=${nodeToTrigger.node.userAccount.toString()}, slot=${
user.slot
}) order ${nodeToTrigger.node.order.orderId.toString()}`
}, orderId=${nodeToTrigger.node.order.orderId.toString()}, numMakers=${
nodeToTrigger.makers?.length ?? 0
}`
);

const nodeSignature = getNodeToTriggerSignature(nodeToTrigger);
Expand Down Expand Up @@ -1970,6 +1980,36 @@ export class FillerBot extends TxThreaded implements Bot {
)
);

logger.info(`Triggrable node has ${nodeToTrigger.makers.length} makers`);
const makerInfos = await Promise.all(
nodeToTrigger.makers.map(async (m) => {
const maker = new PublicKey(m);
logger.info(`Getting maker info for ${maker.toString()}`);
const { data } = await this.getUserAccountAndSlotFromMap(
maker.toString()
);
const makerUserAccount = data;
const makerAuthority = makerUserAccount.authority;
const makerStats = getUserStatsAccountPublicKey(
this.driftClient.program.programId,
makerAuthority
);
return {
maker,
makerStats,
makerUserAccount,
};
})
);

const fillIx = await this.driftClient.getFillPerpOrderIx(
new PublicKey(nodeToTrigger.node.userAccount),
user.data,
nodeToTrigger.node.order,
makerInfos
);
ixs.push(fillIx);

if (this.revertOnFailure) {
ixs.push(await this.driftClient.getRevertFillIx());
}
Expand Down Expand Up @@ -2296,6 +2336,51 @@ export class FillerBot extends TxThreaded implements Bot {
return true;
}

public findTriggerableNodesWithMakers(
dlob: DLOB,
marketIndex: number,
slot: number,
oraclePriceData: OraclePriceData,
marketType: MarketType,
stateAccount: StateAccount
): NodeToTriggerWithMakers[] {
const baseTriggerable = dlob.findNodesToTrigger(
marketIndex,
slot,
oraclePriceData.price,
marketType,
stateAccount
);
if (baseTriggerable.length > 0) {
logger.info(
`Found ${baseTriggerable.length} nodes to trigger for market ${marketIndex}`
);
}

const triggerWithMaker: NodeToTriggerWithMakers[] = [];

for (const nodeObj of baseTriggerable) {
const order = nodeObj.node.order;

const makers = dlob.getBestMakers({
marketIndex,
marketType,
direction: isVariant(order.direction, 'long')
? PositionDirection.SHORT
: PositionDirection.LONG,
slot,
oraclePriceData,
numMakers: NUM_MAKERS,
});
triggerWithMaker.push({
...nodeObj,
makers,
});
}

return triggerWithMaker;
}

protected async tryFill() {
const startTime = Date.now();
let ran = false;
Expand Down Expand Up @@ -2325,7 +2410,7 @@ export class FillerBot extends TxThreaded implements Bot {

// 1) get all fillable nodes
let fillableNodes: Array<NodeToFill> = [];
let triggerableNodes: Array<NodeToTrigger> = [];
let triggerableNodes: Array<NodeToTriggerWithMakers> = [];
for (const market of this.driftClient.getPerpMarketAccounts()) {
try {
const { nodesToFill, nodesToTrigger } = this.getPerpNodesForMarket(
Expand Down
72 changes: 59 additions & 13 deletions src/experimental-bots/filler-common/dlobBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
UserAccount,
isVariant,
decodeUser,
NodeToTrigger,
Wallet,
PhoenixSubscriber,
BN,
Expand All @@ -27,6 +26,8 @@ import {
PositionDirection,
UserStatus,
isUserProtectedMaker,
OraclePriceData,
StateAccount,
} from '@drift-labs/sdk';
import { Connection, PublicKey } from '@solana/web3.js';
import dotenv from 'dotenv';
Expand All @@ -37,6 +38,7 @@ import {
SerializedNodeToFill,
SerializedNodeToTrigger,
NodeToFillWithContext,
NodeToTriggerWithMakers,
} from './types';
import {
getDriftClientFromArgs,
Expand All @@ -47,6 +49,7 @@ import { initializeSpotFulfillmentAccounts, sleepMs } from '../../utils';
import { LRUCache } from 'lru-cache';

const EXPIRE_ORDER_BUFFER_SEC = 30; // add an extra 30 seconds before trying to expire orders (want to avoid 6252 error due to clock drift)
const NUM_MAKERS = 3; // number of makers to consider for triggerable nodes

const logPrefix = '[DLOBBuilder]';
class DLOBBuilder {
Expand Down Expand Up @@ -259,14 +262,14 @@ class DLOBBuilder {

public getNodesToTriggerAndNodesToFill(): [
NodeToFillWithContext[],
NodeToTrigger[],
NodeToTriggerWithMakers[],
] {
const dlob = this.build();
const nodesToFill: NodeToFillWithContext[] = [];
const nodesToTrigger: NodeToTrigger[] = [];
const nodesToTrigger: NodeToTriggerWithMakers[] = [];
for (const marketIndex of this.marketIndexes) {
let market;
let oraclePriceData;
let oraclePriceData: OraclePriceData;
let fallbackAsk: BN | undefined = undefined;
let fallbackBid: BN | undefined = undefined;
let fallbackAskSource: FallbackLiquiditySource | undefined = undefined;
Expand Down Expand Up @@ -342,13 +345,16 @@ class DLOBBuilder {
stateAccount,
market
);
const nodesToTriggerForMarket = dlob.findNodesToTrigger(
marketIndex,
slot,
oraclePriceData.price,
this.marketType,
stateAccount
);
const nodesToTriggerForMarket: NodeToTriggerWithMakers[] =
this.findTriggerableNodesWithMakers(
dlob,
marketIndex,
slot,
oraclePriceData,
this.marketType,
stateAccount
);

nodesToFill.push(
...nodesToFillForMarket.map((node) => {
return { ...node, fallbackAskSource, fallbackBidSource };
Expand All @@ -359,6 +365,46 @@ class DLOBBuilder {
return [nodesToFill, nodesToTrigger];
}

public findTriggerableNodesWithMakers(
dlob: DLOB,
marketIndex: number,
slot: number,
oraclePriceData: OraclePriceData,
marketType: MarketType,
stateAccount: StateAccount
): NodeToTriggerWithMakers[] {
const baseTriggerable = dlob.findNodesToTrigger(
marketIndex,
slot,
oraclePriceData.price,
marketType,
stateAccount
);

const triggerWithMaker: NodeToTriggerWithMakers[] = [];

for (const nodeObj of baseTriggerable) {
const order = nodeObj.node.order;

const makers = dlob.getBestMakers({
marketIndex,
marketType,
direction: isVariant(order.direction, 'long')
? PositionDirection.SHORT
: PositionDirection.LONG,
slot,
oraclePriceData,
numMakers: NUM_MAKERS,
});
triggerWithMaker.push({
...nodeObj,
makers,
});
}

return triggerWithMaker;
}

public serializeNodesToFill(
nodesToFill: NodeToFillWithContext[]
): SerializedNodeToFill[] {
Expand Down Expand Up @@ -392,15 +438,15 @@ class DLOBBuilder {
}

public serializeNodesToTrigger(
nodesToTrigger: NodeToTrigger[]
nodesToTrigger: NodeToTriggerWithMakers[]
): SerializedNodeToTrigger[] {
return nodesToTrigger
.map((node) => {
const buffer = this.getUserBuffer(node.node.userAccount);
if (!buffer) {
return undefined;
}
return serializeNodeToTrigger(node, buffer);
return serializeNodeToTrigger(node, buffer, node.makers);
})
.filter((node): node is SerializedNodeToTrigger => node !== undefined);
}
Expand Down
9 changes: 9 additions & 0 deletions src/experimental-bots/filler-common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
SpotBalanceType,
NodeToFill,
DLOBNode,
NodeToTrigger,
PublicKey,
} from '@drift-labs/sdk';

export type SerializedUserAccount = {
Expand Down Expand Up @@ -95,6 +97,7 @@ export type SerializedPerpPosition = {

export type SerializedNodeToTrigger = {
node: SerializedTriggerOrderNode;
makers: string[];
};

export type SerializedTriggerOrderNode = {
Expand All @@ -104,6 +107,8 @@ export type SerializedTriggerOrderNode = {
sortValue: string;
haveFilled: boolean;
haveTrigger: boolean;
isSwift: boolean;
isUserProtectedMaker: boolean;
};

export type SerializedNodeToFill = {
Expand Down Expand Up @@ -143,3 +148,7 @@ export type NodeToFillWithBuffer = {
makerNodes: DLOBNode[];
authority?: string;
};

export type NodeToTriggerWithMakers = NodeToTrigger & {
makers: PublicKey[];
};
Loading

0 comments on commit 82bac7b

Please sign in to comment.