Methodology
Transparency is the foundation of credible research. This page documents exactly how the Liquidator Economy dashboard collects, prices, and aggregates liquidation data from Aave V3, SparkLend, Morpho, and Fluid on Ethereum mainnet, so you can verify, reproduce, or critique every number we publish.
1. Data Sources
All raw event data is read directly from the Ethereum mainnet via public JSON-RPC nodes. We do not depend on any centralized indexer like Dune, The Graph, or a third-party API for the underlying liquidation data.
Indexed contracts
- Aave V3 Pool: 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2
- SparkLend Pool: 0xC13e21B648A5Ee794902342038FF3aDAB66BE987
- Morpho: 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb
- Fluid Vault Factory: 0x324c5Dc1fC42c7a4D43d92df1eBA58a54d13Bf2d
Indexed events
Aave V3 and SparkLend share an identical LiquidationCall event (Spark is an Aave V3 fork):
event LiquidationCall( address indexed collateralAsset, address indexed debtAsset, address indexed user, // borrower uint256 debtToCover, uint256 liquidatedCollateralAmount, address liquidator, bool receiveAToken )
Morpho uses a different shape. Each liquidation carries a bytes32 market ID rather than token addresses. We call idToMarketParams(id) on the Morpho contract once per market to resolve the loan/collateral tokens, oracle, and LLTV, then cache the result:
event Liquidate( bytes32 indexed id, // market id, resolves to tokens address indexed caller, // liquidator address indexed borrower, uint256 repaidAssets, uint256 repaidShares, uint256 seizedAssets, uint256 badDebtAssets, // unique to Morpho: socialised bad debt uint256 badDebtShares )
Morpho also uniquely tracks bad debt, which is the portion of a liquidation the liquidator couldn't cover and which gets socialised among lenders. Aave and Spark can't have bad debt by design (they always require excess collateral).
Fluid has a different architecture still. Rather than a single pool contract, Fluid deploys a separate vault contract for every collateral/debt pair. We discover vault addresses by scanning the factory's NewPositionMinted event (the minter field is the vault address), then call constantsView() on each vault to resolve its supply and borrow tokens. Each vault emits its own LogLiquidate event:
event LogLiquidate( address liquidator_, uint256 actualColAmt_, // collateral seized from the vault uint256 actualDebtAmt_, // debt repaid on the vault's behalf address to_ // recipient of the seized collateral )
Block range
Aave V3 from block 16,291,127 (Jan 27, 2023). SparkLend from block 17,185,580 (May 2023). Morpho from block 18,883,124 (Dec 27, 2023). Fluid from block ~19,500,000 (April 2024). All protocols are continuously indexed up to the current block.
2. Pricing: On-Chain Oracles
We do not use market price APIs. Every USD value on this dashboard is computed from the protocol's own price oracle at the exact block of the liquidation. This is the same price the protocol itself used to authorize the liquidation.
Oracle contracts
- Aave V3 Oracle: 0x54586bE62E3c3580375aE3723C145253060Ca0C2
- SparkLend Oracle: 0x8105f69D9C41644c6A0803fDA7D03Aa70996cFD9
For every Aave V3 and SparkLend liquidation event, we call getAssetsPrices(address[]) on the relevant oracle at the historical block number of the liquidation. The oracle returns USD prices with 8 decimals of precision, sourced from Chainlink feeds (and Chronicle/RedStone aggregators on Spark).
Because we read prices at the exact block, our numbers reflect the on-chain reality at the moment the liquidation happened. Not a market average, not a delayed price feed, not an interpolation.
Morpho pricing: Morpho uses a separate oracle per market, so we first attempt to price every Morpho liquidation using the Aave V3 oracle (which covers the majority of tokens used as Morpho collateral/debt). For tokens the Aave oracle doesn't support (e.g. Pendle PT tokens, exotic LRTs, isolated pool stablecoins), we fall back to DeFiLlama's historical prices API with the block timestamp rounded to the nearest hour, and a 6-hour search window. These prices are cached in our database to ensure reproducibility.
3. Profit Calculation
We track two profit numbers for every liquidation: gross profit (the liquidation bonus before any costs) and net profit (what the liquidator actually keeps after gas).
Gross profit
collateral_usd = (liquidatedCollateralAmount / 10^collateral_decimals) * oracle_price debt_usd = (debtToCover / 10^debt_decimals) * oracle_price gross_profit = collateral_usd - debt_usd
Token decimals are read on-chain from each ERC20 contract's decimals() function and cached in our database. We do not hardcode 1e18. USDC uses 6, WBTC uses 8, etc.
Net profit
gas_cost_eth = gasUsed * effectiveGasPrice / 1e18 gas_cost_usd = gas_cost_eth * eth_price_at_block net_profit = gross_profit - gas_cost_usd
Gas data is fetched from the transaction receipt (eth_getTransactionReceipt) for each liquidation. ETH price for converting gas to USD is read from the Aave oracle at the same block.
Liquidation bonus efficiency (per asset)
avg_bonus_pct = AVG((collateral_usd - debt_usd) / debt_usd) * 100
The bonus efficiency table on the Insights page shows the average effective liquidation bonus extracted per collateral asset. This will usually be slightly below the protocol's configured bonus (typically 5–10%) because liquidators sometimes liquidate less than the maximum allowed amount.
4. Deduplication & Integrity
A single Ethereum transaction can contain multiple liquidation events (when one liquidator atomically liquidates several positions). To distinguish unique events from duplicates we use a composite key:
UNIQUE (tx_hash, collateral_asset, debt_asset, borrower, debt_to_cover)
This guarantees one row per real liquidation while still allowing legitimate multi-position liquidations within a single transaction.
Scan progress is checkpointed in a scan_state table after every batch flush, so an interrupted scan resumes from the last completed block and never double-counts.
5. Cascade Detection
A "cascade" on this dashboard is defined as any block containing two or more liquidation events. Cascades typically reflect chain reactions during volatile market moves where one liquidation pushes other positions below their health factor.
Cascade blocks : COUNT blocks with >= 2 liquidations Major cascade blocks: COUNT blocks with >= 5 liquidations Cascade events : SUM of events that occurred in cascade blocks
6. Rekt Map & ETH Price Overlay
The Rekt Map correlates daily liquidation volume with ETH price to reveal how market crashes drive liquidation cascades. It identifies the 10 worst liquidation days ("Rekt Days") by total collateral seized.
Daily aggregation
-- Each day: event count, total volume, profit, biggest single liq, -- unique liquidators, unique borrowers, top protocol by volume GROUP BY DATE(TO_TIMESTAMP(block_timestamp))
ETH price source
ETH prices come from our price_cache table, which stores hourly WETH prices fetched from DeFiLlama's historical prices API. We average these hourly prices per day and LEFT JOIN them onto the daily liquidation data. Days with no cached price show as gaps in the ETH price line.
ETH day-over-day change
For each Rekt Day in the "Hall of Rekt" table, we compute the ETH price change as a percentage relative to the previous day's average ETH price. This is calculated server-side by iterating the sorted daily array.
Top 10 ranking
ROW_NUMBER() OVER (ORDER BY total_volume DESC) as rekt_rank -- Days with rekt_rank <= 10 are marked as is_top_rekt = true
7. Cross-Protocol Bot Overlap
The overlap matrix on the Insights page answers: "Do the same liquidator addresses operate across multiple protocols?" This reveals shared infrastructure — bots that go where the profit is.
Pairwise overlap detection
-- Self-join: find liquidators active on BOTH protocol A and B -- a.protocol < b.protocol prevents double-counting pairs FROM liquidator_proto a JOIN liquidator_proto b ON a.liquidator = b.liquidator AND a.protocol < b.protocol
The diagonal of the matrix shows total unique liquidators per protocol. Off-diagonal cells show the count of addresses active on both protocols. Hover tooltips show combined volume and profit for shared liquidators.
Multi-protocol activity breakdown
We also count how many liquidators operate on exactly 1, 2, 3, or all 4 protocols. This uses array_length(array_agg(DISTINCT protocol), 1) per liquidator address.
8. Derived Metrics & Chart Methodology
Liquidation size distribution
Individual liquidation events are bucketed by their collateral seized amount (USD) into 8 ranges: $0–$100, $100–$1K, $1K–$10K, $10K–$50K, $50K–$100K, $100K–$500K, $500K–$1M, and $1M+.
Monthly profit (gross profit flooring)
The monthly profit chart sums GREATEST(gross_profit_usd, 0) per event. Negative gross profit values (which occur when collateral_usd < debt_usd due to oracle timing mismatches) are floored to zero so they don't distort the monthly aggregate. This is a conservative choice — the alternative would be to subtract these losses, which would understate liquidator earnings.
Profit concentration snapshot
Liquidators are ranked by total gross profit and grouped into tiers: Top 5, Top 6–10, Top 11–20, Top 21–50, and Everyone Else. This shows what share of total liquidation profit each tier captures.
Concentration over time
The Top 5 profit share is computed monthly. For each month, we rank all active liquidators by gross profit and compute what percentage the top 5 capture. Months with fewer than 5 active liquidators are excluded. Months where total profit is zero or negative show 100% concentration (trivially true).
Gas strategy comparison
For the top 20 liquidators by gross profit (with at least 5 gas-traced events), we compute average gas price (gwei), average gas cost (USD), total gas spent, and profit margin after gas. This reveals whether top bots outperform by paying higher gas for faster inclusion or by optimising gas efficiency.
Collateral-debt pair treemap
The top 30 collateral/debt pairs (by total volume, minimum 2 events) are displayed as a treemap where each cell's area is proportional to total liquidation volume for that pair.
9. Known Limitations
- Flashloan fees not deducted. Many liquidators use flashloans to source the debt token. The flashloan fee (typically 0.05–0.09%) is a real cost that is not currently subtracted from net profit. Future versions may detect and account for it.
- Swap slippage not deducted. After seizing collateral, most liquidators swap it back into the debt token (or stables) and incur DEX slippage and fees. We do not track this. Reported net profit is therefore an upper bound.
- Gas data coverage. A small share of historical transaction receipts cannot be fetched from free public RPCs (timeouts on very old txs). Coverage is shown on the Insights page; events without gas data are excluded from net-profit charts but still appear in gross-profit aggregates.
- MEV detection not yet implemented. We do not currently flag whether a liquidation went through Flashbots or another private mempool. This is on the roadmap.
- Bot clustering not yet implemented. What looks like dozens of independent liquidators may actually be a small number of operators running multiple bots. Wallet clustering by funding source is on the roadmap.
- Morpho bad debt is tracked but not yet visualised. Unlike Aave and Spark, Morpho can end up in a state where the liquidator couldn't fully cover a position. The remainder is “socialised” as bad debt across that market's lenders. We store this as
bad_debt_assetsandbad_debt_usdper event but don't yet surface it on the charts. A dedicated bad debt view is on the roadmap. - Morpho exotic tokens may have less reliable pricing. Some Morpho markets use tokens (Pendle PTs, niche LRTs, isolated pool stablecoins) that the Aave oracle doesn't support. For these we fall back to DeFiLlama historical prices, which have a ~1-hour granularity and can miss very short-lived price spikes. This can slightly skew net profit for liquidations in those specific markets.
- Fluid Smart Vaults (T2/T3/T4) are not yet covered. Fluid ships four vault types: T1 uses direct ERC20 collateral and debt, while T2, T3, and T4 use “smart collateral” or “smart debt” powered by Fluid's DEX. The pricing logic for smart vaults requires aggregating multiple underlying pool positions, which our first iteration doesn't support. We mark these vaults as unresolved and skip their liquidations. Adding T2/T3/T4 coverage is on the roadmap.
- Ethereum mainnet only. L2 deployments (Aave on Arbitrum, Optimism, Base, etc.) and other lending protocols (Compound V3, Venus, etc.) are not yet indexed.
10. Tech Stack
- RPC client: Viem (with public RPC fallbacks)
- Database: PostgreSQL (Neon serverless)
- Frontend: Next.js 14 App Router
- Charts: Recharts (SVG-based)
- Styling: Tailwind CSS
- Language: TypeScript
- Screenshots: html-to-image (SVG-native, 2x retina)
- Hosting: Vercel
Found a bug or have a methodology question? The dashboard is open research. We want it to be correct. Reach out and we'll investigate any discrepancy.