July 22nd, 2022
This post is the first part of a 2-part perspective on the 0x protocol in Web3, completed jointly with Justin Cullen. The top-level TL;DR is that we study 0x, one of the major DEX aggregation services, from a systems thinking perspective.
We start by analyzing the 0x system itself (this part) and then go on in Part 2 to synthesize 0x within the broader system - Web3 Order Flow. Comments, questions, and claims of “you’re wrong” can be sent to any of my inboxes.
TL;DR: We dive into 0x, a DEX Aggregator, and take apart its components to understand how it works as a system. For each of those components, we gauge what purpose it serves and why it exists, as well as how they functionally connect.
We understand the 0x system by taking it apart. For each constituent part, we then repeat the process and take those apart. Graphically, the following diagram completely describes 0x today. Below, we examine the different flows through the system, then split into subsystems and consider each independently. Let’s dive in.
Here is the top level breakdown:
- Matcha is a web interface built by 0x for trading tokens or buying them with fiat. This can be white-labeled by other services.
- ZRX is the governance token for the protocol. This can be staked, although I’m both not sure why someone one would do that, nor does it appear to have any utility value at the moment.
- 0x DAO is the organization governing 0x.
- Relayers are services that “relay” the end user’s swap request to liquidity sources and return a Web3 payload to complete the transaction. 0x provides the software and tooling to run a Relayer, in addition to running their own, but there are Relayers running that are independent of 0x. Most of these are off-chain nodes who interact with the on-chain 0x protocol. Note that the 0x API, which the Relayers talk to, is not on-chain.
- 0x Protocol is the on-chain subsystem that completes transactions. It is entirely on-chain.
- RFQ, or “Request For Quote”, is the subsystem for communicating with third parties providing liquidity, either Makers or Takers. Most of the Makers and Takers represent on-chain liquidity sources, although not all do.
The Makers and Takers are the two sides to the 0x marketplace. Makers create 0x orders and provide liquidity into the system for the Takers to consume. Examples include on-chain liquidity from DEXs and AMMs (Uniswap, Curve, Bancor) and off-chain liquidity from professional market makers. Takers fill the order and receive the tokens, perhaps on behalf of the user. Examples include MetaMask, Coinbase, and dydx, but also could just be the end user or an intermediary smart contract. Here is an example where the end user is the Taker.
There are multiple entry points to the system:
- Any transaction from a swap UI such as Matcha speaks directly to the 0x API Relayer, which then enters the protocol via the RFQ system.
- A participant could participate in the RFQ pool, either as a Taker or Maker, without going through an existing service.
- ZRX tokens holders can vote on governance or stake their tokens in the Treasury. The latter, staking, isn’t worthwhile anymore though outside of voting. It also is challenging to do.
An example experience for a user is to visit matcha.xyz and request a token swap. Here’s an example from 0xTracker trading HDRN to USDC. This will hit the 0x API, which serves as the Relayer for Matcha. Here’s another transaction using Coinbase Wallet and not Matcha, but still with the 0x API as the Relayer. Finally, here’s one where Tokenlon is the Relayer.
In RFQ-M, after going through the 0x Relayer, the Maker executes the transaction on the blockchain and pays the associated gas costs. This is used when the market manages the user’s trade, e.g. limit, OTC, and/or gas-less trades.
The flow is that the Relayer (0x API in Matcha case) speaks to the RFQ module, which pings the RFQ Maker subsystem for quotes and returns them to the Relayer. The Relayer forwards these to the Taker for signature and then the Taker returns the transaction to the Maker for last look. If the Maker agrees, they fulfill the transaction via the MetaTransaction feature. In this setting, because the order is filled by a market-maker, the user pays no gas or network fees.
Gas-less trading may sound like a blessing. And in large block trades, it can be. However, it isn’t always preferable because the overall cost may be higher. That there are fewer liquidity sources available for gas-less means the spread is wider and the swap price can be greater. Consequently, the eventual cost for small trades is often higher than it is when just paying gas and using AMMs + RFQ-T. For big block trades, because the market makers are given last look with RFQ-M, they have no fear of their stale quotes being arbitraged. This frees them up to give tighter spreads and is advantageous for blocks that are difficult to move without impacting the AMM pools.
RFQ-T is used when the user’s trade can be completed without further management and without impacting the market.
The flow is that the relayer speaks to the RFQ module, which pings the RFQ Taker subsystem for quotes and returns them to the Relayer. However, now the quotes are signed and committed. So when the Relayer forwards the aggregate best quote to the Taker, they submit directly to the protocol without the Maker getting last look.
Only settlement is on-chain. That is by design because 0x uses off-chain relay and on-chain settlement, which means orders are stored off-chain. When an order is eventually filled, either because a Taker executed it or because a Maker submitted it, the protocol verifies all conditions are satisfied, including the Maker signature, before atomically swapping. The main advantages of this design are that it’s cost effective and fast. A design goal is to incentivize participants to be truthful. End users are truthful because they first commit to a swap. The Makers can be truthful when committing to a quote because they are the ones that take it to market and so have final look. Does this distort the end users’ truthfulness? No, because the result of the Maker declining to execute is just that the users learn about a market change and can choose to respond in kind or maintain their price stance. The Relayers themselves have no incentive to change the prices in their order book because users have an open market with many Relayers. Could they all collude? Yes, that is possible, but 0x running its own Relayer dampens that effect. If 0x’s Relayer was also colluding, then either the collusion price is the new price or 0x’s protocol will decline in usage. In the long run, Relayers will need to get paid somehow. Can orders be front-run? Not by any of these participants, but they are certainly susceptible to the same MEV and intra-block issues that plague naive transactions throughout DeFi.
The Relayer takes advantage of 0x’s software via the HTTP API to optimize the trade and maximize revenue for the end user. This potentially splits up the trade to hit many different sources of liquidity (such as Uniswap, Pancakeswap, etc) and avoid slippage costs. After figuring out the optimal trade route, the Relayer builds the payload. In non-technical terms, this means converting the trade route into a format that can be signed and executed on-chain through a front-end interface. The resulting blob of code is the “payload”, which the Relayer then returns to the web interface for confirmation from the user. This is possible because the Relayer keeps a connection open with the front-end swap UI that remembers enough information to complete the transaction. In technical parlance, the Relayer exposes a stateful HTTP UI.
After confirmation, the payload then hits the 0x Protocol, which uses 0x’s Exchange Proxy (EP) contract to settle what may be a complex trade involving many parties. This contract represents an entire on-chain subsystem (detailed below) dedicated to executing the trade amongst all the parties. To the end user, this is seen as one on-chain transaction.
Note that the EP is an upgradeable contract that changes when 0x pushes out a new version. For users hitting the API, they just need to change to a new version number; for users hitting the contract directly, nothing should change other than setting some flags to maintain compatibility.
One path through the on-chain subsystem has a Maker executing a delayed request on your behalf using the MetaTransactions Feature. This arises when doing gas-less trading. The end user receives a quote and the user interface only requests that the message is signed. That message is then passed by the Relayer through the /rfqm component to the RFQ Maker, who submits it on your behalf to the Exchange Proxy. The latter then settles via the Meta Transactions Feature and returns to you (via the interface) a receipt of the submitted transaction. Here’s an example transaction on Etherscan (reproduced below). Note that the address that submitted the transaction is not the address starting the flow on Matcha.
Two other example paths are when the Exchange Proxy executes simple over-the-counter orders or limit orders, which short-circuit the rest of the flow and immediately hit the NativeOrders Feature that completes settlement. This is triggered on Matcha via either the limit or gas-less experience.
NFT transactions are completed via the ERC721 or ERC1155 Features.
Paths with the most complexity are those which require actions on top of the token trade. Actions include splitting the funds to be directed to multiple parties or wrapping Eth into WETH. This requires going through the TransformERC20 Feature, which will first create a flash wallet that holds the funds momentarily in a sandbox. It will then take further actions on those sandboxed funds such as channeling them through liquidity proviTders like Uniswap. After collating the results of those Features, it passes to the NativeOrders feature to complete the flow.
Smart contracts can interact with the EP directly. An example is Coinbase’s Exchange Proxy, found on Etherscan here and in the 0xTracker here. So while the 0x Swap API will typically do smart routing on the backend and return a (potentially) complex transaction to the end user to sign, this is not a requirement. There is a future where the EP is hard-coded into smart contracts throughout Web3 and exists as a sticky underlying fabric in the whole space serving an important role to end users.
Chesterton’s Fences? - The Relayer component is crucial to the overall system. It was built to manage the many-to-many- relationship between end users and the order flow. - RFQ is similarly crucial. This module is the glue both between the Relayer and the order flow, but also between the Protocol and the order flow. - The 0x Protocol is necessary for on-chain interaction and hides all of the corresponding complexity. - Matcha itself is not crucial to the working system. It is an add-on that exists because 0x the organization wanted to build a parallel and synergistic business. - The 0x DAO is also not crucial to the working system. While it does affect the system through voting and treasury allocations, this could be done in other ways without those operations being “decentralized”. Thus far, there are no tangible benefits other than some $$ from the token release and goodwill from the larger community. - Finally, the ZRX token is not crucial to the system. It exists because there was once a time where the system was going to use it as the payment avenue. Today, that is set to zero and the organization’s stated intent is to “not be rent-seeking”. Regardless of if that changes in the future, the protocol operates without issue in that setting.
The Relayer component manages the (off-chain) orderbook and optimizes swap routing via the off-chain 0x API, the large section under “HTTP API” in the graphic below. The 0x organization itself runs a Relayer while others are completely independent, e.g. Tokenlon. The purpose of the Relayers is to help end users with order discovery.
The order book is fairly innocuous, serving as a way to understand the available pool of liquidity. So is the /rfqm subsystem routing communication between users and RFQ Makers. On the other hand, trade optimizing, as detail more below, is quite complex.
The Transaction Watcher can also be complex pending what the protocol implements. This component is the conduit through which the on-chain protocol alerts the Relayer to relevant on-chain changes such as completed token swaps.
The first part of the process is to pull orders from the 0x mesh network before collecting quotes from DEXs and market makers in a single batch operation. Both the orders and sampled quotes are then converted to DAGs where each node represents a fill. The optimal solution is the combination of these DAGs that results in the greatest output token amount for an end user’s given input token amount. To assemble this solution, the DAG paths are merged to optimize for return rate modulo fees and gas.
The following charts show an example. The three lines A, B, and C represent overall returns for a given token swap from different DEXs where the x-axis is the amount to fill. The initial fill is best under A. So we would optimize this by having A take the first chunk. B then has the next best value, so we push out B’s curve to take effect starting at and instead of the first node it which it is better than A. We repeat this for C and yield the final curve in the bottom right, which is the one that would maximize the AUC subject to our constraints.
After performing this optimization, the Relayer then needs to complete settlement. This means converting the path to 0x orders. These orders are wrapped appropriately for on-chain usage, encoded as hex blobs to be signed and submitted, and then the EP fills each order until the required number of tokens have been transacted.
Chesterton’s Fence? Every component appears to be important for this system to function. We could make an argument that differentiating price from quote is unnecessary. This part was designed to have one flow (quote) that was binding for the Maker and another (price) that was non-binding. Only quote is important for this subsystem to run, but within the larger system (0x), participants want both in order to better handle their own needs. For example, a Maker does not want a price view like CoinGecko to be pinging it with binding quotes.
The organization is built as a DAO, with a token, a forum, voting, and a treasury. The token doesn’t have any demand drivers at the moment other than speculation. At one time it did because of protocol fees, but no longer. A relevant conversation we had with 0x team members about this in Discord:
Us: With the protocol fee multiplier set to 0 and consequently no rewards in staking, how does 0x make money?
0x: It's an open-source protocol, like HTTP, which means that it doesn't have to "make money" to continue to add value. The protocol will function in current state without additional investment (see 0x Protocols v2 & v3 as examples that are not being actively developed on but still are being used today by a few apps). Of course, it would be ideal if ongoing protocol dev funding could be self-sustaining via the community treasury but atm it's not a blocker as we have teams like 0x Labs continuing to contribute towards improving the protocol. in the future, I envision the possibility of other larger players in the ecosystem dedicating resources to do the same.
Us: Is there a part of the protocol that is going to be generating cash flow? if not, what are the other reasons to hold the token besides voting?
0x: Anything is possible in the future since the protocol is open-source as I mentioned. The real Q is how does the protocol do so w/out being rent-seeking (which would work against adoption)?
The staking appears to be turned off, although the user flows are still available. The staking page shows zero available pools. Going through the staking wizard ends with “Staking recommendations not available.”
Chesterton’s Fences? The organization needs its treasury, but the rest of this system is arguably unnecessary in this form. It is a design decision to have an open forum, open voting, and a representative token to do the voting accounting. That could just as well be closed, and it is closed for most 0x product decisions. The reason for all of this existing today is to be friendly to the crypto community and follow its ethos, which has likely helped greatly in attracting projects since 0x’s inception in 2016. The token especially appears to be unnecessary today. It was created to be the payment medium for the protocol, but that’s no longer the case both because there is no payment and because when there was it was paid in the token transferred, not ZRX. Today there does not appear to be a reason to hold the coin other than bullish sentiment on its future. Even then, why would this token be worth anything outside of governance on (mostly) inconsequential decisions?
This subsystem is self-contained and acts as both a UI to access 0x’s features as well as a white label interface for others to use. It works just like any other trading interface and is only special in so far as it was built by 0x and shows off 0x’s utility. This may turn out to be a money-making source for 0x but cash flows do not flow back to token holders as of today. See this tweet from the 0x team for confirmation.
Note that until July 12th 2022, there was an option to select between gas-less and OTC on the Matcha interface. They then updated their UI and rolled these two options into just the market tab. It now automatically chooses for you. The OTC tab no longer appears even for supported pairs (see https://matcha.xyz/blog/otc), and gas-less is no longer a user option but rather automatically selected when applicable.
Chesterton’s Fences? While it is not imperative for Matcha to offer the credit / debit card integration and it isn’t clear how much benefit that component provides, it serves as an attestation to their effort to make a beautiful user experience. There’s no fucking way every generation of crypto users are going to be cool with onboarding into wallets and all their machination. Embracing fiat payments to onboard is a major plus for a swap UI. This was birthed in late June 2020 following other aggregation services debuting UIs. Of course, the website interface is crucial. The components doing limit and market orders are table stakes today. Gas-less trading and OTC are nice to haves, not crucial. Time will tell whether those are culled or become more important.
The on-chain part of 0x is the subsystem governed by the Exchange Proxy. This area seems quite complicated, but it’s because there is cause for many individual Features components built in order to each do a single function. This allows for easy composability amongst the contracts; the alternative would be fewer, more monolithic, on-chain contracts that each do more but are harder to reason about.
Chesterton’s Fences We expect that some parts of this are actually not crucial but, as is the case with legacy Web3 systems, they remain in use because the intentional slowness to upgrade necessitates being slow to cull away unnecessary components. An example are the special Features just for Uniswap, PancakeSwap, and similar services. We do however need features for Transforming ERC20s, for executing RFQM transactions, for handling the popular NFT designs (721 and 1155), and for operating a Flash Wallet to take just the right amount of money to each FillQuote. So while all of these Features were originally set up with purposeful intent, over time they will naturally drop off in usage and/or be replaced with better abstracts. And yet, because of how the chain works, they will continue to be available for anyone to call.
The RFQ subsystem is crucial for keeping the Relayers’ order books up to date, fulfilling all customer swap requests, and processing otherwise challenging scenarios like gas-less or OTC orders.
One part that we did not discuss in earlier sections is the whitelist options. Each RFQ-Taker and RFQ-Maker request has an optional field to only interact with certain Takers or Makers. This helps run private & exclusive markets or dealing with only trusted parties.
Chesterton’s Fences This subsystem is not large. The RFQ Makers and RFQ Takers are all requires participants. Although the whitelists are not strictly necessary to the core product, they enable interfaces that otherwise would not be possible.
Special thanks to Sam Whitmore, Ren Lu, Avi Fein, and Dino for helping with earlier versions of this!