C.R.E.A.M. Finance yUSD pricePerShare Donation / Wrappable-Token Collateral Drain (2021-10-27)

  • Name: C.R.E.A.M. Finance yUSD pricePerShare donation / wrappable-token collateral drain
  • Date: 2021-10-27
  • Protocol: C.R.E.A.M. Finance
  • Chain: Ethereum
  • Category: donation / share-price manipulation / oracle manipulation / wrappable-token collateral-pricing failure
  • Loss: about $130 million
  • Summary: The attacker used a 500M DAI flash-mint style loan plus a 524,102.159 WETH Aave flash loan to build an enormous crYUSD collateral position inside C.R.E.A.M. v1, then manipulated Yearn yUSD’s pricePerShare() by directly transferring about 8.43M yCrv into the yUSD vault contract at 0x4b5bfd52124784745c1071dcb244c6688d2533d3 without minting new yUSD shares. Because yUSD’s share-value math counted raw vault assets over outstanding yUSD supply, and because the attacker had already redeemed almost all yUSD so supply sat near the same ~8M level, that direct yCrv donation roughly doubled pricePerShare() from about 1 to about 2. C.R.E.A.M. treated the boosted yUSD wrapper price as collateral truth for the attacker’s huge crYUSD position, letting them borrow 523,208 ETH plus most remaining assets across Ethereum v1 markets.
  • Trigger / entry point:
    • The vulnerable market was C.R.E.A.M. Ethereum v1’s crYUSD collateral listing, which accepted Yearn’s yUSD vault token as collateral and trusted its wrapper exchange rate.
    • Yearn yUSD’s pricePerShare() depended on _shareValue(), which in turn depended on _freeFunds() and _totalAssets(); _totalAssets() included the vault’s raw yCrv token balance plus strategy debt.
    • Direct yCrv transfers to the yUSD vault increased _totalAssets() immediately even if no new yUSD shares were minted.
    • C.R.E.A.M.’s post-mortem called this a wrappable token pricing issue: the protocol let a wrapper’s own exchange-rate math become a same-transaction collateral oracle.
  • Root cause:
    • C.R.E.A.M. priced yUSD collateral through a wrapper exchange rate the attacker could print by donating underlying yCrv directly into the vault contract.
    • The attack became practical because the attacker first collapsed yUSD supply to a small residual amount before making the donation, so each donated yCrv unit had outsized effect on pricePerShare().
    • C.R.E.A.M. then treated the manipulated wrapper mark as if it were fair collateral value and extended credit against it across unrelated markets.
    • In short: raw-balance donation changed Yearn’s assets-per-share ratio, and C.R.E.A.M. honored that ratio as borrowable solvency.
  • Exploit path:
    1. The main setup and first drain occurred in exploit transaction 0x0fe2542079644e107cbf13690eb9c2c65963ccb79089ff96bfaf8dced2331c92 using attacker contracts 0x961d2b694d9097f35cfffa363ef98823928a330d and 0xf701426b8126bc60530574cecdcb365d47973284, funded from wallet 0x24354d31bc9d90f62fe5f2454709c32049cf866b.
    2. Contract 0x961d...330d flash minted or flash borrowed 500,000,000 DAI, converted it through Curve’s Y-pool into about 451,065,927.89 yDAI, added liquidity, and deposited the resulting yCrv into Yearn’s yUSD vault to mint about 446,756,774.41 yUSD.
    3. The attacker supplied that yUSD into C.R.E.A.M. and minted about 22,337,774,341.38 crYUSD, creating the first giant wrapper-collateral position.
    4. A second contract 0xf701...3284 flash borrowed 524,102.159 WETH from Aave, retained about 6,000 WETH liquidity for the attack flow, and deposited about 518,102.15 ETH into C.R.E.A.M. to mint crETH.
    5. Using the ETH-backed position, that second contract borrowed about 446,758,198.60 yUSD from C.R.E.A.M., re-supplied the borrowed yUSD back into crYUSD, minted another huge crYUSD balance, and transferred the resulting crYUSD to the first attacker contract. This recursive step concentrated roughly $1.5B of apparent crYUSD collateral under the first contract while leaving the borrowed yUSD available to unwind the wrapper supply.
    6. The first attacker contract then redeemed about 449,780,371 yUSD back into yCrv, leaving yUSD total supply and vault-held yCrv both near ~8M units. At this point pricePerShare() was still near 1 because remaining assets and remaining supply were roughly matched.
    7. The attacker then transferred about 8,431,514.82 yCrv directly into the yUSD vault contract without minting any new yUSD shares. That donation doubled the numerator in Yearn’s assets-per-share math while supply stayed near 8M, pushing yUSD pricePerShare() to roughly 2.
    8. C.R.E.A.M. immediately marked the attacker’s giant crYUSD position at the inflated wrapper value. With that fake collateral, the first contract borrowed about 523,208 ETH from C.R.E.A.M. to repay the second contract’s WETH flash loan and free the ETH-backed helper leg.
    9. The attacker then used the remaining inflated crYUSD collateral to borrow through the rest of the Ethereum v1 markets, draining assets across a series of follow-on transactions including 0x5189ac29b4d7ed7c1e78423f679f376ac0a2b32158349db84b01677f0608aac8, 0xa43053e945df7a0e407b083a3a1068f11d7e799bbe7dc99e8d8205f5cac2cd68, 0x0e560a840eaa749a9b55f1cae4b48d3e03c6f2060d65fbf66414008c29e77c27, 0x426c4ee29c3bc19ecb036cfedbca095c16847f8b688edaab7b1812577a3ab8a0, 0x59a98612d1fc3c8dc2b404258dfa46083a5635a2775659f8de3db18aec1b326c, and 0xb9583254ecd4efca21759e6ed5c8314ea918246d02f0f5fca580d7eb24b4e79c.
    10. After borrowing out the markets, the attacker unwound the setup by removing liquidity back into yDAI, withdrawing roughly 493.64M DAI, swapping residual USDC into DAI, and repaying the original 500M DAI flash-mint leg.
  • What the attacker needed to be true:
    • C.R.E.A.M. had to accept yUSD as collateral and price it from its live wrapper exchange rate rather than from a haircut, delayed mark, or independent solvency oracle.
    • Yearn yUSD had to count direct yCrv transfers in _totalAssets() without minting new yUSD shares.
    • The attacker had to be able to reduce live yUSD supply to a small residual amount before donating additional yCrv, making pricePerShare() highly donation-sensitive.
    • Cross-market liquidity in C.R.E.A.M. needed to be deep enough that the attacker could convert the printed yUSD collateral value into many other real assets.
    • Flash liquidity had to be large enough to build and unwind the giant initial yUSD / ETH collateral tower inside one attack sequence.
  • Technical anatomy worth remembering:
    • This was not just an oracle manipulation in the usual AMM-spot sense. The attacker printed a higher wrapper exchange rate by changing the wrapper’s own raw-balance accounting.
    • The decisive design mistake was letting a wrappable token act as collateral while its pricePerShare() could be moved by direct underlying donation.
    • The exploit combined two leverage sources: recursive collateral building inside C.R.E.A.M. and then donation-driven share-price inflation inside Yearn.
    • C.R.E.A.M.’s post-mortem explicitly noted that the vulnerable class extended beyond yUSD to other wrapper-style assets whose exchange-rate math could move independently of trustworthy market value.
    • The attack is a strong early example of a donation / share-price manipulation being monetized through a lending market rather than through direct redemption alone.
  • Representative transactions and addresses:
    • Attacker wallet: 0x24354d31bc9d90f62fe5f2454709c32049cf866b
    • Attacker contract #1: 0x961d2b694d9097f35cfffa363ef98823928a330d
    • Attacker contract #2: 0xf701426b8126bc60530574cecdcb365d47973284
    • Main exploit transaction: 0x0fe2542079644e107cbf13690eb9c2c65963ccb79089ff96bfaf8dced2331c92
    • Follow-on drain transactions: 0x5189ac29b4d7ed7c1e78423f679f376ac0a2b32158349db84b01677f0608aac8, 0xa43053e945df7a0e407b083a3a1068f11d7e799bbe7dc99e8d8205f5cac2cd68, 0x0e560a840eaa749a9b55f1cae4b48d3e03c6f2060d65fbf66414008c29e77c27, 0x426c4ee29c3bc19ecb036cfedbca095c16847f8b688edaab7b1812577a3ab8a0, 0x59a98612d1fc3c8dc2b404258dfa46083a5635a2775659f8de3db18aec1b326c, 0xb9583254ecd4efca21759e6ed5c8314ea918246d02f0f5fca580d7eb24b4e79c
    • Yearn yUSD vault: 0x4b5bfd52124784745c1071dcb244c6688d2533d3
  • Response / mitigation:
    • C.R.E.A.M. suspended Ethereum v1 market interactions after the exploit and locked crToken transfers.
    • The team also stopped supply and borrow support for wrappable tokens, explicitly naming the wrapper-pricing class as the key vulnerability.
    • Yearn was able to salvage the approximately 8.43M yCrv donation, which C.R.E.A.M.’s post-mortem described as about $9.42M, and arranged to return it to the protocol multisig.
    • The incident became one of the clearest warnings that wrapper exchange rates need explicit collateral haircuts or separate oracle treatment before a lending market should trust them.

Why this incident matters

  • C.R.E.A.M.’s yUSD loss is a canonical case where donation-based share-price inflation, wrapper pricing, and lending collateral reuse all fused into one exploit.
  • It shows that pricePerShare() is not merely descriptive vault math once another protocol treats it as collateral truth.
  • It also preserves a useful bridge between later ERC-4626 donation attacks and earlier Yearn-style wrapper incidents: the accounting surface changed, but the invariant failure was the same.
  • The healthier-side lesson is sharper than Yearn math got manipulated: a local wrapper ratio moved, C.R.E.A.M. promoted that ratio into canonical collateral truth, and that published truth still inherited immediate authority over ETH and the rest of Ethereum v1’s reserve inventory.

Three wrapper-and-collateral promotions this incident collapsed

  1. Yearn’s local wrapper accounting moved

    • After using recursive C.R.E.A.M. leverage to thin live yUSD supply back toward ~8M, the attacker transferred about 8.43M yCrv directly into the yUSD vault contract without minting new yUSD shares.
    • C.R.E.A.M.’s own post-mortem preserved the resulting shape cleanly: yCrv.balanceOf(yUSD) moved from roughly 8m to roughly 16m while yUSD.totalSupply() stayed near 8m, so pricePerShare() jumped from about 1 to about 2.
    • That only proved the wrapper’s local assets-per-share math had changed. It did not yet mean the new ratio deserved to become lending-solvency truth for C.R.E.A.M.
  2. C.R.E.A.M. promoted that wrapper-local mark into canonical collateral truth

    • Yearn’s pricePerShare() path counted the vault’s raw yCrv balance inside _totalAssets(), so the direct donation truthfully published a much higher wrapper rate even though no new depositor had earned it.
    • C.R.E.A.M. then treated that wrapper-derived mark as money-good collateral value for the attacker’s giant crYUSD position, effectively revaluing the position from roughly $1.5B of apparent backing toward roughly $3B.
    • The decisive false promotion was not merely Yearn counted balances this way, but C.R.E.A.M. accepted that freshly donation-shaped wrapper answer as canonical cross-market borrow truth.
  3. That published wrapper truth still inherited immediate reserve-spending authority

    • Once the inflated mark was live, the attacker borrowed about 523,208 ETH to close the helper leg and then drained most remaining Ethereum v1 market liquidity through follow-on borrows.
    • This is where the wrapper print became realized protocol loss. The doubled pricePerShare() did not stay a local accounting curiosity; it retained same-window authority to unlock blue-chip reserves across unrelated markets.
    • The preserved lesson is that wrapper state moved, that state was published as canonical collateral truth, and that published truth still got to spend the reserve are three separate promotions. C.R.E.A.M. collapsed them into one.

Pattern tags:

Why the exploit worked

  • Yearn’s yUSD vault counted raw yCrv held by the vault in _totalAssets(), so a direct yCrv transfer increased pricePerShare() without minting any new yUSD.
  • The attacker used the recursive C.R.E.A.M. setup to shrink effective live yUSD supply before donating, which made the vault exchange rate donation-sensitive even though the product was not at launch-day state.
  • C.R.E.A.M. treated that wrapper exchange rate as money-good collateral value and let it scale borrow power across unrelated markets.
  • The protocol had enough cross-market liquidity, and enough tolerance for recursive wrapper-collateral buildup, that the attacker could turn the printed mark into real ETH and other assets before intervention.

Detection and audit pivots

  • Ask whether a listed wrapper’s pricePerShare, convertToAssets, or equivalent rate can move from direct underlying transfers, strategy accounting drift, or other off-path balance changes.
  • Recreate the wrapper math after aggressive redemptions or supply-thinning events; many not-empty vaults become effectively bootstrap-sensitive once supply is pushed down far enough.
  • Check whether the lending market applies any haircut, cap, delay, or collateral quarantine before a wrapper-derived rate becomes borrow power.
  • Trace whether recursive supply / borrow loops let one actor dominate the receipt-token side of the market before paying the cost to manipulate the exchange rate.
  • Treat any wrapper collateral listing as an oracle integration review, not a vanilla token-listing review.

Failure-prevention checklist

  • Do not let a wrapper’s live pricePerShare or convertToAssets output become same-transaction collateral truth unless off-path balance changes are either impossible or explicitly quarantined and recognized through a hardened accounting path.
  • Treat direct donations, rescue transfers, strategy-side inventory changes, and other ambient balance growth as hostile until proven otherwise. If raw token balances can move wrapper value, collateral systems should assume attackers can author that move.
  • Model low-supply and supply-thinning states explicitly. A wrapper does not need to be literally empty to reacquire bootstrap-style sensitivity; aggressive redemptions or recursive loops can make the surviving share base small enough for donation economics to become dangerous again.
  • Bound wrapper integrations with borrow caps, isolation, delayed collateral enablement, and fast asset-local pause paths so one printed exchange-rate jump cannot immediately reach the protocol’s deepest blue-chip liquidity.
  • Review recursive collateral loops and helper-account structures as part of the oracle problem. If one actor can first dominate wrapper-share ownership and then print the rate, the wrapper listing already carries concentrated-manipulation risk.
  • Separate wrapper-local accounting truth from protocol-wide solvency authority. A vault may honestly say assets per share doubled; that does not mean a lending market should immediately let that print underwrite ETH, BTC, or stablecoin borrowing.
  • Rehearse the wrapper rate doubles in one transaction case against borrow, liquidation, and pause operations. If the protocol’s only answer is that should not happen, the listing is not hardened enough.

Audit prompts

  • Which exact Yearn or wrapper accounting function is the downstream market trusting here, and what raw balances or off-path transfers can change it without issuing new wrapper shares?
  • Can a borrower deliberately thin live wrapper supply before making a donation or other numerator-side top-up, so the system re-enters effectively bootstrap-sensitive exchange-rate math long after launch?
  • Does the lending market distinguish between wrapper accounting says this share is worth more and the protocol can safely lend deep reserve assets against that claim right now, or are those treated as the same fact?
  • What caps, haircuts, delays, or borrow-side quarantine rules stop a wrapper-local rate jump from turning into cross-market reserve extraction before operators react?
  • Could one actor dominate wrapper-share ownership through recursive loops, helper accounts, or cross-market leverage before paying the cost to manipulate the wrapper numerator?
  • If the wrapper mark doubled while the underlying strategy had not plausibly earned that gain, what concrete onchain control would block new borrows or force asset-local de-recognition?
  • Which other listed wrappers, LP receipts, or vault shares in the same protocol rely on similarly ambient balance-sensitive exchange-rate math, and are they inheriting the same unbounded trust assumption?
  • If the protocol insists on supporting the wrapper for product reasons, what independent sanity bound proves that one unit of wrapper collateral cannot outrun plausible underlying earnings by an attacker-sized multiple inside one transaction?

Lessons that should already be standard

  • Wrapper exchange-rate math is an oracle the moment another protocol honors it as borrowable value.
  • The vault counted the assets correctly is not a defense when the attacker was allowed to author which assets counted in the numerator.
  • Bootstrap risk is a lifecycle property, not just a launch-day property. A live wrapper can be driven back into low-supply, donation-sensitive conditions by redemptions and leverage choreography.
  • Wrapper collateral reviews fail when they stop at the wrapper contract. The real question is whether a downstream lender should trust that wrapper’s local accounting as protocol-wide solvency truth.
  • Deep-liquidity reserve pools should not be reachable through a printable wrapper mark. If shallow or locally authored wrapper state can unlock ETH, BTC, or stablecoin reserves, the payout surface is mis-sized.
  • Recursive loops and helper accounts are part of the same exploit family, not secondary theatrics. Concentrating share ownership is often what makes an otherwise honest donation rail economically fatal.
  • Wrappable token is not a niche product label; it is a warning that accounting semantics, not just spot-market price, now sit inside the lending protocol’s security boundary.

Internal linkages

Control surface