Skip to Content
DevelopersTrading AutomationKeeper BotsTutorial: Order Matching Bot

Tutorial: Order Matching Bot

Introduction

Order Matching Bots (Matching Bots) are responsible for matching two orders that cross or a taker order against the AMM. Specifically, this includes:

  • Market Orders: Market Buy and Market Sell

  • Limit Orders: Limit Buy and Limit Sell

Matching Bots receive a small compensation for each order that they successfully fill.

See Keepers & Decentralised Orderbook for a technical explanation of how the decentralised orderbook (DLOB) and matching incentives work.

Matching Bots are similar to Tutorial: Order Trigger Bot in that they:

  • also maintain a local copy of the Decentralised Limit Orderbook (DLOB);

  • do not require the operator to manage collateral; and

  • receive a small reward for performing their duties.

Getting Started

The reference implementation of the Order Matching Bot is available here .

Follow the instructions at Keeper Bots to set the required environment variables and make sure a ClearingHouseUser is initialized.

Start the Matching Bot:

yarn run dev:filler

Technical Explanation

Step 1: Get nodes from the DLOB that are ready to be filled

Market orders that are sent on the Drift Protocol first go through the Just-In-Time (JIT) Auctions. After the auction period, Matching Bots step in to fill orders for a small reward.

The DLOB implementation includes a method for getting orders ready to be filled:

const market = this.clearingHouse.getMarketAccounts()[0]; // get a MarketAccount const oraclePriceData = this.driftClient.getOracleDataForMarket(marketIndex); const oracleIsValid = isOracleValid( market.amm, oraclePriceData, this.driftClient.getStateAccount().oracleGuardRails, this.slotSubscriber.getSlot() ); const vAsk = calculateAskPrice(market, oraclePriceData); const vBid = calculateBidPrice(market, oraclePriceData); const nodesToFill = this.dlob.findNodesToFill( marketIndex, vBid, vAsk, this.slotSubscriber.getSlot(), oracleIsValid ? oraclePriceData : undefined );

Step 2: Filter for fillable nodes

To avoid trying to fill orders that aren’t ready to be filled, filter out orders that are too small to fill

if ( !nodeToFill.makerNode && (isVariant(nodeToFill.node.order.orderType, "limit") || isVariant(nodeToFill.node.order.orderType, "triggerLimit")) ) { const baseAssetAmountMarketCanExecute = calculateBaseAssetAmountMarketCanExecute( market, nodeToFill.node.order, oraclePriceData ); if ( baseAssetAmountMarketCanExecute.lt(market.amm.baseAssetAmountStepSize) ) { // skip order continue; } }

Step 3: Call fill_order on DriftClient

const user = this.userMap.get(nodeToFill.node.userAccount.toString()); const txSig = await this.driftClient.fillOrder( nodeToFill.node.userAccount, user.getUserAccount(), nodeToFill.node.order, undefined );
Last updated on