By Alireza Arjmand, Felix Wegener and Pedro Aisenson
In the evolving landscape of on-chain trading, UniswapX emerges with a unique design that challenges traditional trading and liquidity aggregation paradigms. But how does it ensure user security while optimizing trading rates through its auction based system?
Through our collaboration with the Uniswap team, we comprehensively examined the UniswapX codebase. Our audit revealed key security components: stateless contracts that minimize attack vectors, reactors that verify swap invariants, and a competitive filler market that mitigates MEV risks. We’re here to provide a detailed analysis.
Swappers: Users of the system, who send request for a swap under certain conditions
Fillers: The matchers in the system, they compete submit swap request on-chain and trigger the execution on order’s appropriate reactor
Reactor: On-chain contracts that settle an order. These are the endpoints that Fillers send the orders to, and where it gets checked if the swap is following the conditions that the swapper specified.
Orders: A set of input tokens and output tokens, which define a swap requested by a swapper. All the information is bundled up and sent to the fillers
Input token: The tokens that are requested to be swapped.
Output token: The tokens that the swapper is looking to swap with.
Background and Orientation
From the inception of on-chain trading, the ecosystem has undergone significant transformations to address inherent challenges and optimize user experience. Initially, Uniswap pioneered the Automated Market Maker (AMM) model, where trades were executed against a liquidity pool. While revolutionary, this model presented an obstacle – the fragmentation of liquidity across multiple pools. This fragmentation often led to suboptimal price efficiencies for traders, especially in pools with lower capitalization.
Recognizing these challenges, the next phase of on-chain trading evolution brought forth decentralized exchange (DEX) aggregators. These aggregators operated by routing trades through a curated set of liquidity sources, leveraging intricate algorithms to ascertain the most efficient trading path. However, even this approach had its limitations due to its reliance on pre-defined criteria and the constraints of predefined liquidity sources.
UniswapX emerges as a response to these challenges. Instead of relying on static liquidity sources or deterministic routing algorithms, UniswapX introduces a more dynamic and competitive paradigm. Through its competitive filler model and Dutch auctions, it delegates the responsibility of trade execution and routing to fillers. This ensures that swappers consistently obtain the most competitive rates, irrespective of the liquidity source. By entrusting fillers with the autonomy to determine the optimal route, UniswapX establishes a framework that is both liquidity and route-agnostic, heralding a new era of efficiency and user-centricity in on-chain trading.
UniswapX enables users to exchange their on-chain assets without incurring gas fees while also safeguarding them from MEV extraction. In this system, users, referred to as "swappers," transmit a signed request to a network of "fillers", who are responsible for fulfilling and executing the swappers' requests on the blockchain. Each of the order settlements happen on-chain, however the liquidity routing is completely delegated to the filler, as long as they satisfy the initial conditions outlined by the swapper.
This design fundamentally shifts the trading paradigm. Instead of the traditional approach where obtaining the best rate is typically determined by the magnitude of the largest liquidity pool or a routing algorithm, UniswapX introduces a competitive framework. Here, 'fillers' compete against one another to offer optimal outputs. The responsibility for routing squarely rests on the fillers, granting them the autonomy to fulfill the order using any method they see fit. This competitive dynamic is further solidified through the use of Dutch auction reactors, ensuring that swappers consistently receive the best possible trading rates, taking into account fees, MEV, and slippage collectively.
While UniswapX boasts a refined architectural design, this piece delves into the security principles ingrained within the system to ensure its robustness. We also delve deeper into the user flow, highlighting the safeguards in place against MEV extraction.
UniswapX Protocol Overview
To fully grasp UniswapX’s approach to security, we first have to understand the big picture view of the protocol. As a reference, you can refer to Uniswap Documentation for more information (reference for the picture below).
(1) Before swappers can send requests to the fillers, they must authorize the `Permit2` contract with sufficient allowance for the targeted ERC20. This enables them to transfer the asset they want to swap without sending any transactions.
(2) With `Permit2` enabled, users can now create `orders` in a manner that they specify a single token that they want to swap which is called `input token`, for any number of tokens that they would want to receive which are called `output tokens`. swappers create and sign these orders as swap requests, which are then dispatched to the fillers' internal network. As of now, swappers have the option to create three distinct types of orders, which include:
- Limit Order: A simple order where the swapper determines a specific number of input and output for each token involved.
- Dutch Order: In a Dutch Order, the price shifts at a steady rate from the start time to the end time. This structure aims to make the swap more favorable for the fillers as the time passes on, and the first filler who settles the order, gets to be the winner of the auction. This setup also introduces a sense of competition among the fillers, as each filler is motivated to settle the order as soon as it has enough profit for them due to the competition among fillers.
- Exclusive Dutch Order: Exclusive Dutch order is the same as the Dutch order, but it grants exclusivity to a specific filler for a predetermined duration before becoming publicly accessible. Uniswap team hosts a public network for Request For Quote (RFQ) where swappers can get a quote from fillers before sending the request, this way they can choose the best rate from a filler and make it exclusive to them for some time before the `order` becomes a normal Dutch Order.
(3) Fillers have access to a mempool of orders, and they can choose which order they want to fill. To do this, they forward the chosen requests as transactions to an on-chain contract known as “reactor”. Each reactor's main responsibility is to settle orders on-chain correctly. There is a separate reactor for each type of `order`, and swappers have to embed the target reactor's address inside their request before they sign it. At this point, the reactor finalizes the swap by transferring all of the `input` assets in, and sending all the `output` tokens to their recipients.
UniswapX Security Principles
Throughout our collaboration with the Uniswap team, we have extensively examined and reviewed the UniswapX codebase in its entirety, pinpointing the crucial security measures that establish the protocol's safety. In this section, we share our insights into the UniswapX protocol's security framework, underscoring the principal security factors that are fundamental to the protocol.
Stateless Contracts: All of the swaps done via the UniswapX protocol use `Permit2` functionality, which means that users can transfer money with a signature which is included as a part of order. With this in mind, UniswapX contracts are designed in a way to be almost stateless, which results in several conditions:
- Since there is no state stored, the contracts can not be taken into an unexpected state, and each transaction is executed based on its inputs alone. This causes the attack surface to be reduced significantly.
- Stateless functionalities are much simpler in nature, they are easier to test, and therefore easier to ensure their correctness.
Invariant verification: Each reactor has one main responsibility, to make sure the `input` and `output` tokens are transferred properly and in time. The main functionality that reactors provide is the function `execute`, which has two phases:
- Prepare: Where it handles all the fees that the swapper should pay, and then the control is transferred to the filler.
- Fill: Transfer all of the `output` tokens to their recipients. This should be the last thing that happens in the whole function.
No matter what happens between `Prepare` and `Fill`, UniswapX ensures that the functionality will work properly by checking these two invariants at the start and at the end of the function.
Protection against MEV: By making the filler market competitive and accessible to many entities, UniswapX is making sure that swappers are enjoying the best price possible. In the case of Dutch Auction, where the price is reducing over time, if one filler waits too long before accepting the trade, other fillers can come in and take the opportunity for themselves.
Notably, if MEV makes a fill viable, a sophisticated filler can quickly accept the offer ahead of competitors. This dynamic ensures that the final price factors in any potential MEV, offering swappers the most favorable rate. In this way the concept of MEV and price impact are treated and minimized together. This also includes gas fees which are paid by fillers and will be accounted for in their decision of filling or not an order at a certain price.
Given the competitive nature of executing swaps, only the initial filler manages to seize the opportunity, leaving subsequent attempts unsuccessful. To prevent the costs associated with unsuccessful transactions, fillers can utilize services like Flashbots which only include successful transactions in their blocks. Using Flashbots would also help fillers by protecting their transactions against front-running.
In our analysis of the UniswapX protocol, we investigated the security principles integrated into its system. The protocol addresses various challenges associated with on-chain trading while emphasizing user security.
These efforts contribute to the ongoing evolution of the web3 environment. For a comprehensive understanding of the UniswapX protocol and our full security review, we recommend referencing the detailed [audit report]. Additionally, our blog provides insights from other protocol audits, showcasing our commitment to transparency and security in the decentralized space.