On MEV Agents and Forward Routing Problems

Cover Image for On MEV Agents and Forward Routing Problems
by Team Agents
by Team Agents

Gm anon, I am Luca, member of the Team Agents at Urani. We develop and open-source MEV agents searching for optimal order execution paths.

Funnily enough, searching somehow mirrors my life's journey. In this post, I introduce myself and I discuss the problem that helped me land a job at Urani.


If you are interested in my personal story, you can keep reading. Otherwise, skip to the next section for the technical discussion.

The technical challenges included developing an MEV agent that maximizes the order's surplus by matching a set of order intents to various potential liquidity sources.



Looking Up in the Sky


I was born in a small town in northern Italy, nestled between lakes and the Alps, and I was fascinated by space.

At 8, charmed by magnets, I designed a project for a magnetic engine for spacecraft, which I thought would be tremendously effective (spoiler alert - it wasn’t). Strangely, it didn't reach space, but instead ended up in the trash can.

However, this experience made me realize I wanted to design technologies that benefit people.

My quest to find ways to impact people positively started with studying Engineering Physics, specializing in semiconductor materials and electronic devices.

Studying organic electronics made me passionate about molecular systems, and I collaborated with a lab conducting experiments with ultrafast lasers on organic molecules for biocompatible optoelectronic devices.

Then, attracted by clean energy applications, I worked on my M.Sc. thesis in Germany, modeling and developing new catalytic materials. Lastly, I returned to Italy to pursue a Ph.D. in Theoretical and Computational Chemistry.

During this period, I unleashed my geeky potential, delving deeper into the quantum mechanical modeling of molecules and joining a team developing scientific software.

As I traveled the world to speak at various conferences, I felt my path should change again. I was having fun in the scientific community but felt the push to do something concretely valuable for people.



Discovering Urani


While searching the web for highly impactful start-ups, I stumbled upon Urani 🪐.

They seemed like the perfect match for me. Not only does developing advanced strategies and AI-centric MEV agents trigger my geeky and technical side, but the concept of promoting fairness, accessibility, and meritocracy in DeFi, and protecting users from toxic-MEV bots, makes me feel I’d be doing something truly impactful for people.

(Really, they hooked me with a job post that showed a thumbnail image featuring a piece of the time-independent perturbation theory in quantum mechanics.)



So, I dropped my resume and crossed my fingers. When I got the reply, I was ready to take on the challenge they gave me.



My First MEV Agent and How I Got a Job at Urani


"MEV agents are crucial components of the Urani Protocol, serving as matching engines to identify the best execution paths for orders.

MEV agents function by analyzing the current batch of orders to detect peer-to-peer matches and ring trades that could provide the best prices for executing trades or limit orders. They assess various factors, including liquidity, order book depth, and price slippage, to ensure traders receive the optimal execution.

Additionally, these agents can directly interact with on-chain automated market makers (AMMs) or use DEX aggregators to find the most advantageous prices and routes."


I was tasked with developing an MEV agent that can match a set of order intents (in JSON) to various potential liquidity sources and determine the optimal execution to maximize the order's surplus.

For instance, here is a simple example of an order intent:



Setting the Framework


Suppose a user with an order expressing their intent to buy buy_token and sell sell_token with specified restrictions. These restrictions include the maximum amount of sell_token the user is willing to sell (s_lim) and the minimum amount of buy_token the user is willing to receive (b_lim).

We have a set of venues or liquidity pools with an AMM where coins can be swapped. All the coins and venues define an undirected graph, with the former being the vertices and the latter being the edges. For example:



The order's surplus Γ is defined as:



Where π = s_lim / b_lim is the user's worst acceptable exchange rate.


The problem posed is: if users has 1000 MU (sell_token), what is the optimal way to convert it into NU (buy_token)? These problems are called forward routing.


Interestingly, for such problems, direct routes (i.e., selling all 1000 MU along a single simple path connecting MU to NU), are not always the most efficient, and a combination of multiple routes can often yield better results.

Thus, the task translates into helping the user solve this problem:



With N being the number of simple paths connecting sell_token with buy_token (MU and NU in our example, respectively).



Gladly, the forward routing problem is convex, so we do not have to embark on a global optimization problem but can employ local minimizers.



My Approach


There are many ways to solve this problem. In my solution, the main components are a set of classes:

  • Order: Represents an order with user intent for trading.
  • Venue: Represents a trading venue with token reserves.
  • Market: Represents a market of trading venues; it is a graph with tokens at the vertices and venues at the edges.
  • Agent: Represents a market agent that formulates and optimizes trading strategies.

Given a generic intent, with the user Order and the list of Venues forming a Market graph, Agent reads the Market and constructs a strategy to fulfill the user's swap needs.

In this case, strategy is a directed subgraph of Market containing all the simple paths connecting the user requested sell_token to buy_token.

The Agent now searches for the optimal coin exchange among the paths in the strategy to maximize the user surplus by applying a constrained maximization of the order's surplus Γ function defined above.

This is the scheme of such an approach:



Which translates into this code:


One can call such function with a simple Python program:


That when is run for the previous intent outputs:


Generating the following results:


That's enough to make it work.

However, If you want more technical details on how such code works, sit down and fasten your belt.



Technical Discussion


In this first steps, we build:

  1. The user Order containing the intent of buying buy_token and selling sell_token, with the worst acceptable exchange rate;
  2. The Venue objects containing the trading venues;
  3. The Market object, i.e., the graph of coins and trading venues.




The User Order's

First of all, we ingest the intent into the variable data and read values from it:


This allows to initialize an instance of the class order:





The Venues

Next, we include all the venues:


This allows to initialize a list of instances of the class venue:





The Market

Having stored the venues, we can now build the Market graph:


The initialization of a market instance generates the graph as follows:


In our example, Market will look something like:






The Agent

Now, that we have all the necessary inputs, we can initialize the Agent and construct the strategy graph:


Where the Agent object looks like:





Strategy Construction


Strategy is a directed subgraph of Market. Agent, stores also all the paths connecting sell_token to buy_token. In our case, this will look something like:


In case of more complex graphs, multiple paths are stored for future propagation and optimization, for example:


To do this, we first read the Market with the method:


And then, we construct the strategy multigraph:





The Strategy Optimization


Now we have all the ingredients to try to solve our forward routing problem:

  1. We have the intents of the user defining the constraint of our problem;
  2. We have the paths along which we can propagate to reach buy_token from sell_token;
  3. Having set the direction of propagation, we also have the price function for each edge, allowing swapping from one coin to another through an AMM venue.

Note: the price function of the venue AMM C-A will be in an AMM:



Where a is the amount of coin A sold to buy the amount c of coin C. [A], [C] are the initial liquidities of the tokens.

Now we can use the optimize_strategy method bound to Agent:


In this routine, we make use of the propagate along (path) which is defined as:


And that's all.

Now we have obtained the optimal amount of coins sold and bought through each channel, we just need to output the results to the user.



Final Thoughts


The approach I employed works on acyclic graphs. Adding an edge between two coins makes the graph become a multigraph. From a theoretical point of view, the problem of routing on multigraphs is still convex (e.g., see this reference).

The code works fine for very simple multigraphs (i.e., only two coins are connected by more than one venue). However, when multiple venues connect multiple coins, the problem of detecting all simple paths connecting sell_token to buy_token arises. This problem is combinatorial by nature and gets extremely complex as the graph's dimensions increase.

In addition to this, even if the directed graph wouldn't have multi-edged connected vertices, the problem of simple path detection from A to B is highly complex (#P-complete), and requires complex numerical techniques to be solved efficiently.

Moreover, I never considered multi-asset venues, which would imply more complex graphs and for which the price functions could change during propagation. Indeed, if I consider a multi-asset pool, with tokens A, B, and C, it can happen that the price function c(a) might change if I first visited this venue but along a different edge of the graph (e.g., A/B).

Another source of additional complexity is the possibility that the graph changes through time. Indeed, it might be possible for new venues to be added to the market, introducing new connections among the nodes.

Eventually, I did not consider that in real swaps, liquidity pool providers' fees, venues' price functions, and price slippage, among other factors, might influence the executed outcome.



Until Next Time, Anon


The real world is much more complex than this challenge, but this was a fun start. By the way, if you like what you learned today, you can try it yourself: here is the repository for my project.

We at Urani are working hard to leverage advanced algorithms for price-routing, ring-trade detection, and MEV-minimization.

I am particularly excited about being part of this fantastic group, protecting users in decentralized finance.