Event Flow Diagram
The following diagram illustrates the complete flow of events in the Filler bot, from receiving gRPC and WebSocket events, updating the orderbook (DLOB), to sending and confirming transactions:Event Sources
The Filler bot receives events from multiple sources that drive its operation:gRPC Slot Update
Slot updates are the primary timing mechanism for the bot:- Frequency: Approximately every 400ms (Solana slot time)
- Purpose: Triggers periodic cross detection for auction orders and limit orders
- Routing: Sent to both
DLOBNotifier(for price updates) and the main loop (for processing)
Slot updates create a regular heartbeat for the bot to scan all markets for new opportunities.
gRPC Account Update
Account updates notify the bot when on-chain state changes:- User Accounts: Order placements, cancellations, fills, position changes
- Market Accounts: AMM state updates, liquidity changes
- Oracle Accounts: Price feed updates
- Routing: Sent to
DLOBNotifierto update orderbook state
The bot subscribes to all user accounts and relevant market accounts via gRPC filters.
gRPC Transaction Update
Transaction updates provide confirmation status for submitted transactions:- Confirmations: Transaction landed on-chain successfully
- Errors: Transaction failed or was rejected
- Routing: Sent directly to
TxWorker.confirm_txfor processing
- Parse transaction logs to verify expected fills occurred
- Update metrics (success rate, fill rate, latency)
- Remove transactions from pending queue
- Detect competition scenarios (order already filled by others)
Swift Order WebSocket
Swift orders are off-chain orders submitted directly to Drift:- Source: WebSocket connection to Drift’s Swift order service
- Content: Signed order parameters with auction details
- Routing: Processed directly in the main loop
- Purpose: Provides low-latency opportunities to fill orders against resting liquidity
DLOB and DLOBNotifier
DLOBNotifier
TheDLOBNotifier acts as an event processor that updates the DLOB:
Responsibilities:
- Receives gRPC slot and account updates
- Batches events for efficient processing
- Parses account data to extract order information
- Emits
DLOBEventnotifications for DLOB to consume
SlotOrPriceUpdate: Triggers auction price recalculationOrderPlaced: Adds new resting order to DLOBOrderCancelled: Removes order from DLOBOrderFilled: Updates or removes filled order
DLOB (Orderbook State)
The DLOB maintains the complete orderbook state in memory: Data Structures:- Orders indexed by market, side (bid/ask), and price level
- User order mappings for quick lookups
- Efficient structures for cross detection queries
find_crosses_for_auctions(): Finds auction orders that can be filledfind_crosses_for_taker_order(): Matches taker against resting ordersget_top_makers(): Queries best resting orders for liquidations
Main Loop Processing
The Filler bot’s main loop usestokio::select! with biased selection:
Swift Order Priority
Swift orders are processed first because:- They represent immediate opportunities
- Other bots may compete for the same fill
- Lower latency provides competitive advantage
Slot Update Processing
On each slot, the bot:- Update Oracle Prices: Fetch latest prices from DriftClient
- Check Pyth Prices: Use faster Pyth Lazer feed if available
- For Each Market:
- Query DLOB for auction crosses
- Filter crosses using slot limiter (avoid spam)
- Build and submit fill transactions if crosses found
- Calculate Priority Fee: Use percentile-based fee (50th-60th)
- Add Entropy: Small random component to avoid duplicate tx hashes
Find Crosses
Cross detection is the core of the Filler bot’s logic:Auction Crosses
- Auction orders where auction price crosses resting liquidity
- AMM (vAMM) opportunities where AMM wants to provide liquidity
- Top maker orders for each crossing taker
Swift Order Crosses
Cross Filtering
Before attempting fills, crosses are filtered:OrderSlotLimiter prevents:
- Repeated attempts on the same order within a few slots
- Wasted transactions on orders that consistently fail
- Excessive priority fee spending
Transaction Building and Sending
When crosses are found, the bot builds a fill transaction:try_auction_fill
- Build Instruction: Create
fill_perp_orderinstruction - Add Maker Accounts: Include all crossing maker accounts
- Set Compute Budget: Priority fee + CU limit
- Submit to TxWorker: Send via channel
try_swift_fill
- Build Swift Fill Instruction: Include signed order data
- Add Maker Accounts: Resting orders to match against
- Set Compute Budget: Higher CU limit for Swift fills
- Submit to TxWorker: Send via channel
TxWorker
The TxWorker runs in a separate thread:- Receive transaction request from channel
- Sign transaction with wallet
- Send to RPC endpoint
- Add to
PendingTxsbuffer with metadata - Increment send metrics
- Receive transaction update from gRPC
- Look up transaction in
PendingTxsby signature - Fetch full transaction details from RPC
- Parse logs for fill events
- Compare actual fills to expected intent
- Update metrics (success, fill rate, latency)
- Remove from pending buffer
Feedback Loop
The confirmation feedback loop enables the bot to:- Learn Competition Patterns: Detect which orders are filled by others
- Optimize Priority Fees: Adjust fees based on success rate
- Monitor Performance: Track fill rates, latency, error types
- Detect Issues: Alert on high error rates or stale data
This event-driven architecture enables the bot to react to opportunities within milliseconds while maintaining reliable transaction handling.