TL;DR
On March 2, 2026, a flash loan attacker manipulated the sDOLA price oracle on Curve's LlamaLend platform, triggering cascading liquidations that drained ~$240K from borrowers. The root cause wasn't a traditional smart contract bug — it was an economic design flaw in how the oracle tracked vault share pricing. This article dissects the attack and extracts concrete oracle design patterns every DeFi lending protocol should implement.
The Attack: What Happened
The sDOLA market on LlamaLend allowed users to deposit sDOLA (a yield-bearing wrapper around DOLA) as collateral to borrow crvUSD. The attacker exploited the gap between the oracle's price feed and the actual economic state of the system.
Attack Flow
1. Flash loan → Acquire large DOLA position
2. Donate DOLA to sDOLA vault → Inflate sDOLA/DOLA exchange rate
(1.189 DOLA → 1.353 DOLA per sDOLA, ~14% spike)
3. Oracle reads inflated rate → Borrower health factors drop below 0
4. Trigger liquidations on underwater positions
5. Collect liquidation rewards → Repay flash loan → Profit
The attacker walked away with ~6.74 WETH + 227,325 DOLA (~$240K total).
Why It Worked
The oracle tracked the sDOLA exchange rate, which is derived from the vault's total assets divided by total shares. By donating assets directly to the vault, the attacker could atomically inflate this ratio within a single transaction — and the oracle had no safeguard against this.
Critically, Curve Lend's soft-liquidation AMM mechanism couldn't handle atomic oracle price changes. The instant the oracle reported a higher sDOLA price, the soft-liquidation bands shifted, creating immediate impermanent loss for borrowers even though their collateral's \"value\" appeared to increase.
The Deeper Problem: Vault Share Oracles
This isn't the first time vault share pricing has caused problems. The pattern is recurring:
| Incident | Year | Loss | Root Cause |
|---|---|---|---|
| Euler Finance | 2023 | $197M | Donation attack on eToken pricing |
| ERC-4626 First Depositor | 2022-2024 | Various | Share inflation via donation |
| sDOLA LlamaLend | 2026 | $240K | Vault share oracle manipulation |
The fundamental issue: vault share prices are derived values, not market prices. They can be manipulated by anyone who can change the vault's asset-to-share ratio — and donations are the simplest vector.
Oracle Design Patterns That Prevent This
Here are five concrete patterns, ordered from simplest to most robust:
Pattern 1: TWAP on Share Prices
Instead of reading the instantaneous vault share price, compute a time-weighted average:
// Pseudo-code: TWAP oracle for vault shares
function getSharePrice() external view returns (uint256) {
uint256 currentPrice = vault.convertToAssets(1e18);
uint256 timeElapsed = block.timestamp - lastUpdate;
// Exponential moving average with decay
uint256 smoothedPrice = (currentPrice * timeElapsed +
lastPrice * SMOOTHING_PERIOD) /
(timeElapsed + SMOOTHING_PERIOD);
return smoothedPrice;
}
Trade-off: Introduces latency. Legitimate price changes take time to reflect, which could cause issues during rapid market moves.
Pattern 2: Rate-of-Change Circuit Breakers
Reject oracle updates that exceed a maximum rate of change per block:
function validatePriceUpdate(uint256 newPrice) internal view returns (bool) {
uint256 maxChange = lastPrice * MAX_CHANGE_BPS / 10000;
if (newPrice > lastPrice + maxChange ||
newPrice < lastPrice - maxChange) {
return false; // Reject anomalous price
}
return true;
}
For yield-bearing vaults like sDOLA, the maximum legitimate rate of change is bounded by the yield rate. A 14% jump in a single block is physically impossible through normal yield accrual.
Recommended threshold: max(dailyYieldRate * 2, 50 bps) per block.
Pattern 3: Donation-Resistant Pricing
Track the vault's \"expected\" exchange rate based on yield accrual, independent of actual balances:
function donationResistantPrice() external view returns (uint256) {
// Use internal accounting, not balanceOf
uint256 expectedAssets = lastKnownAssets +
accruedYield(block.timestamp - lastAccrual);
return expectedAssets * 1e18 / totalShares;
}
This is what Aave V3 does with its getScaledUserBalanceAndSupply — the index grows deterministically based on interest rates, not external token transfers.
Pattern 4: Multi-Source Oracle Aggregation
Don't rely on a single price source. Cross-reference vault share prices with:
- DEX TWAP (e.g., sDOLA/DOLA Curve pool)
- Chainlink feed (if available)
- Internal accounting rate
function getVerifiedPrice() external view returns (uint256) {
uint256 vaultPrice = vault.convertToAssets(1e18);
uint256 dexTwap = curveTwapOracle.getPrice(SDOLA, DOLA);
uint256 internalRate = internalAccounting.getRate();
// Median of three sources
return median(vaultPrice, dexTwap, internalRate);
}
Pattern 5: Liquidation Delay Buffers
Even with good oracles, add a time buffer before executing liquidations on collateral types known to be manipulable:
function canLiquidate(address user) external view returns (bool) {
if (healthFactor(user) >= 1e18) return false;
// Require health factor to be below threshold for N blocks
if (block.number - firstUnhealthyBlock[user] < LIQUIDATION_DELAY) {
return false;
}
return true;
}
Flash loan attacks are atomic — they must complete within one transaction. A multi-block delay makes them economically infeasible.
Auditor's Checklist: Vault Collateral Oracle Review
When auditing a lending protocol that accepts vault shares (ERC-4626, LP tokens, yield-bearing tokens) as collateral:
- [ ] Can the share price be manipulated atomically? (donation, sandwiching)
- [ ] Is there a TWAP or smoothing mechanism on the oracle?
- [ ] What's the maximum legitimate rate of change? (bound by yield/fee rate)
- [ ] Does the liquidation mechanism handle instant price spikes?
- [ ] Are flash loan protections in place? (same-block borrow+liquidate prevention)
- [ ] Is there multi-source price verification?
- [ ] Has the oracle been tested against donation attack simulations?
What Curve Should Fix
- Implement rate-of-change bounds on sDOLA oracle — a 14% single-block move should be rejected outright
- Add a liquidation grace period for soft-liquidation AMM positions — even 2-3 blocks would defeat flash loan attacks
-
Use internal accounting rate for vault share pricing rather than
convertToAssets()which reflects donations - Cross-reference vault price with sDOLA/DOLA DEX TWAP as a sanity check
Conclusion
The sDOLA LlamaLend exploit is a textbook example of why oracle security in DeFi lending goes far beyond \"use Chainlink.\" When your collateral is a derived value (vault shares, LP tokens, rebasing tokens), the oracle must account for manipulation vectors that don't exist with simple spot assets.
The five patterns above aren't theoretical — they're battle-tested across protocols that have survived similar attacks. If you're building or auditing a lending protocol in 2026, vault collateral oracle security should be at the top of your review list.
This analysis is part of my ongoing DeFi security research. Follow @ohmygod for weekly deep-dives into smart contract vulnerabilities and audit techniques.
References:
Top comments (0)