Solver teams aiming to use the open-source driver implementation need to implement their own solver engine.
Overview
An open source Rust implementation of a solver engine can be found in the solvers crate. This engine can be run in a few different “modes” to demonstrate and test the whole system end to end (cf.solvers::infra::cli::Command):
- Baseline: Solve individual orders exclusively via on-chain liquidity provided in the driver-augmented auction.
- Legacy: Forward auction to another solver engine implementing the deprecated, legacy HTTP interface
Architecture
Solver Engines implement the API expected by the driver component. The information received by the driver should be sufficient to produce valid responses, meaning that the solver engine could be implemented as a pure function. However, in practice, solver engines often benefit from additional state management, such as indexing liquidity sources and simulating execution routes for more accurate cost estimates, to remain competitive.Methodology
The inner workings are engine specific and highly depend on the underlying matching algorithm. While third-party aggregator algorithms are proprietary (the engine simply calls their API for as many orders as possible), the baseline solver engine can give an idea of how to generate basic solutions for simple problem instances.Baseline
For each order in the problem set, this solver implements a greedy single-path output maximization algorithm in a weighted graph where vertices correspond to tokens and edges correspond to AMMs providing liquidity between tokens with their output equal to the exchange rate as defined by AMM function given the input amount. Outputs are adjusted to consider the execution cost of updating the AMM when used, using fixed gas amount estimates but taking into account the gas price provided in the auction input. The graph originates over a set of “base tokens” plus the buy and sell token of the order. It aims to find the single path from buy to sell token that maximizes the output for sell orders and minimizes the input for buy orders. It handles partially fillable attempting to first fill the entire order. If the resulting output doesn’t satisfy the limit price, it re-attempts filling the order to 50% and keeps halving its amount until a match is found. It does not produce Coincidences of Wants.Flash Loans
The solver can receive an optional object with each order that provides hints for using flash loans. These hints act as guidance, but the solver is free to return a different list of flash loan objects in their solution. The solver has three options:- Provide no hint: In this case, the driver will assume the flash loan hint attached to the order gets settled in the solution.
- Use the provided hint: The solver can directly copy the flash loan hint included with the order.
- Define a custom hint: The solver can specify a different flash loan hint, allowing for better optimization of flash loan usage.
IFlashLoanRouter contract.
The solver must consider the gas cost implications of using a flash loan, as the associated overhead is non-negligible.
The settlement contract will receive the swap order funds, but it is the solver’s responsibility to ensure the flash loan is fully repaid within the same transaction. Additionally, the solver needs to account for when the funds will become available, factoring in any user-defined pre-hooks.
The reference driver facilitates this process by pulling funds from the IFlashLoanRouter contract and transferring them to the user, so they can be used for the order swap. Since the settlement contract is the recipient of the swap, the driver must then move the funds back to the IFlashLoanRouter contract, ensuring that the flash loan lender can retrieve the required repayment from it. If a solver chooses to implement a custom driver, they are responsible for managing this behavior as they deem appropriate.
We support the following flash-loan lenders:
Dependencies
Solver engines need to be “registered” inside the driver configuration file to receive requests. Checkdriver::infra::config::file::SolverConfig for the available configuration parameters.