Blog Post: Illuminating Ethereum's Order Flow Landscape
Flashbots logopresents

🎨 Orderflow.art

Illuminating Ethereum's order flow landscape. Empowering users with tools to visualize power and profit in the MEV supply network.

/avatars/angela.jpg/avatars/danning.png/avatars/jaden.jpg
🗺️

Orderflow.art Methodology

Sankey Spec

The sankey displays data from landed transactions from November 1, 2023. It is based on 2 end result datasets we produced: retail trade volume and retail liquidity impact.

Retail Trade Volume

Dune materialized view: dune.flashbots.result_overall_of (Orderflow View)
We built the Trade Volume sankey to monitor the distribution power and orderflow market share of each project along the order flow supply chain. To measure this properly, we need to account for the originally requested trade volume from retail traffic, hence there are two major differences between this result and generic total DEX trading volume:
  • It only includes a list of known router by frontends which is a better representative of real retail user traffic; and filters out unknown routers, which are likely bot volume today.
  • It’s deduplicated to avoid the overcounting of router’s multihops.
One known limitation is that it’s likely undercounting the total “retail traffic” as there can be smaller volume routers without labels in public datasets that we don’t cover. Please contact us at [email protected] if you see any missing routers that you would like to add!

Retail Liquidity Impact

Dune materialized view: dune.flashbots.result_overall_lq (Liquidity View)
The Liquidity Impact sankey is meant to show the market structure on the liquidity providing landscape on DEX trading space. Hence we include each liquidity provider’s total routed volume at each layer. It indexes all the liquidity sources and counts all the leg of hops within the trade, introduced by router or solvers. Note that when a router does a multihop to split a less liquid pair into 2 fills (e.g. route token A<->token B thru token A<->WETH, WETH<->token B - where its total volume will be 2x than what user requested to trade - we believe it’s inherent to its routing complexity hence it also counts as the liquidity source’s true volume.
 

Table Schema

Orderflow View
Column
hash
block_time
block_number
user
frontend
metaaggregator
solver
trade_pair
trade_usd
mempool
ofa
builder
Example
0x123…456
2023-10-02 18:18
19039288
0xabc…def
Metamask Swaps
Metamask Swaps Router
Hashflow
USDC-WETH
100.12
public
null
beaverbuild
Liquidity View
Column
hash
block_time
block_number
frontend
metaaggregator
solver
trade_usd
aggregator
token_pair
amount_usd
liquidity_src
pmm
Example
0x123…456
2023-10-02 18:18
19039288
Metamask Swaps
Metamask Swaps Router
Airswap
100.12
null
USDC-WETH
100.12
Airswap RFQ
Wintermute

Fields Definitions

orange background is columns only in orderflow view
blue background is columns only in liquidity view
column
type
description
nullable
hash
varbinary
transaction hash of user trade
no
block_time
timestamptz
timestamp of user trade
no
block_number
long
number of the block height
user
varbinary
address of the user who made the swap
no
frontend
varchar
best estimate of frontend used to make the trade; see Frontend in Methodology
no
metaaggregator
varchar
offchain system that pings multiple aggregators and/or solvers for quotes; see Metaaggregator in Methodology
yes
solver
varchar
entity that decided the route of the trade; see Solver in Methodology
no
trade_pair
varchar
sent and received token by the user, alphabetically ordered eg USDC-WETH
yes
trade_usd
numeric
deduped usd amount of the user trade; see DEX Dedup Table in Methodology
yes
token_pair
varchar
token pair of the swap route through the liquidity source; see DEX Base Table in Methodology
yes
amount_usd
numeric
usd amount of how much was routed through that liquidity source; see DEX Base Table in Methodology
yes
aggregator
varchar
solvers from Cowswap/UniswapX who pinged aggregator api — 1inch, 0x, paraswap, DODO, Hashflow; see Aggregator in Methodology
yes
liquidity_src
varchar
liquidity sourced for the trade; see Liquidity Source in Methodology
yes
pmm
varchar
private market maker who provided the liquidity thru RFQ systems; see PMM in Methodology
yes
mempool
varchar
whether the transaction was seen in the mempool; see Mempool in Methodology
no
ofa
varchar
which orderflow auction(s) saw the transaction; see OFA in Methodology
no
builder
varchar
which builder landed the transaction; see Builder in Methodology
no

Overall Methodology

DEX Base Table
DEX Base Table is used for baseline accounting of all the liquidity source used in trades, for all the non-solver models (solver models: CowSwap, Uniswap X, 1inch Fusion). It is largely based off the dex.trades table contributed by Dune data community. The dex.trades table has major DEX AMMs and RFQ and Limit Orders decoded and attributed, but can likely undercount newer AMMs and smaller liquidity sources. You can find the codebase for dex.trades in Dune’s spellbook repo.
We examined the coverage of dex.trades, and added decoding (see the UNION in query) for Hashflow (RFQ) Trades, and also 1inch Limit Order Protocol Trades (indexed in dex_aggregator.trades table, including 1inch’s RFQ and Limit Orders).
Note that because each liquidity source will log a swap event, the total volume combined from DEX Base Table will include overcounting from aggregator/solver routers’ “multihop” features (e.g. sourcing liquidity for a PEPE-USDC trade through 2 hops PEPE-WETH and WETH-USDC). We keep the per liquidity source volume in the liquidity version sankey diagram, but dedup the trade volume for orderflow version sankey to reflect more accurate retail side requested trade volume for measuring orderflow distribution power (see next section on DEX Dedup Table).
DEX Dedup Table
We dedupped the fills per transaction using following logic (query):
  1. rank all the fills in 1 transaction by log index order
  1. check for continuous 2 fills: if 1st fill’s output token is 2nd fill’s input token — if true, then take the input token of first fill, and 2nd fill’s output token, as the original requested trade pair.
  1. sum up all the fills grouped by the pairs, to total the trade size for multiple fills split across liquidity sources (e.g. a big USDC-WETH trade, filled by Uni V2, Uni V3, and a PMM)
  1. from here, even tho the multihop may not be fully cleaned up (because step2 does only 1 join, which will only handle 1hop, but e.g. 1inch router sometimes do 2hops); we will take the highest amount as the trade volume.
Frontend
The best estimate of where the orderflow’s entry point is, using a list of router labels.
  • For trades hitting the AMMs’ routers directly,
    • we indexed each project’s latest in-use router and name the entry point in the ... Frontend convention;
    • if trades are hitting their deprecated routers, it’s labeled as Unknown: Router Name;
  • For trades hitting the DEX aggregator’s routers,
    • we indexed major affiliates for 0x API using onchain data,
    • for other projects without onchain affiliate info, we named them in the ... Integrators convention. Note that this also include their own frontend traffic. (e.g. 1inch Website, CowSwap)
Metaaggregator
The field is meant to record a application when they source multiple routing solutions, e.g MetaMask: Swap Router who pings 1inch, Airswap, Openocean, Hashflow, 0x API, Paraswap etc and compare for the optimal price. Other examples include Kyber Router, DefiLlama.
By this definition, solver models also fall into this criteria (Unsiwap X, CowSwap, 1inch Fusion) where they are comparing a list of solvers (as called in Cowswap, or “fillers” on Uniswap, “resolvers” on 1inch Fusion).
Solver
expanded from its usual meaning, we are referring “Solver” here as the universal routing role, including for non-solver model cases.
  • For Solver Models: the whitelisted entities providing routing solutions to the project, recorded with their names registered with the protocol (solvers on CowSwap, fillers on Uniswap X, resolvers on 1inch Fusion)
  • For Non-solver Models: the routing entities, including AMM Routers, DEX Aggregator Routers; see the list of indexed routers here.
Aggregator
as different from its usual meaning —
  • For Solver Models: when the solver uses an aggregator (0x API, 1inch API, Paraswap etc) behind their routing, this will be recorded, by checking if the trade also appeared in dex_aggregator.trades table. (see codebase for the dune table in spellbook)
  • For Non-solver Models: null (aggregator like 1inch, 0x API are defined as the “solver” - as the universal routing role in above section)
Liquidity Source
  • For Solver Models:
    • For AMM Orders: using the dex.trades table to index liquidity sources.
    • For RFQ Orders: because solvers have their own direct RFQ integration with private liquidity sources (PMM), this field is left as null; PMM info are filled directly in pmm field mapped thru maker (see next section).
  • For Non-solver Models:
PMM
For all the projects, we are using a curated list of marker maker addresses (see query) to match the maker addresses for RFQ orders, based on a few sources:
  • Etherscan Labels
  • Nansen Wallet Profiler
  • Heuristics (e.g. same deployer from known addresses, etc)
Mempool
Using the Dune imported Mempool Dumpster dataset (see query), we are checking if any of the trade is seen in the mempool dataset, if yes then it’s labeled as public, if not then it’s private.
OFA
Currently we indexed MEV Blocker and Flashbots Protect (MEV-share), who have published their data on Dune:
  1. For MEV Blocker: query distinct user tx from mevblocker.raw_bundles
  1. For Flashbots Protect: query distinct user tx from landed txs (see query)
If the transaction was seen in either or both of them, we will label it with the OFA’s name.
Builder
Ideally builder’s pubkey is the most accurate identifier, but because there is no MEV-Boost Relay Data imported in Dune, we are using an approach by decoding builder’s signature from extraData in the blocks (see query).
Token Categories
When categorize token trading pairs, we identify 3 major types:
  • ETH/BTC Pairs: ETH or BTC paired with major Stablecoins (see query)
  • Stablecoin Pairs: Major stablecoin that is paired up (see query)
  • Longtails: everything else that is not in the set above.
 
Project-specific Methodology
Frontend
Meta-aggregator
tx_hash
User
Solver
trade_pair
trade_usd
aggregator
liquidity_src
pmm
token_pair
amount_usd
Note
null, not a meta-aggregator
Hashflow transactions are all transaction hashes that emitted the Hashflow Trade event, indexed and decoded by Dune table hashflow_ethereum.pool_evt_trade
-
-
The trade event emitted contains contract addresses of the baseToken , the token the user sold, and quoteToken , the token the user bought. We use the prices.usd Dune table to find the token symbol, and concatenate it with a - in an alphabetical order.
The trade event emitted contains the baseTokenAmount , the raw amount the user sold, and quoteTokenAmount , the raw amount the user bought. We convert the raw amount to a double and then divide by the decimals sourced from the prices.usd table to get the actual amount. This value is then multiplied by the price from the corresponding minute in the prices.usd table for the associated token contract address.
-
-
PMM liquidity sourced from Hashflow is identified using the contract_address field of the Hashflow Trade event emitted. Labels are copied from Etherscan’s token_tracker label associated with the address.
Same as trade_pair
Same as trade_usd
Hashflow is classified as a liquidity_src when it behaves as an aggregator in the tables to account for the case where 1inch sources liquidity from Hashflow.
Uniswap X
Uniswap X transactions are all transactions hashes that have emitted at least one Dutch Order Reactor Fill Event.
The user is the swapper address emitted in the Dutch Order Reactor Fill Event.
The “filler” is the maker address in Fill Event. Maker addresses are labeled using Maker Labels.
We extract the tokens sold and bought by the user by filtering for the transfers to and from the swapper address, which is extracted from the Dutch Order Reactor Fill event. We get ERC20 transfer token and amount information by joining Dune table erc20_ethereum.evt_Transfer on transaction hash and ETH transfer token and amount information by joining Dune table ethereum.traces where value is > 0 on transaction hash. The token pair is obtained by alphabetically concatenating the symbols associated with the token contract address in the prices.usd Dune table.
After getting the user’s sold and bought tokens and raw amounts using the transfers-to-swapper approach detailed on the left, we convert the raw amount to a double and then divide by the decimals sourced from the prices.usd table to get the actual amount. This value is then multiplied by the price from the corresponding minute in the prices.usd table for the associated token contract address.
project where transaction hash is present in dex_aggregator.trades table, which means that the filler pinged an aggregator API. Projects: 0x API, 1inch, 1inch Limit Order Protocol, DODO, Paraswap Fillers will also source liquidity from PMM liquidity aggregator Hashflow. Transactions are checked for the Hashflow Trade event and a row is added if present. See Hashflow for detailed methodology.
project + version where transaction hash is present in dex.trades table, which means the solver or aggregator that the solver pinged sourced liquidity from an AMM. There may be more that one row associated with each transaction hash, for example, for each hop.
if transaction hash is not present in dex.trades ,dex_aggregator.trades, or hashflow , then concatenate solver with ‘PMM’
token_pair associated with the transaction hash from dex.trades or dex_aggregator.trades See Hashflow for detailed methodology.
amount_usd associated with the transaction hash from dex.trades or dex_aggregator.trades See Hashflow for detailed methodology.
There are two primary edge cases with this approach: 1. Some solvers will split the user trade, causing 2 fill events per transaction hash. Since we do not rely on the fill event to calculate the trade pair and amounts — only to identify Uniswap X transactions, we keep one fill event per transaction hash. 2. Whenever a gnosis safe wallet transacts, there is an extra transfer that shows up as ‘WETH-WETH’. This is removed at the end. Due to the complexity of solver solutions, which combine aggregator API pings with direct liquidity sourcing from AMMs, we cannot determine from dex.trades whether the AMM liquidity was sourced directly by a solver or indirectly via an aggregator such as 1inch. So, our methodology unions all rows from dex_aggregator.trades and dex.trades. This is misleading in cases where an aggregator sourced the AMM liquidity, as the sankey will show the AMM liquidity sourced directly by the solver.
Cowswap
Cowswap transactions are labeled by filtering for transactions hashes where project = CoW Protocol from dex_aggregator.trades Dune table. This table is maintained by the Cowswap team. In orderflow view, transaction hashes are duplicated with different token pairs and amounts when there is a batch. In liquidity view, transaction hashes are deduplicated and amount_usd is summed when there is a batch.
taker column in dex_aggregator.trades associated with each transaction hash Note: during batches, there may be more than one row with the same transaction hash but unique takers.
The from_address of the settlement transaction hash is the Solver. The solvers are labeled using Cowswap’s Solver Labels Dune Table.
token_pair associated with the transaction hash from dex_aggregator.trades
amount_usd associated with the transaction hash from dex_aggregator.trades
Transaction hash is present in dex_aggregator.trades table with project != CoW Protocol, which means that the solver pinged an aggregator API. Projects: 0x API, 1inch, 1inch Limit Order Protocol, DODO, Paraswap Solvers will also source liquidity from PMM liquidity aggregator Hashflow. Transactions are checked for the Hashflow Trade event and a row is added if present. See Hashflow for detailed methodology.
If the solver sourced liquidity from an AMM, the transaction hash will appear in dex.trades with the associated project + version .
PMM liquidity sourced directly from makers are identified by maker address with project as 0x API on dex.trades.
token_pair associated with the transaction hash from dex.trades or dex_aggregator.trades See Hashflow for detailed methodology.
amount_usd associated with the transaction hash from dex.trades or dex_aggregator.trades See Hashflow for detailed methodology.
Cowswap uses batches, which means two or more separate user trades could have the same “settlement” transaction hash. This number represents the orders that flow through Cowswap’s offchain orderbook. This includes the orderflow from Cowswap’s Web UI, Safe Wallet, Balancer, among others.
MetaMask: Swap Router
any tx goin thru the Metamask Swap Router
tx_from address of the transaction
identified via aggregatorId in the input data
dedup result from dex.trades
dedup result from dex.trades
-
project + version where transaction hash is present in dex.trades table, which means the aggregator sourced liquidity from an AMM
PMM liquidity sourced from Hashflow is identified using the contract_address field of the Hashflow Trade event emitted.
token_pair associated with the transaction hash from dex.trades
amount_usd associated with the transaction hash from dex.trades
Uniswap Website & Wallet’s make up most of Uniswap Universal Router’s volume. So, we count all transaction hashes in dex.trades with a to_address of Uniswap Universal Router as a proxy for the orderflow that enters through Uniswap Website & Wallet.
tx_from address of the transaction
Uniswap Universal Router
dedup result from dex.trades
dedup result from dex.trades
-
Uniswap Universal Router routes exclusively to Uniswap V2 & V3. JOIN on transaction hash, and grabs project + version for all rows in dex.trades. This filters out transactions that interact with the Uniswap Universal Router but does not make a swap.
null
token_pair associated with the transaction hash from dex.trades
amount_usd associated with the transaction hash from dex.trades
On September 22, 2023, Uniswap started sending all Uniswap Wallet transactions to MEV Blocker by default, and at this moment, it cannot be toggled off. This number represents all trades on Ethereum that hit the Uniswap Universal Router. The data also includes transactions originating from Uniswap swap widget and possibly other unknown sources, as pinging this router is permissionless.
labeled based on 1inch’s entries in dex_aggregator.trades
tx_from address of the transaction
check if dex_aggregator.trades has the tx hash, if no, then null
dedup result from dex.trades
dedup result from dex.trades
-
check for all RFQ system first, then otherwise for AMM use project + version from dex.trades
for hashflow, using the labeling based on integration contract; for other PMM, joined with addresses labeled.
token_pair associated with the transaction hash from dex.trades
amount_usd associated with the transaction hash from dex.trades
1inch Limit Order Protocol are considered as liquidity source and is amended besides dex.trades as baseline volume. It includes 1inch Limit Orders (normal Limit Orders and Fusion orders), and also RFQ Orders (labeled based on version including rfq notation from dex_aggregator.trades table)
1inch Fusion
labeled checking settle_orders fill_order_to function call.
-
resolver label is based on 1inch's decoded table oneinch.fusion_executors
fusion trades info decoded from call data (see query)
fusion trades info decoded from call data (see query)
-
removed the duplicate fusion entry from 1inch Limit Order Protocol entries; check for all RFQ system first, then otherwise for AMM use project + version from dex.trades
for the orders matched with direct RFQ fills without swap event logged, check the token transfer into 1inch Settlement contract that is not from the resolver contract, map the maker address; for hashflow, using the labeling based on integration contract; for other PMM, joined with addresses labeled.
token_pair associated with the transaction hash from dex.trades
amount_usd associated with the transaction hash from dex.trades
using the table dune.teamm.result_maestro_trades_materialized created by whale_hunter
tx_from address of the transaction
used to be Uniswap V2 Router, until recently when the project switch to their own router (see histogram)
dedup result from dex.trades
dedup result from dex.trades
-
check for all RFQ system first, then otherwise for AMM use project + version from dex.trades
for hashflow, using the labeling based on integration contract; for other PMM, joined with addresses labeled.
token_pair associated with the transaction hash from dex.trades
amount_usd associated with the transaction hash from dex.trades
labeled thru the known Unibot router
tx_from address of the transaction
Unibot Router
dedup result from dex.trades
dedup result from dex.trades
-
check for all RFQ system first, then otherwise for AMM use project + version from dex.trades
for hashflow, using the labeling based on integration contract; for other PMM, joined with addresses labeled.
token_pair associated with the transaction hash from dex.trades
amount_usd associated with the transaction hash from dex.trades
 
Dune Query Database
Type
Dune Title
Query Link
Materialized View Name
Refresh Time
Project
Orderflow View
Materialized View
dune.flashbots.result_uniswap_x_orderflow_view
00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_uniswap_x_liquidity_view
00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_alltime_uniswap_x_sankey_liquidity_view
00:00-00:30
Project
Orderflow View
Materialized View
dune.flashbots.result_cowswap_sankey_orderflow_view
00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_cowswap_sankey_liquidity_view
00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_alltime_cowswap_sankey_liquidity_view
00:00-00:30
Raw
Orderflow View
Materialized View
dune.flashbots.result_orderflow_version_dex_dedup_table
00:00-00:30
Raw
Orderflow View
dune.flashbots.result_orderflow_version_alltime_dex_dedup_table
00:00-00:30
Raw
Materialized View
dune.flashbots.result_1inch_fusion_txs_7d
00:00-00:30
Raw
Materialized View
dune.flashbots.result_1inch_fusion_txs_alltime
00:00-00:30
Project
Orderflow View
Materialized View
dune.flashbots.result_1inch_fusion_orderflow_view
00:30-01:00
Project
Liquidity View
Materialized View
dune.flashbots.result_1inch_fusion_liquidity_view
00:30-01:00
Project
Liquidity View
Materialized View
dune.flashbots.result_alltime_1inch_fusion_liquidity_view
00:30-01:00
Project
Orderflow View
Materialized View
dune.flashbots.result_orderflow_version_orderflow_sankey
00:30-01:00
Project
Liquidity View
Materialized View
dune.flashbots.result_overall_lq_alltime
01:00-01:30
Project
Liquidity View
Materialized View
dune.flashbots.result_overall_lq
01:00-01:30
Project
Orderflow View
Materialized View
dune.flashbots.result_overall_of
01:00-01:30