Skip to main content
Helpful?

Integrating as a Filler

There are two components to integrating as a filler: defining a filler execution strategy and retrieving & executing discovered orders.

1. Defining a Filler Execution Strategy

To execute a discovered order, a filler needs to call one of the execute methods (source) of an Order Reactor, providing it with the orders to execute.

The simplest fill strategy is called Direct Filler, where the trade is executed directly against tokens held in the fillers address. To use this strategy, a filler can simply approve the order's output tokens to the reactor and call execute or executeBatch from their address. (see source):

// Execute direct filler order
outputToken.approve(reactor, type(uint256).max);
reactor.execute(order);

More sophisticated fillers can implement arbitrarily complex strategies by deploying their own Executor contracts. This contract should implement the IReactorCallback interface, which takes in an order with input tokens and acquires the allotted number of output tokens for the caller. It must approve the output tokens to the reactor, which then transfers them to the order output recipients to settle the order. Executor contracts must call reactor.executeWithCallback or reactor.executeBatchWithCallback. They can also specify arbitrary callback data that will be passed into the reactorCallback call.

contract Executor {
function execute(Order calldata order, bytes calldata callbackData) {
reactor.executeWithCallback(order, callbackData)
}

function reactorCallback(ResolvedOrder[] calldata orders, bytes calldata callbackData) {
// implement strategy here
}
}

// Execute custom fill strategy
address executor = /* Address of deployed executor contract */ ;
bytes fillData = /* Call data to be sent to your executor contract */;
executor.execute(order, fillData);

For convenience, we’ve provided an example Executor Contract which demonstrates how a filler could implement a strategy that executes a UniswapX order against a Uniswap V3 pool.

2A. Retrieve & Execute Signed Dutch Orders

All signed Dutch Orders created through the Uniswap UI will be available via the UniswapX Orders Endpoint. We have swagger documentation but see below for a quick example curl.

GET https://api.uniswap.org/v2/orders?orderStatus=open&chainId=1&limit=1

It’s up to the individual filler to architect their own systems for finding and executing profitable orders, but the basic flow is as follows:

  1. Call GET on the /orders of the UniswapX Orders Endpoint as written above, to retrieve open signed orders
  2. Decode returned orders using the UniswapX SDK
  3. Determine which orders you would like to execute
  4. Send a new transaction to the execute or executeBatch methods of the Dutch Order Reactor specifying the signed orders you’d like to fill and the address of your executor contract

2B. Retrieve & Execute Signed Limit Orders

The process for retrieving and executing limit orders is the same as Dutch Orders above except that Limit Orders will be retrieved from the Limit Orders Endpoint (full API docs here) and executed against the Limit Order Reactor. The process is:

  1. Call GET on the /limit-orders of the UniswapX Limit Orders Endpoint as written above, to retrieve open signed orders
  2. Decode returned orders using the UniswapX SDK
  3. Send a new transaction to the execute or executeBatch methods of the Limit Order Reactor specifying the signed orders you’d like to fill and the address of your executor contract

For Dutch and Limit Orders, if the order is valid it will be competing against other fillers attempts to execute it in a gas auction. For this reason, we recommend submitting these transactions through a service like Flashbots Protect.

Helpful?