Hundred Finance hWBTC Empty-Market Exchange-Rate Exploit (2023-04-15)
- Name: Hundred Finance hWBTC empty-market exchange-rate exploit
- Date: 2023-04-15
- Protocol: Hundred Finance
- Chain: Optimism
- Category: empty-market exchange-rate inflation / precision-loss redemption / cross-market lending drain
- Loss: about $7.4 million
- Summary: The attacker targeted Hundred Finance’s unused Optimism
hWBTCmarket, whose age did not stop it from becoming effectively fresh again once supply had collapsed to dust. They drove receipt-token supply down to almost zero, then donated roughly 500 WBTC directly into thehWBTCcontract so the exchange rate seen by collateral checks became enormous. In Compound-v2 math that inflation flowed throughgetCash()intoexchangeRateStored, and therefore intogetAccountSnapshot()/ borrow power, even though no newhWBTChad been minted. With that distorted collateral, the attacker borrowed from deeper-liquidity sibling markets. A truncation bug in theredeemUnderlyingpath then let the attacker pull the donated WBTC back out while burning only 1 wei ofhWBTCinstead of the nearly 2 wei economic reality required. The attacker finally liquidated the residual position to reset the market and repeated the pattern across other pools. - Trigger / entry point:
- The key target was Optimism
hWBTCat0x35594E4992DFefcB0C20EC487d7af22a30bDec60, an effectively empty market that could be driven to a tinytotalSupply. - Hundred’s exchange-rate math trusted the market’s raw WBTC balance, so direct transfers into
hWBTCincreasedgetCash()and therefore the quoted exchange rate without minting newhWBTC. - The
redeemUnderlyingmath rounded down when converting underlying amount to receipt tokens to burn, which became exploitable when the market had only a few wei ofhWBTCoutstanding.
- The key target was Optimism
- Root cause:
- Hundred left an effectively unused duplicate Optimism WBTC market live as borrow-relevant collateral even after it had drifted back into launch-dangerous dust supply, giving the attacker an isolated empty-state scaffold rather than a mature market with durable outside supply.
- Its receipt-token exchange rate could be inflated by direct underlying transfers because raw balance changes flowed straight into solvency-critical accounting:
getCash()fedexchangeRateStored, andexchangeRateStoredfedgetAccountSnapshot()for collateral value. redeemUnderlyingultimately converted underlying amount back intohWBTCshares with floor-roundedExpmath (div_/truncate()style behavior), so a required burn just under 2 wei became a burn of only 1 wei.- In short: the protocol let a nearly zero-supply market define borrow power for the rest of the system, then compounded that design flaw with rounding behavior that favored the attacker.
- Exploit path:
- The attacker, publicly tracked at
0x155da45d374a286d383839b1ef27567a15e67528, opened with a 500 WBTC Aave v3 flash loan in transaction0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451. - They redeemed prior
hWBTCso the market’stotalSupplyreturned to zero, then used a fresh helper contract to mint 200hWBTCwith 4 WBTC. - They redeemed almost the entire position, leaving just 2 wei of
hWBTCoutstanding. - They transferred roughly
500.30063816WBTC directly intohWBTC, which did not mint any new shares but made each remaining wei ofhWBTCrepresent an absurd amount of WBTC on paper. - Using that distorted collateral value, the attacker entered the market through the Unitroller
0x5a5755E1916F547D04eF43176d4cbe0de4503d5dand borrowed from sibling pools, beginning with about 1021 ETH fromhETH/crETHat0x1A61A72F5Cf5e857f15ee502210b81f8B3a66263. - The decisive cash-out came when the attacker called
redeemUnderlyingfor roughly500.30063815WBTC. Economic reality required burning almost 2 wei ofhWBTC, but truncation rounded the burn down to 1 wei. - That left one residual wei of
hWBTC, which the attacker then used in liquidation / reset steps so the market could be emptied again and the same pattern repeated against additional pools such as SNX, USDC, DAI, USDT, sUSD, and FRAX. - A second major drain transaction,
0x15096dc6a59cff26e0bd22eaf7e3a60125dcec687580383488b7b5dd2aceea93, continued the extraction before the flash loan was repaid.
- The attacker, publicly tracked at
- What the attacker needed to be true:
hWBTChad to be empty or controllably near-empty so tiny receipt-token balances could dominate the exchange-rate math.- Direct WBTC transfers into the market had to affect the exchange rate immediately through raw
getCash()accounting. - Hundred had to accept inflated
hWBTCcollateral quickly enough to allow borrowing from deeper-liquidity sibling markets. - Redemption math had to truncate in the attacker’s favor once the market reached the extreme
2 weisupply state. - The sibling markets needed enough real liquidity to turn fake
hWBTCsolvency into withdrawable assets.
- Technical anatomy worth remembering:
- The donation step alone was not the whole exploit. The real money came from pairing exchange-rate inflation with precision-loss redemption and then using the manipulated market as collateral elsewhere.
- This was not a conventional oracle attack. The protocol’s own internal exchange-rate formula became the printable price:
getCash()increased after the donation,exchangeRateStoredjumped, andgetAccountSnapshot()treated the attacker’s dusthWBTCbalance as massive collateral. - The decisive arithmetic edge sat in
redeemUnderlying: after the donation, redeeming about500.30063815WBTC implied burning roughly1.99999992wei ofhWBTC, but floor truncation rounded that down to1. - Empty-market state was decisive. At normal supply levels, the same truncation would have been nuisance-level noise rather than a multi-million-dollar drain.
- The exploit also shows why duplicate, unused, or operationally forgotten markets are dangerous in lending forks: they can become attack scaffolding for stealing from active pools.
- Representative transactions and artifacts:
- Attacker EOA:
0x155da45d374a286d383839b1ef27567a15e67528 - First main exploit tx:
0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451 - Second main exploit tx:
0x15096dc6a59cff26e0bd22eaf7e3a60125dcec687580383488b7b5dd2aceea93 hWBTC:0x35594E4992DFefcB0C20EC487d7af22a30bDec60hETH/crETH:0x1A61A72F5Cf5e857f15ee502210b81f8B3a66263- Unitroller:
0x5a5755E1916F547D04eF43176d4cbe0de4503d5d - Aave v3 flash-loan pool used in public reproductions:
0x794a61358D6845594F94dc1DB02A252b5b4814aD
- Attacker EOA:
- Response / mitigation:
- Hundred publicly warned that the issue was a general Compound-v2-fork weakness rather than a one-off deployment error.
- The incident quickly became the reference case for auditing empty markets, seed liquidity, and precision behavior across Compound-style forks.
- Later fork incidents in 2023 and 2024 showed that many teams still had not hardened empty-market handling or tiny-supply redemption math.
Three solvency-authority promotions this incident collapsed
-
An abandoned-looking market was still allowed to become attacker-owned denominator state
- The dangerous fact was not merely that
hWBTCexisted. It was that an old side market could drift back into an effectively fresh state, return to microscopic supply, and still remain a live collateral surface. - Once the attacker reduced
totalSupplyto2 wei, they effectively controlled the denominator that would decide what the next unit of WBTC meant for supplier-side value.
- The dangerous fact was not merely that
-
That attacker-shaped denominator was still promoted into canonical collateral truth
- Direct WBTC donation into
hWBTCraised rawgetCash(). - Hundred then treated that raw-balance increase as ordinary exchange-rate truth through
exchangeRateStored, and exported the result throughgetAccountSnapshot()as if the printedhWBTCmark were economically backed collateral rather than attacker-authored thin-market state.
- Direct WBTC donation into
-
That published collateral truth still deserved immediate reserve-spending authority elsewhere
- Liquid sibling markets accepted the distorted
hWBTCmark quickly enough for the attacker to borrow real assets against it. - The later
redeemUnderlyingunder-burn and liquidation/reset loop mattered because the protocol had already crossed the decisive line: an attacker-authored dust-market mark still retained live cross-market borrowing and reserve-extraction authority.
- Liquid sibling markets accepted the distorted
The durable lesson is that the market is almost empty again, the next balance change defines supplier truth, and that printed truth can still spend sibling liquidity are three separate security promotions. Hundred failed all three.
Pattern tags
- empty-market-exchange-rate-inflation
- fresh-market-initialization-failure
- The preserved shape is sharper than generic
donation attackor genericrounding bug: Hundred let an effectively fresh-again side market collapse to2 weiofhWBTCsupply, let direct raw-balance donation redefine the market’s printed exchange rate over that microscopic denominator, and then let the same printed mark become immediate borrow power against deeper sibling markets. - This was also a clean
old market != mature marketfailure. The dangerous state was notbrand-new deployment; it wasdust-supply reserve whose next unit of donated balance still decides what collateral means.
Why the exploit worked
- Hundred allowed an abandoned-looking side market to keep full cross-market collateral authority after it had already drifted back into an effectively fresh state. Once supply was reduced to
2 wei, the protocol no longer had a real outside depositor base; it had one attacker-owned denominator defining what the next unit of WBTC would mean. - In that state, direct donation stopped being passive balance noise and became solvency authorship.
getCash()read the raw WBTC balance,exchangeRateStoredtransformed that into supplier-side value, andgetAccountSnapshot()then exported the printed result as ordinary collateral truth to the rest of the protocol. - The rounding bug completed the cash-out path rather than standing alone. Without the under-burn in
redeemUnderlying, the attacker could have printed absurd paper collateral but would have had a harder time recovering the donated WBTC; without the empty-market donation path, the truncation would have stayed economically small. The exploit only paid because the protocol joined tiny-supply state, raw-balance-sensitive pricing, and attacker-favorable burn math into one pipeline. - Downstream borrowing had no second distrust boundary. There was no rule saying an effectively fresh, dust-supply, or impossible-growth market could stay locally observable while still being unable to define borrow power for liquid sibling pools.
- The preserved lesson is therefore broader than
watch for donation attacks: market lifecycle, balance-accounting semantics, redemption arithmetic, and cross-market collateral admission all belonged to one security object, and Hundred split them apart.
Detection and audit pivots
- Ask the lifecycle question directly: what onchain fact proves a market has durable supplier breadth, and what demotes it back into quarantine if supply later collapses toward dust? If the answer is only
this market is old, the control does not exist. - Reconstruct the whole exchange-rate publication path, not only the redemption bug:
underlying balance -> getCash() -> exchangeRateStored -> getAccountSnapshot() -> collateral checksshould tell one coherent story about economically backed value before the market can matter system-wide. - Force direct donations into low-supply and duplicate markets during testing. If unsolicited balance increases can change borrowable exchange rate faster than the protocol can mint proportional shares, quarantine the market or separate donation handling from solvency math.
- Simulate
redeemUnderlying, liquidation, and seize flows at pathological denominators like1 wei,2 wei, and other dust-supply states. If the only thing keeping the bug small isnobody should ever get here, the exploit surface still exists. - Check for downstream distrust boundaries. Can a dust-supply market remain listed while collateral factor stays
0, borrow caps stay negligible, or emergency demotion paths automatically remove its ability to define cross-market solvency before one fake mark drains liquid sibling pools?
Failure-prevention checklist
- Reclassify dormant markets as effectively fresh when supplier breadth collapses. If
totalSupplyor meaningful outside supply falls back toward attacker-ownable dust, automatically demote collateral factor, borrow caps, or market status before the next donation can become systemwide solvency truth. - Seed non-burnable minimum liquidity that cannot be redeemed away later. The protocol should never be able to return to a
2 weidenominator where one actor owns the meaning of the next donated unit of WBTC. - Keep raw-balance changes from directly redefining collateral truth. Donations, rescue transfers, and other off-path balance increases should either mint proportional claims, route to a quarantined bucket, or stay excluded from exchange-rate inputs until reviewed.
- Treat
redeemUnderlyingburn math as treasury logic at pathological denominators. If redeeming attacker-sized underlying in a dust-supply market can round~1.99999992 weiof required burn down to1 wei, the market is not safe to leave borrow-relevant. - Separate local accounting observability from cross-market solvency authority. A market that is new, duplicate, dormant, or impossible-growth should be allowed to exist only behind collateral-factor
0, tiny borrow caps, or another borrow-side quarantine until the denominator is no longer attacker-owned. - Fuzz the full empty-market exploit pipeline, not isolated steps: supply collapse, direct donation, exchange-rate publication, sibling-market borrowing, redeem-under-burn, and liquidation/reset loops should all be tested as one joined cash-out path.
- Inventory duplicate and forgotten markets as security liabilities. A side market that nobody uses is not harmless clutter if it can still publish collateral marks into active sibling pools.
Audit prompts
- What exact onchain condition proves this market is mature enough to define borrow power, and what exact condition demotes it back into effectively-fresh quarantine if supply later collapses?
- Can direct underlying transfers into the receipt-token contract still flow straight into
getCash(),exchangeRateStored, account snapshots, or other borrow-relevant marks without minting proportional new supplier claims? - At
1 wei,2 wei, or similarly tiny supply states, how many receipt-token units shouldredeemUnderlyingburn economically, and where does floor division let the protocol burn less than that? - If the market is duplicate, long-unused, or operationally forgotten, why is it still allowed to define collateral truth for liquid sibling pools instead of staying locally visible but cross-market quarantined?
- Which controls would stop the attack after the donation but before sibling-market borrowing: supply-floor guards, collateral-factor demotion, per-market borrow caps, impossible-growth alerts, or automatic pause on exchange-rate jumps?
- Can liquidation or reset steps recycle the last residual receipt-token wei so the same market can be used repeatedly inside one exploit sequence?
- What invariant proves that every meaningful increase in supplier-side collateral value came from matched accounting paths rather than an attacker-chosen denominator plus unsolicited balance growth?
Lessons that should already be standard
- An old market can become a fresh-market bug again. Age is not a security property when supplier breadth has already collapsed back into dust.
- Direct donation is already collateral authorship if raw balance feeds exchange rate. Calling it
just a transferis how protocols let attackers publish borrow truth without minting proportional claims. - Tiny-supply rounding is not a cosmetic precision issue. Once one or two receipt-token wei represent real money, floor division becomes treasury policy.
- Cross-market lending turns local accounting lies into protocol-wide bad debt. A dust-supply side market should never get to define borrow power for the rest of the book without extra distrust boundaries.
- Duplicate or forgotten listings are latent launch surfaces. If a market can be the first meaningful-supplier market again, it needs launch-grade hardening again.
- The exploit family is one joined object: denominator control, exchange-rate publication, under-burn, and sibling-market liquidity access either fail together or defend together.
Why this incident matters
- Hundred is the canonical demonstration that an almost-empty receipt-token market can become a protocol-wide solvency weapon, even when the market is old enough to look operationally harmless.
- It ties together three lessons that often get reviewed separately: effective-freshness quarantine for dormant markets, raw-balance donation risk, and tiny-supply integer truncation.
- It also helped surface a broader fork ecosystem problem: security assumptions that were tolerable in mature, liquid core Compound markets became dangerous when copied into thinly used side markets and then left borrow-relevant after drifting back into dust-supply conditions.
Internal linkages
- Core recurring pattern: empty-market-exchange-rate-inflation.
- Launch / lifecycle subpattern: fresh-market-initialization-failure.
- Positive-design companions: effective-freshness-reclassification-and-dormant-market-quarantine and fresh-market-seeding-and-activation-discipline — the sharper lifecycle follow-up is why an operationally forgotten side market with dust supply was still allowed to define cross-market solvency instead of being treated like a fresh or effectively fresh market again.
- Positive-design companion: bootstrap-state-irreversibility-and-supply-floor-design — the sharper denominator question is why the market’s opening-state floor was still reversible all the way back into attacker-ownable dust instead of becoming a durable security boundary.
- Adjacent pattern: donation-share-price-manipulation.
Control surface
-
The decisive leverage sat in
hWBTCmarket initialization, direct-balance-sensitive exchange-rate math,redeemUnderlyingrounding, and cross-market collateral policy that let one empty market dictate borrow power elsewhere. -
Hundred did not merely have a rounding bug. It had a full exploit pipeline: empty-market state, printable exchange rate, permissive collateralization, and attacker-favorable truncation.
-
Sources:
- https://rekt.news/hundred-rekt2
- https://blocksec.com/blog/6-hundred-finance-incident-catalyzing-the-wave-of-precision-related-exploits-in-vulnerable-forked-protocols
- https://www.comp.xyz/t/hundred-finance-exploit-and-compound-v2/4266
- https://www.numencyber.com/hundred-finance-exploit-7-million/
- https://raw.githubusercontent.com/SunWeb3Sec/DeFiHackLabs/main/src/test/2023-04/HundredFinance_2_exp.sol
- https://optimistic.etherscan.io/tx/0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451
- https://optimistic.etherscan.io/tx/0x15096dc6a59cff26e0bd22eaf7e3a60125dcec687580383488b7b5dd2aceea93
-
Last reviewed: 2026-08-01 UTC