HopeLend hETHWBTC Empty-Market liquidityIndex Exploit (2023-10-18)

  • Name: HopeLend hETHWBTC empty-market liquidityIndex exploit
  • Date: 2023-10-18
  • Protocol: HopeLend / Hope.money
  • Chain: Ethereum
  • Category: empty-market liquidityIndex inflation / precision-loss burn / cross-market lending drain
  • Loss: about 526 ETH (roughly 835K at the time)
  • Summary: HopeLend left its hETHWBTC reserve effectively uninitialized for about 73 days, with no real outside liquidity, so an old listing had drifted back into an effectively fresh market. The exploit path combined two Aave-style accounting failures inside that empty reserve. First, the attacker deposited 2,000 WBTC, then used HopeLend flash loans to concentrate roughly 1.26 WBTC of LP fee income per loop into a nearly nonexistent hETHWBTC supply, pushing the reserve liquidityIndex from the normal 1e27 scale to about 7,560,000,001e27. That made a single 1e-8 unit of hETHWBTC appear to be worth about 75.6 WBTC, which HopeLend then accepted as collateral against the rest of the protocol. Second, after draining other markets, the attacker used rayDiv truncation in the burn path to withdraw 113.4 WBTC while burning only one 1e-8 hToken unit instead of the nearly 2e-8 units economic reality required. A generalized frontrunner copied the exploit from the mempool, landed the profitable transaction first, and paid a massive validator bribe out of the proceeds.
  • Trigger / entry point:
    • HopeLend’s hETHWBTC reserve at 0x25126F207Db7dC427415eA640ce0187767403907 existed but had essentially zero live liquidity, so the first meaningful attacker could dominate the entire reserve state.
    • The core lending pool at 0xc74b72bbf904bac9fac880303922fc76a69f0bb4 used Aave-style liquidityIndex accounting, where flash-loan LP fees increase supplier value pro rata.
    • Because only a dust amount of hETHWBTC remained after the attacker burned almost all supply, each later flash-loan fee update moved the index by an absurd amount.
    • HopeLend still treated the manipulated hETHWBTC as valid collateral for borrowing WETH, USDT, USDC, HOPE, and stHOPE from sibling markets.
  • Root cause:
    • HopeLend allowed an effectively empty reserve to remain live and collateral-relevant, so a single attacker could monopolize liquidityIndex growth.
    • More specifically, the protocol treated old reserve as if it still meant mature reserve, instead of reclassifying hETHWBTC as effectively fresh again once real supplier breadth had collapsed and the next meaningful actor could redefine the market’s accounting.
    • Flash-loan fee accounting assumed a healthy supplier base; in an empty reserve, the LP-fee mechanism became a way to print collateral value for the only remaining hToken holder.
    • The burn path used rayDiv floor rounding, which became catastrophic once WBTC’s 8-decimal granularity and the extreme liquidityIndex made the economically correct burn amount just under 2 minimum hToken units.
    • In short: a dormant empty market, unrevoked cross-market solvency authority, fee-driven liquidityIndex inflation, and attacker-favorable burn truncation formed one exploit pipeline.
  • Exploit path:
    1. An original searcher identified the bug and prepared an attack contract in block 18377039, but a generalized frontrunner monitoring the mempool copied the exploit and ultimately captured the profitable execution in block 18377042.
    2. The exploit sourced 2,300 WBTC via an Aave flash loan, then deposited 2,000 WBTC into HopeLend’s empty hETHWBTC reserve to mint 2,000 hETHWBTC.
    3. The attacker next took a 2,000 WBTC HopeLend flash loan from the same reserve, transferred that 2,000 WBTC directly back into the reserve contract, and then withdrew 1,999.99999999 WBTC, leaving only 0.00000001 hETHWBTC outstanding.
    4. That tiny remaining hToken balance was the key setup. Each 2,000 WBTC flash loan generated about 1.26 WBTC of LP fees for suppliers (0.09% fee times the LP share), and with only 1e-8 hETHWBTC left, those fees were effectively credited to a single dust unit.
    5. By repeating the flash-loan loop roughly 60 times, the attacker pushed liquidityIndex to about 7,560,000,001e27, so the remaining 1e-8 hETHWBTC read as collateral worth about 75.6 WBTC.
    6. Using that fake collateral value, the attacker borrowed assets from HopeLend’s other pools, including about 175.4 WETH, 145,522.220985 USDT, 123,406 USDC, 844,282 HOPE, and 220,617 stHOPE, which were later swapped into more liquid assets.
    7. The cash-out phase then exploited burn truncation. After depositing 151.20000002 WBTC, the attacker received 0.00000002 hETHWBTC; withdrawing 113.4 WBTC should have burned about 0.000000019999999998 hETHWBTC, but rayDiv floor rounding burned only 0.00000001.
    8. With one minimum hToken unit preserved, the attacker could loop 75.60000001 WBTC deposits against 113.4 WBTC withdrawals, producing roughly 37.8 WBTC of value per cycle until the initial Aave flash loan was repaid and the rest of the stolen assets remained as profit.
  • What the attacker needed to be true:
    • The hETHWBTC reserve had to stay effectively empty, with no real supplier base to dilute fee accrual.
    • HopeLend flash loans had to charge fees that flowed back into the same reserve’s liquidityIndex.
    • The protocol had to accept inflated hETHWBTC value as real collateral against deeper-liquidity sibling markets.
    • Burn math had to round down in favor of the user once the correct burn amount was just under 2 minimum hToken units.
    • The attacker needed enough external flash liquidity to set up the initial WBTC position and complete the loop in one block.
  • Technical anatomy worth remembering:
    • This was the dormant-reserve cousin of Radiant’s fresh-market exploit. Both are Aave-style empty-market attacks where liquidityIndex, not exchange rate, is the printable variable.
    • The critical setup step was not only the flash loan; it was the deliberate reduction of hToken supply to a single 1e-8 WBTC-denominated unit before fee accrual started compounding.
    • WBTC’s 8-decimal granularity mattered. The bug became monetizable because the economically correct burn amount landed just below 2 minimal hToken units, so flooring it to 1 created a huge gap.
    • The mempool twist matters too: the profitable transaction was not necessarily executed by the original discoverer, but by a frontrunner who copied the exploit and paid about 263 ETH as validator bribe to secure ordering.

Three reserve-authority promotions this incident collapsed

  1. An old reserve was still treated as if age itself meant economic maturity

    • hETHWBTC had existed for about 73 days, but that only proved the reserve was old and reachable.
    • It did not prove the reserve still had a healthy supplier denominator or that the next meaningful actor could no longer define what reserve-side fee income meant.
    • HopeLend effectively let listed for months stand in for mature enough to keep full collateral authority even after the market had drifted back toward attacker-ownable dust.
  2. That attacker-owned dust denominator was still promoted into canonical supplier-side solvency truth

    • Once the attacker compressed supply down to 0.00000001 hETHWBTC, the reserve’s next unit of flash-loan fee income no longer looked like ordinary shared supplier yield.
    • It looked like authorship over liquidityIndex itself, because one dust unit now captured almost the entire next increment of reserve-side value.
    • The dangerous promotion was accepting the reserve can still publish a supplier balance as if it already implied that published balance still deserves ordinary accounting trust under a healthy denominator.
  3. That published supplier-side truth still inherited immediate cross-market reserve-spending authority

    • The manipulated scaledBalance * liquidityIndex output did not stay local to the dormant WBTC reserve.
    • HopeLend still let that printed mark fund real borrowing from WETH, USDT, USDC, HOPE, and stHOPE markets, and later let burn truncation turn the same distorted state into under-burned WBTC withdrawals.
    • In other words, old reserve exists, that reserve may still publish trustworthy supplier value, and sibling markets must already spend against that value were collapsed into one joined state transition.
  • Representative transactions and artifacts:
    • Successful exploit tx: 0x1a7ee0a7efc70ed7429edef069a1dd001fbff378748d91f17ab1876dc6d10392
    • Original searcher / attempted attacker: 0x1F23eb80f0c16758E4A55D48097c343bD20Be56f
    • Profitable frontrunner EOA: 0xa8bbb3742f299b183190a9b079f1c0db8924145b
    • Post-exploit fund recipient used in negotiations: 0x9a9122Ef3C4B33cAe7902EDFCD5F5a486792Bc3A
    • HopeLend lending pool: 0xc74b72bbf904bac9fac880303922fc76a69f0bb4
    • hETHWBTC reserve / hToken: 0x25126F207Db7dC427415eA640ce0187767403907
    • Additional cash-out helper contract: 0x5a63e21ebded06dbfcb7271fbcef13c9f0844e74
  • Response / mitigation:
    • Hope.money negotiated with the address controlling the recovered proceeds, ultimately moving most of the funds into a Gnosis Safe after allowing the frontrunner to keep a small bounty.
    • The incident highlighted that Aave-style forks need the same empty-market hygiene as Compound forks: unused reserves cannot stay live and collateral-relevant just because their steady-state math looks familiar.
    • It also reinforced that precision testing has to include extreme empty-market states and low-decimal assets like WBTC, not only normal-scale balances.
    • The deeper lifecycle lesson is that a dormant reserve needs an explicit path to lose collateral authority once it becomes attacker-ownable again; historical listing age is not a substitute for current breadth.

Pattern tags

  • supplier-index-inflation
  • empty-market-exchange-rate-inflation
  • fresh-market-initialization-failure
  • The preserved shape is sharper than generic flash-loan fee bug in an old Aave fork: HopeLend let a long-listed reserve fall back into an attacker-ownable opening denominator, let flash-loan premiums compound into liquidityIndex over that dust supply, and then let the printed supplier-side mark become immediate cross-market borrow power.
  • This was also a clean old reserve != mature reserve failure. HopeLend’s problem was not just that hETHWBTC was empty; it was that the protocol never reclassified that empty state as economically equivalent to a fresh market again.

Why the exploit worked

  • HopeLend let an old WBTC reserve keep full collateral authority after it had already drifted back into an effectively fresh state. Once the attacker reduced hETHWBTC supply to a single 1e-8 unit, the reserve no longer had a meaningful outside supplier base; it had one actor deciding what the next unit of fee income would mean.
  • In that state, flash-loan premiums stopped behaving like neutral protocol revenue and became solvency authorship. The reserve’s own liquidityIndex machinery turned repeated 2,000 WBTC flash-loan fees into collateral value for the only remaining dust supplier, without any external oracle failure.
  • The rayDiv burn truncation then completed the cash-out path rather than standing alone. Without the under-burn, HopeLend would still have had a fake-collateral problem but a harder time converting it back into withdrawable WBTC; without the empty-market setup, the same rounding loss would have been economically small. The exploit paid because dormant-reserve lifecycle failure, fee-socialized index inflation, and low-decimal burn rounding lined up in one pipeline.
  • Downstream borrowing imposed no second distrust boundary. A reserve that had become first-actor-capturable again was still allowed to define borrow power for WETH, USDT, USDC, HOPE, and stHOPE, even after liquidityIndex growth had become impossible under any healthy supplier distribution.
  • The preserved design lesson is therefore broader than watch empty Aave markets: reserve lifecycle, supplier-index socialization, burn arithmetic, and cross-market collateral admission were one security object, and HopeLend split them apart.

Detection and audit pivots

  • Ask the lifecycle question directly: what onchain fact proves an old reserve is still economically mature, and what demotes it back into quarantine if supplier breadth later collapses toward dust? If the answer is only this market has existed for months, the control does not exist.
  • Reconstruct the entire supplier-value publication path: flash-loan premium routing, liquidityIndex, hToken burn math, collateral factor, and sibling-market borrow checks should all tell one coherent story before a low-liquidity reserve can matter system-wide.
  • Simulate the exact dust state that made HopeLend exploitable: one 1e-8 WBTC-denominated hToken unit, repeated same-reserve flash loans, and withdrawals under extreme index values. If the exploit only appears when the reserve becomes effectively empty again, the test harness still has to cover that state.
  • Treat low-decimal assets as adversarial when paired with rebasing supplier indexes. WBTC-sized minimum units make 1.99999999 versus 1 hToken burns economically catastrophic in a way 18-decimal assets may not reveal during casual review.
  • Look for a downstream distrust boundary. Can a dormant reserve remain listed while collateral factor stays 0, flash loans stay off, or debt caps stay too small for one printed mark to drain sibling pools? If not, the protocol is still trusting old listings more than live supplier reality.

Failure-prevention checklist

  • Reclassify dormant reserves as effectively fresh when supplier breadth or scaled supply collapses toward attacker-ownable dust. A 73-day-old market with one meaningful supplier should not retain the same collateral authority as a deep reserve.
  • Keep same-reserve flash-loan premiums from socializing into liquidityIndex while the denominator is thin. Route those fees to treasury, a pending bucket, or a quarantined reserve state until supplier breadth is healthy enough to deserve ordinary yield treatment.
  • Separate reserve reachability from cross-market solvency authority. A dormant market can stay visible or even deposit-open while collateral factor remains 0, flash loans stay off, and debt caps stay too small for one printed mark to drain sibling pools.
  • Make burn math safe at pathological index values and low-decimal asset granularities. If the economically correct burn is ~1.99999999 minimum hToken units, the protocol still needs to consume enough supplier state that the withdrawal cannot mint value.
  • Add explicit denominator-health and impossible-growth checks: one meaningful supplier, microscopic hToken supply, or liquidityIndex growth that only makes sense if one wallet owns the next unit of fee accrual should freeze or de-collateralize the reserve automatically.
  • Re-test empty-market behavior after launch, not only at launch. A reserve that later drifts back into dust supply should lose the same privileges a fresh reserve lacks instead of inheriting trust forever.
  • Put blast-radius controls under the market anyway: isolated mode, per-reserve debt caps, correlated-borrow suppression, and fast pauses should stop one WBTC reserve from turning fee-index fiction into protocol-wide WETH and stablecoin bad debt.
  • Treat mempool visibility as part of the risk model for atomic drain paths. If one profitable transaction can be copied and bribed into the block by a generalized frontrunner, emergency responses must assume the first visible exploit may not be the only one.

Audit prompts

  • What exact reserve state proves hETHWBTC is still mature today rather than merely old, and what onchain condition forces it back into quarantine if suppliers later redeem toward dust?
  • Can the same reserve both generate attacker-controlled flash-loan premiums and immediately socialize them over a denominator that one actor effectively owns?
  • Which paths keep flash loans, collateral factor, liquidation thresholds, and sibling-market borrow caps live even when the reserve has only one meaningful supplier?
  • At extreme liquidityIndex values and WBTC-sized minimum units, how many hToken units should a withdrawal burn economically, and where does floor rounding let the protocol destroy less supplier state than the withdrawal consumes?
  • If a reserve has been dormant for months, what prevents old listing from silently standing in for economically mature collateral object during governance review, monitoring, and automated controls?
  • What automated production signal would have caught HopeLend before cross-market drains began: one-address supplier concentration, impossible index growth, flash-loan fees accruing into a dust reserve, or a dust hToken balance suddenly gaining tens of WBTC of collateral value?
  • Can the reserve stay locally observable while downstream trust stays off, or does every listed reserve automatically inherit collateral authority whether or not its denominator is still healthy?
  • If the exploit path becomes visible in the mempool, what pause, cap, or deny path can still stop copied transactions from draining the same reserve before the next block is sealed?

Lessons that should already be standard

  • Old reserves can become fresh-market bugs again. Historical listing age is not a substitute for current supplier breadth.
  • Flash-loan premiums are not neutral income in a dust reserve. When one actor both generates and captures them, the protocol is letting that actor print collateral.
  • Low-decimal assets turn tiny precision issue into treasury policy. Once one 1e-8 hToken unit can represent meaningful WBTC, floor rounding is part of solvency design.
  • Downstream borrowing is where empty-market accounting lies become real losses. A dormant side reserve should not get immediate line-of-sight to deep sibling liquidity without another distrust boundary.
  • Lifecycle controls have to survive runtime drift, not just launch day. A market that becomes attacker-ownable months later still needs launch-grade skepticism.
  • Mempool competition does not reduce exploit severity; it often increases it. Atomic solvency bugs should be modeled as publicly copyable once one exploiter demonstrates the path.

Why this incident matters

  • HopeLend broadens the empty-market corpus with a non-launch-window Aave-style example: not a brand-new reserve like Radiant, but a stale and unused one that had become effectively fresh again while still remaining economically live.
  • It preserves the exact mechanics of fee-concentrated liquidityIndex inflation in an empty reserve, which is the Aave-family analog of direct donation inflation in Compound-style forks.
  • It also sharpens the lifecycle lesson preserved by the empty-market cluster: market still exists and market still deserves cross-market solvency authority are different claims.
  • It is also a clean reminder that solver and MEV dynamics are part of exploit reality: once an exploit is publicly visible in the mempool, whoever controls ordering may become the actual thief.

Internal linkages

Control surface