OverviewLeaderboardExplorerInsightsRekt MapClustersMethodology

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 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.

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_assets and bad_debt_usd per 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.

← Back to dashboard

>datumlab.xyz/liquidator-economy
Powered by Datum Labs