Hundred hWBTC Donation Exploit
Exploit Transactions
0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451Victim Addresses
0x5a5755e1916f547d04ef43176d4cbe0de4503d5dOptimism0x35594e4992dfefcb0c20ec487d7af22a30bdec60OptimismLoss Breakdown
Similar Incidents
Helio Plugin Donation Inflation
30%Euler DAI Reserve Donation
27%ParaSpace cAPE Donation Repricing
25%Paribus Redeem Reentrancy
24%Aave AMM LP Oracle Manipulation Through Delegated Recursive LP Looping
22%0VIX ovGHST Oracle Inflation
21%Root Cause Analysis
Hundred hWBTC Donation Exploit
1. Incident Overview TL;DR
On 2023-04-15, the adversary drained multiple Hundred Finance Optimism markets by abusing the empty-market hWBTC listing as collateral. The public setup phase ended at block 90761917, where the attacker-controlled orchestrator already held the full hWBTC supply (1,503,167,295 raw shares) and the hWBTC market still held 30,064,194 satoshis of WBTC cash. In seed transaction 0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451 at block 90761918, the attacker flash-borrowed WBTC, manufactured dust hWBTC collateral, donated WBTC directly into the market to inflate the exchange rate, then borrowed or liquidated across hSNX, hUSDC, hDAI, hUSDT, hSUSD, hETH, and hFRAX.
The root cause is a Compound-v2-style empty-market donation flaw. Hundred's CErc20 implementation floors the number of cTokens burned when redeeming a chosen amount of underlying, and its stored exchange-rate calculation trusts raw underlying.balanceOf(address(this)). In a near-empty market that combination lets an attacker keep dust shares outstanding, make those shares appear extremely valuable with a direct donation, and then use the fictitious collateral value inside Hundred's borrow-capacity and liquidation math.
The exploit predicate in root_cause.json is strictly monetary. The adversary contract 0x978d0ce23869ec666bfde9868a8514f3d2754982 was valued at $9,128.5265130930 before the seed tx and $6,714,751.589791875073173541387 after it, for a net gain of $6,705,623.063278782073173541387 after $7,590.87537080288991 of fees. The valuation note in the evidence attributes the before-state to the pre-seed hWBTC position and the after-state to the post-tx balances in SNX, USDC, DAI, USDT, sUSD, FRAX, ETH, and WBTC, all priced with Hundred's public oracle inputs at block 90761917.
2. Key Background
Hundred's Optimism money markets are Compound-v2-style cTokens governed by a Unitroller/Comptroller. The hWBTC market is the critical collateral market in this incident: the market proxy is 0x35594e4992dfefcb0c20ec487d7af22a30bdec60, its CErc20 implementation is 0x7100cbca885905f922a19006cf7fd5d0e1bbb26c, and the Comptroller implementation is 0x8279b109d3a8a61fcdb2532f08e14e763a064be1.
The important accounting rule is that exchangeRateStored() is derived from (cash + borrows - reserves) / totalSupply. In Compound-style markets, cash is whatever the underlying token contract reports as the cToken's current balance. That means a direct underlying transfer into the cToken contract raises cash even if no mint occurs. When totalSupply is tiny, each remaining raw share absorbs a disproportionate fraction of that donated value.
The attacker's public pre-state was built with four public transactions before the seed tx:
0xf479b1f397080ac01d042311ac5b060ceccef491867c1796d12ad16a8f12a47e: mint3,190,800raw hWBTC shares with63,816satoshis.0x771a16e02a8273fddf9d9d63ae64ff49330d44d31575af3dff0018b04da39fcc: mint1,499,976,495raw hWBTC shares with30,000,000satoshis.0xdeb82968c10dc0a42cfb0a8099dec22a63c5e09a731b4bf3ac137094e6d1c193: prepare the final exploit structure.0x7db7c6d1a9d8778c328ee926ff6662723d1577d9fdcb9a131ef531652b65b977: transfer the full1,503,167,295hWBTC-share balance into the orchestrator contract.
At that point the exploit was permissionless. Any unprivileged searcher able to observe the same public state could submit the same seed transaction against the same public liquidity and listed markets.
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK, not a pure MEV arbitrage, because it exploits a broken collateral-accounting invariant inside Hundred's inherited Compound logic. The invariant that should have held is: a chosen redeem amount must burn enough cToken supply that the remaining supply still represents the remaining cash fairly, and direct donations must not turn dust shares into valid high-value collateral.
The verified CErc20 source shows exactly why the invariant fails:
function getCashPrior() internal view returns (uint) {
EIP20Interface token = EIP20Interface(underlying);
return token.balanceOf(address(this));
}
function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {
(vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
...
(vars.mathErr, vars.redeemTokens) =
divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));
...
}
getCashPrior() makes raw donations count as protocol cash, while divScalarByExpTruncate rounds the burn down when the attacker redeems by underlying amount. The verified exchange-rate function confirms that the donation feeds directly into collateral valuation:
function exchangeRateStoredInternal() internal view returns (MathError, uint) {
uint _totalSupply = totalSupply;
...
uint totalCash = getCashPrior();
(mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);
(mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);
return (MathError.NO_ERROR, exchangeRate.mantissa);
}
Hundred's Comptroller then trusts that inflated exchange rate in both liquidity checks and liquidation math:
vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice);
vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);
...
uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored();
seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);
That chain of logic is the concrete breakpoint. Once hWBTC supply falls to dust and raw WBTC is donated into the market, the Comptroller interprets dust shares as enormous collateral, authorizes full-market borrows, and later lets the attacker seize the final dust share for a negligible repayment.
The vulnerable components identified in the validated root cause are:
- Hundred hWBTC / CErc20 implementation
0x7100cbca885905f922a19006cf7fd5d0e1bbb26cviaredeemFreshandexchangeRateStoredInternal - Hundred Comptroller implementation
0x8279b109d3a8a61fcdb2532f08e14e763a064be1viagetHypotheticalAccountLiquidityInternalandliquidateCalculateSeizeTokens - The hWBTC market proxy
0x35594e4992dfefcb0c20ec487d7af22a30bdec60, which remained listed as borrowable collateral despite effectively having no real liquidity
The security principles violated are equally concrete:
- Empty-market listings were treated as safe collateral without a supply floor or donation-resistant accounting.
- Share-burn rounding was biased toward the redeemer even when the result could leave non-zero dust supply.
- Collateral valuation trusted raw underlying balances that donations could inflate without minting new shares.
- Liquidation math let the same dust collateral authorize large borrows and then be seized back for a negligible repayment.
4. Detailed Root Cause Analysis
The exploit unfolds in three deterministic stages.
First, the orchestrator starts the seed transaction from the fully primed public state and redeems its preloaded 1,503,167,295 hWBTC shares for 30,063,816 satoshis of WBTC. That resets hWBTC supply to zero while leaving only 378 satoshis of residual market cash.
Second, each helper contract manufactures dust collateral. A representative helper mints hWBTC with 4 WBTC, receives 20,000,000,000 raw hWBTC shares, and then redeems almost all of them. The collector's helper timeline shows the critical dust state exactly:
{
"step": "hWBTC redeem by helper_1",
"logIndex": 16,
"details": {
"redeemAmount": "400000000",
"redeemTokens": "19999999998",
"redeemer": "helper_1"
},
"totalSupply": "2",
"cash": "378",
"helper_1_hWBTC_balance": "2"
}
After that large redeem, only two raw hWBTC shares remain. The helper then donates roughly 500.30063816 WBTC directly into hWBTC, which raises market cash to 50,030,064,194 satoshis while total supply stays at 2. No mint occurs during this step, so the stored exchange rate spikes artificially.
Third, the helper realizes the fake collateral value. In the hUSDC loop, the decoded receipt shows the exact borrow, dust redeem, and liquidation sequence:
[
{
"logIndex": 86,
"emitter_label": "hUSDC",
"event": "Borrow",
"borrowAmount": "1233516758776"
},
{
"logIndex": 91,
"emitter_label": "hWBTC",
"event": "Redeem",
"redeemAmount": "50030063816",
"redeemTokens": "1"
},
{
"logIndex": 100,
"emitter_label": "hUSDC",
"event": "LiquidateBorrow",
"repayAmount": "282",
"seizeTokens": "1",
"cTokenCollateral": "0x35594e4992dfefcb0c20ec487d7af22a30bdec60"
}
]
This is the decisive failure mode. The helper borrows the target market against the donated dust collateral, then uses redeemUnderlying(...) semantics to recover almost the full donated WBTC balance while burning only one raw share. That leaves the helper insolvent with one last dust share. The orchestrator repays a tiny amount in the borrowed market, seizes the final hWBTC share through liquidation, redeems that seized share, and forwards the recovered WBTC into the next helper loop. The same primitive repeats across hETH, hSNX, hUSDC, hDAI, hUSDT, hSUSD, and hFRAX.
The exploit conditions are also explicit from the evidence:
- The collateral market must be empty or near-empty so that truncation can leave dust supply.
- The underlying token must be freely transferable into the cToken contract.
- The manipulated market must remain listed with a non-zero oracle price and collateral factor.
- Borrow markets must still have lendable cash to drain.
These conditions held on Optimism block 90761917, so the seed transaction was a live ACT opportunity from that public state.
5. Adversary Flow Analysis
The adversary cluster identified in the evidence is:
- EOA
0x155da45d374a286d383839b1ef27567a15e67528: sent the setup transactions, deployed the orchestrator, and submitted the seed tx. - Orchestrator
0x978d0ce23869ec666bfde9868a8514f3d2754982: held the primed hWBTC balance, initiated the Aave flash loan, coordinated the helper loops, and retained stolen assets. - Representative helper
0xd340f2208edbbbeca4fe4893d76eaaa5711e702b: executed the first dust-collateral loop against hETH.
The validated victim-side addresses are:
- Hundred Comptroller
0x5a5755e1916f547d04ef43176d4cbe0de4503d5d - Hundred hWBTC
0x35594e4992dfefcb0c20ec487d7af22a30bdec60
The end-to-end adversary lifecycle is:
- Public hWBTC priming: mint and transfer the entire hWBTC supply into the orchestrator before the seed tx.
- Seed transaction launch: call the orchestrator in tx
0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451, which pulls an Aave WBTC flash loan. - Dust-collateral manufacture: each helper mints hWBTC with
4 WBTC, redeems almost all shares, and leaves two dust shares behind. - Donation and borrow: the helper donates WBTC directly into hWBTC, enters Hundred markets, and borrows the full cash balance of the target borrow market.
- Insolvency and liquidation: the helper redeems almost the full donation by burning only one dust share, becomes liquidatable, and the orchestrator repays a negligible amount to seize the last share.
- Loop continuation and profit realization: the orchestrator redeems the seized share, forwards WBTC into the next helper, and eventually repays the Aave flash loan plus premium while retaining the borrowed assets.
The stage evidence in root_cause.json is also consistent on timing and mechanics:
- Public hWBTC priming: txs
0xf479...47e,0x771a...fcc,0xdeb8...193, and0x7db7...977at blocks89017327,90301503,90741684, and90760766 - Dust collateral manufacture: the seed tx flash-loan path at block
90761918 - Donation, borrow, and liquidation loop: the same seed tx repeating the helper primitive across hETH, hSNX, hUSDC, hDAI, hUSDT, hSUSD, and hFRAX
The representative markets and helper outputs captured in the collector artifacts are consistent with the reported losses: hETH, hSNX, hUSDC, hDAI, hUSDT, hSUSD, and hFRAX were each drained down to dust or near-dust balances.
6. Impact & Losses
Hundred lost roughly $6.71 million in value, and the exploit left multiple helper borrowers with unrecoverable bad debt after their last hWBTC dust shares were seized. The raw on-chain loss amounts reported in the evidence are:
- SNX:
20000006040813679379832with18decimals - USDC:
1233516758494with6decimals - DAI:
842788494009886029179569with18decimals - USDT:
1113430652679with6decimals - sUSD:
865142911064170347497066with18decimals - ETH:
1021915074224867122534with18decimals - FRAX:
457286054364794404672674with18decimals - WBTC:
30063817with8decimals
Operationally, the attack drained the lendable cash of at least seven Hundred borrow markets, left the protocol with bad debt tied to insolvent helper borrowers, and transferred the extracted assets into the adversary cluster after flash-loan repayment.
7. References
- Seed exploit transaction:
0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451 - Pre-seed public state and tx metadata:
/workspace/session/artifacts/collector/seed/10/0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451/metadata.json - Verified Hundred hWBTC market:
0x35594e4992dfefcb0c20ec487d7af22a30bdec60 - Verified Hundred CErc20 implementation:
0x7100cbca885905f922a19006cf7fd5d0e1bbb26c - Verified Hundred Comptroller implementation:
0x8279b109d3a8a61fcdb2532f08e14e763a064be1 - Public setup sequence summary:
/workspace/session/artifacts/collector/iter_8/tx/10/0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451/pre_attack_sequence_summary.json - Helper loop matrix:
/workspace/session/artifacts/collector/iter_8/tx/10/0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451/helper_loop_matrix.json - Helper hWBTC state timelines:
/workspace/session/artifacts/collector/iter_8/tx/10/0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451/helper_hWBTC_state_timelines.json - Grouped receipt chronology:
/workspace/session/artifacts/collector/iter_2/tx/10/0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451/receipt_decoded_grouped.json