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 danning@flashbots.net 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):
- rank all the fills in 1 transaction by log index order
- 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.
- 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-WETHtrade, filled byUni V2,Uni V3, and a PMM)
- 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
... Frontendconvention; - 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
... Integratorsconvention. 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.tradestable. (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.tradestable 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 inpmmfield mapped thrumaker(see next section).
- For Non-solver Models:
- Using the DEX Base Table to index liquidity source.
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:
- For MEV Blocker: query distinct user tx from
mevblocker.raw_bundles
- 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
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_pairSame as
trade_usdHashflow 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.tradesamount_usd associated with the transaction hash from dex_aggregator.tradesTransaction 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.tradesdedup 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.tradesUniswap 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 Routerdedup result from
dex.tradesdedup 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.tradesamount_usd associated with the transaction hash from dex.tradesOn 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.tradestx_from address of the transaction check if
dex_aggregator.trades has the tx hash, if no, then nulldedup result from
dex.tradesdedup result from
dex.trades-
check for all RFQ system first, then otherwise for AMM use
project + version from dex.tradesfor hashflow, using the labeling based on integration contract; for other PMM, joined with addresses labeled.
token_pair associated with the transaction hash from dex.tradesamount_usd associated with the transaction hash from dex.trades1inch 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.tradesfor 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.tradesamount_usd associated with the transaction hash from dex.tradesusing the table
dune.teamm.result_maestro_trades_materialized created by whale_huntertx_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.tradesdedup result from
dex.trades-
check for all RFQ system first, then otherwise for AMM use
project + version from dex.tradesfor hashflow, using the labeling based on integration contract; for other PMM, joined with addresses labeled.
token_pair associated with the transaction hash from dex.tradesamount_usd associated with the transaction hash from dex.tradeslabeled thru the known Unibot router
tx_from address of the transaction Unibot Routerdedup result from
dex.tradesdedup result from
dex.trades-
check for all RFQ system first, then otherwise for AMM use
project + version from dex.tradesfor hashflow, using the labeling based on integration contract; for other PMM, joined with addresses labeled.
token_pair associated with the transaction hash from dex.tradesamount_usd associated with the transaction hash from dex.tradesDune Query Database
Type
Dune Title
Query Link
Materialized View Name
Refresh Time
Project
Orderflow View
Materialized View
dune.flashbots.result_uniswap_x_orderflow_view00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_uniswap_x_liquidity_view00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_alltime_uniswap_x_sankey_liquidity_view00:00-00:30
Project
Orderflow View
Materialized View
dune.flashbots.result_cowswap_sankey_orderflow_view00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_cowswap_sankey_liquidity_view00:00-00:30
Project
Liquidity View
Materialized View
dune.flashbots.result_alltime_cowswap_sankey_liquidity_view00:00-00:30
Raw
Orderflow View
Materialized View
dune.flashbots.result_orderflow_version_dex_dedup_table00:00-00:30
Raw
Orderflow View
dune.flashbots.result_orderflow_version_alltime_dex_dedup_table00:00-00:30
Raw
Materialized View
dune.flashbots.result_1inch_fusion_txs_7d00:00-00:30
Raw
Materialized View
dune.flashbots.result_1inch_fusion_txs_alltime00:00-00:30
Project
Orderflow View
Materialized View
dune.flashbots.result_1inch_fusion_orderflow_view00:30-01:00
Project
Liquidity View
Materialized View
dune.flashbots.result_1inch_fusion_liquidity_view00:30-01:00
Project
Liquidity View
Materialized View
dune.flashbots.result_alltime_1inch_fusion_liquidity_view00:30-01:00
Project
Orderflow View
Materialized View
dune.flashbots.result_orderflow_version_orderflow_sankey00:30-01:00
Project
Liquidity View
Materialized View
dune.flashbots.result_overall_lq_alltime01: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_of01:00-01:30
Project
Orderflow View
Materialized View
dune.flashbots.result_overall_of_alltime