Overview
Understanding DEX Transaction Complexity
When a user executes a swap on Ethereum, the transaction often involves multiple layers of intermediaries before reaching the actual liquidity pools. A user might interact with a wallet like Rabby, which routes through LiFi, which in turn uses 1inch, which finally pulls liquidity from Uniswap and Curve pools. Each layer serves a purpose—optimizing routes, aggregating liquidity, or providing user-friendly interfaces. However, this complexity makes it challenging to understand who facilitated the trade and where the actual liquidity came from. This model aims to create a generalized swap flow model to map the flow of a swap execution from its origin through intermediary routing systems like meta-aggregators, aggregators, or solvers, to the decentralized exchanges’ liquidity pools and vaults that settle it. This model helps users understand and explore the flow of DEX transactions through frontends and intermediaries.- Where trades originate (e.g., wallets, dApps, bot contracts, interfaces)
- How they are routed (via aggregators, meta-aggregators, or intent-based systems)
- Where liquidity is sourced (DEX protocols and pools that ultimately settle the swap)
Models
There are currently 2 versions of the orderflow model. Models with the
“unhydrated” prefix are models without frontend/intermediary labels. The v2 (New) orderflow model is currently only supported on Ethereum, Unichain, Arbitrum, and Base.
| Models | Version | Description |
|---|---|---|
dex.orderflow_liquidity_view | New | Provides a flattened view of liquidity sources, detailing project, protocol, and pool address for each transaction. |
dex.unhydrated_orderflow_v2 | New | Aggregates data from dex.trades and dex.aggregator_trades and includes additional fields for meta-aggregators, aggregators, solvers, and PMMs involved in the transaction. |
dex.orderflow | Legacy | Same data as dex.unhydrated_orderflow model, with the frontend labeled. |
dex.unhydrated_orderflow | Legacy | Provides an aggregated view of swap events from dex.trades and dex.aggregator_trades at the transaction level. Does not include meta-aggregators, aggregators, solvers, or PMMs. |
Data Schemas
Data Schemas
Model:
Model:
dex.orderflow_liquidity_view (New)The dex.orderflow_liquidity_view model is a flattend view of the dex.unhydrated_orderflow/_v2 model, where all the relevant swap details are compressed within a unit of transaction hash. The entiites (frontend, meta-aggregator, aggregator, solver, pmm) labels are normalized to their respective project names.In this mode, a swap that originates from 1 frontend and is routed to 3 liquidity sources will be represented as 3 rows in the model.| Column | Description |
|---|---|
frontend | The originating interface or application through which the user initiated the trade (e.g., MetaMask, Lifi, 1inch). |
meta_aggregator | The higher-level routing system that connects multiple aggregators or intent-based systems (e.g., Lifi, Bungee). |
aggregator | The protocol responsible for routing swaps across DEXs to optimize execution (e.g., 1inch, Paraswap, Kyberswap). |
solver | The intent solver or filler responsible for executing the trade on behalf of a user in intent-based systems (e.g., CoW Protocol solver, Uniswap X filler). |
solver_address | The on-chain address of the solver or filler that executed the swap. |
pmm | The private market maker (PMM) if the trade involved a off-chain liquidity provider (e.g., Tokenlon, 0x RFQ). |
pmm_address | The on-chain address of the private market maker (PMM). |
liquidity | The name or identifier of the liquidity source (DEX or pool) involved in the trade. For Uniswap project, the liquidity identifier is resolved to the corresponding version of the pool (e.g., Uniswap V3, Uniswap V4). |
liquidity_index | The position or ordering index of the liquidity source within the transaction, if multiple pools are used. |
liquidity_pool_address | The contract address of the liquidity pool that facilitated the trade. |
pair | The token pair exchanged in the liquidity pool (e.g., WETH-USDC). |
project | The DEX or protocol project associated with the liquidity source (e.g., Uniswap, Velodrome, Balancer). |
protocol | The specific protocol version or sub-implementation of the project (e.g., Uniswap V3, Curve StableSwap, Velodrome V2). |
usd_amount | The USD value of the trade attributed to this liquidity pool. |
v4_id | The unique Uniswap V4 hook identifier (if applicable), used for attributing swaps to specific hook contracts. |
swap_max_usd_amount | The maximum USD volume among all swap events within the transaction. By proxy, we can take this as the USD volume of the transaction. |
swap_total_usd_amount | The total USD volume summed across all swaps in the transaction, both executed by pools (in dex.trades) and routed through intermediaries (in dex.aggregator_trades). |
liquidity_details | A structured JSON field containing detailed pool-level trade data (project, protocol, pair, pool address, USD volume, and log index). For v4 Uniswap, the pool id is also included. |
transaction_hash | The unique identifier (hash) of the transaction on-chain. |
transaction_index | The index of the transaction within the block. |
block_timestamp | The timestamp when the block containing the transaction was confirmed. |
block_number | The block height in which the transaction was included. |
swapper_address | The address of the end user or contract that initiated the swap. |
from_address | The originating address from which the transaction was sent. |
to_address | The recipient or target contract address to which the transaction was directed. |
_created_at | The timestamp when this record was first created in the dataset. |
_updated_at | The timestamp when this record was last updated or refreshed. |
dex.orderflow (Legacy)| Column Name | Description |
|---|---|
| frontend | The frontend interface used for the transaction |
| block_number | The block number in which the transaction was included |
| block_timestamp | The timestamp of the block in which the transaction was included |
| transaction_hash | The hash of the transaction |
| transaction_index | The index of the transaction within the block |
| swapper_address | The address of the user performing the swap. For most trades, this comes from the transaction_from_address field in dex.trades / dex.aggregator_trades. However, for UniswapX and CowProtocol swaps, it comes from the sender field instead. |
| from_address | The address initiating the transaction (msg.sender) |
| to_address | The address receiving the transaction |
| is_aggregator | Flag indicating if the transaction is an aggregator |
| usd_volume | The max usd_amount of the swap within the entire transaction |
| total_usd_volume | The sum of the usd_amount of all swaps within the transaction |
| senders | Array of addresses sending tokens in the transaction |
| recipients | Array of addresses receiving tokens in the transaction |
| tokens_sold | Array of tokens sold in the transaction |
| integrators | Array of integrator names involved in the transaction |
| integrator_tags | Array of integrator contract addresses |
| aggregator_source | Source of the aggregator |
| aggregator_usd_volume | USD volume of the aggregator portion |
| aggregators | Array of aggregator contracts involved |
| aggregators_count | Count of aggregators involved |
| aggregator_details | JSON details of aggregator swaps |
| liquidity_source | Array of liquidity sources used |
| liquidity_usd_volume | USD volume from liquidity sources |
| liquidity_pools | Array of liquidity pool addresses used |
| liquidity_pools_count | Count of liquidity pools involved |
| liquidity_details | JSON details of liquidity pool swaps |
| total_trades | Total number of trades in the transaction |
| unique_id | Unique identifier for the transaction |
Methodology
Two core abstractions are used to construct the orderflow schemas:dex.trades and dex.aggregator_trades (Table 2).
Table 2: Core abstractions used to construct the orderflow schemas
| Models | What it Represents | Liquidity Source | Typical Examples |
|---|---|---|---|
dex.trades | Captures AMM swaps emitted directly by liquidity pools, reflecting raw on-chain execution. | AMM pools (e.g., Uniswap v2/v3, Curve, Balancer), PMMs, CoWs (if directly settled) | User swaps on Uniswap v3 pool 0x…, Curve pool 0x… |
dex.aggregator_trades | Represents swaps routed through intermediaries such as aggregators, intent-based protocols, or RFQ systems (e.g., Odos, 1inch, CoW Protocol solvers). These swaps source liquidity from AMMs, PMMs, or solver networks. | Aggregators/routers (e.g., 1inch, Odos, Velodrome Router) which tap into liquidity from AMMs, RFQs, or CoWs. RFQ, CoW, and intent-based swaps are included in this model. | User swaps on Odos → Odos routes into Uniswap v3 and Curve |
The Core Challenge: Attribution in Multi-Layered Transactions
Consider a typical complex swap: A user connects their MetaMask wallet to Jumper Exchange (LiFi’s frontend), which routes through KyberSwap Aggregator, ultimately pulling liquidity from two Uniswap V3 pools and one Curve pool. This single transaction generates multiple swap events across different protocol layers. The fundamental question becomes: How do we attribute this transaction? We sought to identify the following entities involved in a swap:| Entity | Definition / Role | Examples |
|---|---|---|
| Frontend | User-facing interface that collects swap intent and submits transactions. | Uniswap UI, MetaMask Swaps, Rainbow Wallet |
| Meta-Aggregator | Routes swaps across multiple aggregators to find the best execution path. Intent-based protocols are currently grouped as meta-aggregators. | CoWSwap, LiFi, KyberSwap |
| Aggregator | Optimizes trade execution across multiple DEX pools and liquidity sources. | 1inch, OpenOcean, Matcha |
| Liquidity Source | Pools or venues providing actual token liquidity for swaps. | Uniswap v2/v3, Curve, Balancer, Kyber AMM |
| Private Market Maker (PMM) | Off-chain liquidity providers offering RFQ prices and competitive execution for large trades. | Wintermute, Flowdesk |
| Solvers | Agents that determine optimal execution across DEXs, PMMs, and liquidity pools; can batch or net trades. | CoW Protocol solvers, UniswapX fillers |
Stage 1: Categorizing DEX Protocols
We classify all DEX protocols into different tiers based on their role in the execution mechanism. This classification reflects both the technical complexity of each protocol type and its position in the execution stack. Every swap event, whether from a high-level aggregator or a direct pool interaction, is tagged with its protocol category and assigned the corresponding priority ranking. Table 3: Protocol Classification Hierarchy| Priority Rank | Protocol Category | Orderflow Entity | Examples | Core Function | Data Source |
|---|---|---|---|---|---|
| 1 | Intent-Based Protocols | Meta-Aggregators | CoW Protocol, Uniswap X, 0x Settler | Batch auctions and solver competitions that optimize execution | dex.aggregator_trades |
| 2 | Meta-Aggregators | Meta-Aggregators | Bungee, LiFi, Kyber Aggregator v2 | Orchestrate multiple aggregators for cross-chain or complex routes | dex.aggregator_trades |
| 3 | Standard Aggregators & RFQs | Aggregators | 1inch AR, 1inch LOP, Paraswap, OpenOcean | Route trades across multiple liquidity sources | dex.aggregator_trades |
| 4 | AMM / Vaults Swaps | Liquidity Sources | Uniswap, Curve, Balancer, Fluid, Aerodrome | The actual liquidity pools where tokens are exchanged | dex.trades |
- Intent-based protocols (rank 1) receive the highest priority because of their fundamentally different execution model. Instead of deterministic routing, they rely on solvers or batch auctions.
- Meta-aggregators (rank 2) are distinguished from standard aggregators because they make routing decisions across multiple aggregation layers.
- Standard aggregators (rank 3) represent the conventional routing layer, whether through traditional aggregation algorithms or request-for-quote systems where professional market makers provide liquidity.
- Direct AMM pool or vault swaps (rank 4) represent the liquidity sources of most DEX swaps, where the underlying tokens are exchanged.
Stage 2: Labeling Transaction Origin
Most transactions don’t explicitly encode which wallet or frontend the user employed. We rely on a mix of transaction-level contract interactions and decoded event log data to infer the origin. Several aggregators emit clues about the transaction origin in their event logs. These can be either string text stating the integrator of the DEX aggregator, or addresses pointing to the referral or affiliate address of the swap. For example, KyberSwap’sClientData events, LiFi’s integrator tags, and Paraswap’s partner addresses are identifiers that tell us whether the user came from MetaMask, Rabby, Ledger, or another interface.
Table 4: Transaction Origin Attribution
| Priority Rank | Protocol Category | Data Source | Origin Logic |
|---|---|---|---|
| 1 | Intent-Based Protocols | dex.aggregator_trades | The project name is assigned as the origin if the transaction-level to_address is the contract address emitting the swap event. |
| 2 | Meta-Aggregators | dex.aggregator_trades | We label the origin as the integrator if populated. Integrator fields for the following protocols are populated based on event logs: - KyberAggregator v2: source field in decoded ClientData event- LiFi: integrator field emitted in swap event- Bungee Protocol: routeName field is a hex string that can be mapped to integrators |
| 3 | Standard Aggregators & RFQs | dex.aggregator_trades | We label the origin as the integrator if populated. Integrator fields for the following protocols are populated based on event logs: - 0x: Affiliate Address or Fee Recipient Address mapping to integrators - OpenOceanV2: referrer address mapping to integrators- Paraswap: partner address mapping to integrators- OdosV2: referralCode address mapping to integrators |
| 4 | AMM / Vaults Swaps | dex.trades | We leave the origin data for these swaps as null. If no aggregators with integrator data are present, we rely on labeling the contract address interaction to infer the transaction origin. |
Stage 3: Transaction-Level Aggregation and Conflict Resolution
Once each swap event is categorized and labeled with origin information, we aggregate all events at the transaction level usingtransaction_hash as the key. This consolidation produces a single orderflow record per transaction, but it requires resolving conflicts when multiple protocols of different types participate.
Selection Logic: Priority-Based with Chronological Tiebreaking
When multiple protocols appear in a single transaction under each entity (e.g., meta-aggregator), we apply a two-tier selection rule:- Primary criterion: Priority ranking (lowest rank number = highest priority)
- Secondary criterion: Event order (lowest
log_index= first event)
meta_aggregator.
Scenario B: Same Protocol Type
When multiple protocols share the same priority—for example, both LiFi and Bungee (both rank 2) routing portions of the same trade—the chronological tiebreaker applies. The protocol whose event appears first (lowest log_index) is selected.
Stage 4: Final Schema Mapping
The aggregation process produces a transaction-level orderflow record with the following attribution dimensions:| Field Name | Data Type | Populated By | Description |
|---|---|---|---|
| origin | varchar | Whenever integrators are present. If not, populated by labeling transaction_to_address from Allium’s label. | The frontend or entry point of the transaction. |
| integrators | variant (array) | Aggregators with event metadata. | Normalized frontend/wallet identifiers (e.g., 'ledger', 'exodus', 'jumper_exchange') extracted from KyberSwap ClientData, LiFi tags, Paraswap partner fields |
| meta_aggregator | varchar | Intent-based (rank 1) or meta-aggregators (rank 2) | Project name of highest-priority meta-aggregator or intent protocol (e.g., 'lifi', 'cow_protocol') |
| aggregator | varchar | Standard aggregators (rank 3) when no rank 1-2 present | Project name of standard aggregator (e.g., 'paraswap_v5', '1inch'). NULL if meta-aggregator exists |
| liquidity_details | variant (array) | All AMM swaps from dex.trades | Array of pool objects with project, protocol, liquidity_pool_address, pair, usd_amount, log_index, id (V4 hooks). Excludes RFQ fills |
| solver_address | varchar | Intent-based protocols only | Solver/filler address: CoW = transaction_from_address, Uniswap X = filler field, 0x Settler = contract_address |
| pmm_address | varchar | RFQ and limit order protocols | Private market maker address from maker, executor, or signerWallet fields (1inch LOP/AR, Paraswap RFQ, Tokenlon, AirSwap) |
| swapper_address | varchar(42) | All transactions | For intent-based swaps: sender_address, others use transaction_from_address |
| from_address | varchar(42) | All transactions | Transaction sender (transaction_from_address) |
| to_address | varchar(42) | All transactions | Transaction recipient (transaction_to_address) |
| usd_volume | float | All transactions | Largest single swap leg, approximates user’s trade size |
| total_usd_volume | float | All transactions | Sum of all swap volumes including intermediate hops |
| user_token_input | varchar | All transactions | First token sold in chronological order |
| user_token_output | varchar | All transactions | Last token bought in chronological order |
| block_number | bigint | All transactions | Block number of the swap execution |
| block_timestamp | timestamp_ntz(9) | All transactions | Block timestamp of the swap execution |
| transaction_index | bigint | All transactions | Transaction position in block |
| transaction_hash | varchar(66) | All transactions | Unique transaction identifier |
| _created_at | timestamp_ntz(9) | All transactions | Record creation timestamp |
| _updated_at | timestamp_ntz(9) | All transactions | Record update timestamp |
Liquidity View Flattening
To enable granular analysis of liquidity routing patterns, thedex.orderflow_liquidity_view flattens the transaction-level schema into a liquidity-source-level schema. This transformation creates one row per liquidity source. If a swap splits into 4 different AMM pools, it will be represented as 4 rows in the liquidity view model. This allows users to plot the output in a Sankey chart and also enables queries like:
- “Which AMM pools does LiFi route through most frequently?”
- “What percentage of CoW Protocol swaps use Uniswap V3 vs V4?”
- “Which solvers access which PMMs?”
Flattened Schema Structure
The view maintains all transaction-level attribution fields (origin, meta_aggregator, aggregator, solver, etc.) and adds per-liquidity-source columns:
| Field Name | Data Type | Source | Description |
|---|---|---|---|
| liquidity | varchar | liquidity_detail['project'] or ['protocol'] | Normalized liquidity source name (e.g., ‘Uniswap V3’, ‘Curve’) |
| liquidity_index | bigint | Array position | Sequential order in which liquidity source was accessed (0 = first) |
| liquidity_pool_address | varchar(42) | liquidity_detail['liquidity_pool_address'] | Pool contract address for AMM trades |
| pair | varchar | liquidity_detail['pair'] | Trading pair identifier (e.g., ‘WETH-USDC’) |
| project | varchar | liquidity_detail['project'] | Raw project name (e.g., ‘uniswap’, ‘curve_v1’) |
| protocol | varchar | liquidity_detail['protocol'] | Protocol version (e.g., ‘uniswap_v3’, ‘uniswap_v4’) |
| usd_amount | float | liquidity_detail['usd_amount'] | USD volume routed through this specific liquidity source |
| v4_id | varchar | liquidity_detail['id'] | Uniswap V4 / Eulerswap V1 hook identifier (pool ID with hooks) |
Data Labels
We source the labels of solvers, frontends, private market makers, and hooks from various publicly available sources. Frontend labels are identified by a mix of integrators used by DEX aggregators. The table below outlines the labeling heuristics for the intermediaries involved in the swap.| Intermediaries | Labeling Heuristics | Label Source |
|---|---|---|
| Origin | For intent-based protocols, we attribute the swap frontend to the DEX project: cow_protocol, uniswap_x, zeroex_settler if the contract address is also the to_address of the swap.For aggregator protocols with integrator data, we will label them and attribute them as the frontend: zeroex_api, lifi, kyberswap_aggregator_v2, zeroex_v4, paraswap_v5, openocean_v2.For aggregated orderflow without any labels, we will rely on labeling the contract interaction as the frontend (i.e., labeling the transaction_from_address). | Allium maintains a repository of DEX aggregators and routers from publicly available sources such as block explorers, public GitHub repositories, and project documents. This list is periodically updated by our attribution team as we identify unlabeled contracts generating large volumes. |
| Private Market Makers & Solvers | Sourced from publicly external sources. PMMs and solvers are identified by their addresses. | Seeded from Flashbots’s Maker List. Additionally, we source unlabeled PMMs & solvers from publicly available sources. |
| Liquidity Source | Based on the underlying DEX project where the swap receives its liquidity. For Uniswap project, this is reflected as Uniswap V2, V3, and V4 based on the protocol version. | From project field of dex.trades |
| UniswapV4 Hook | We identify the hook ID of the swap event and the corresponding hook contract that it is associated with. | Provided by Uniswap Foundation and maintained by the UF team from this Dune query. |
Design Assumptions and Limitations
The liquidity flow schema was designed to generalize how swap executions move through the DeFi stack, beginning at user-facing interfaces, passing through intermediaries such as aggregators and solvers, and concluding in settlement across DEX liquidity pools. In creating a standardized model, we have made certain simplifications and assumptions, leading to inherent trade-offs in attribution. DeFi infrastructure evolves constantly. New aggregators launch, existing ones add features, and protocols migrate to new contract versions. The schema requires active curation to stay accurate:- Contract registries must be updated as protocols deploy new routers
- Event decoding must expand to parse new integrator metadata formats
- Classification rules need periodic review as protocol boundaries shift
Known Gaps
There are known gaps in the coverage of aggregators and DEXs. Frontend and volume coverage of protocols not indexed by Allium will not be reflected in the orderflow schema. The following projects/protocols have been added to our roadmap for support.| Projects | Category | Additional Notes |
|---|---|---|
| Bebop Aggregator | Aggregator | Planned support by Q1 2026 |
| LiquidMesh | Aggregator | Planned support by Q1 2026 |
| MetaMask | Aggregator | *Not currently indexed, as we use contract interaction to infer this. Planned support by Q1 2026 |
| Angstrom V4 Integrator | Swaps | Planned support by Q1 2026 |