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):
- 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-WETH
trade, 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
... 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 inpmm
field 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_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 nulldedup 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