We do not have a reliable USD price for the recorded assets yet.
0x4dcf7407ae5c07f8681e1659f626e114a7667339Ethereum0x7fcb7dac61ee35b3d4a51117a7c58d53f0a8a670Ethereum0x1429a930ec3bcf5aa32ef298ccc5ab09836ef587EthereumInverse Finance lost the full on-hand DOLA balance of cDOLA when an attacker used a flash loan to distort the oracle for cYvCurve-3Crypto collateral and then borrowed against the inflated valuation. The decisive issue was not a privileged key or hidden dependency. The protocol trusted a spot-balance-based price for Yearn vault shares over Curve TriCrypto LP, so a single transaction could temporarily raise collateral value far above its realizable value and unlock an oversized DOLA borrow.
Inverse listed cYvCurve-3Crypto as collateral and used the Comptroller to decide whether a borrower had enough collateral to borrow DOLA from cDOLA. The collateral asset wrapped Yearn vault shares over Curve TriCrypto LP. That means the protocol relied on a pricing chain from TriCrypto pool balances to LP value, from LP value to Yearn vault share value, and then from Yearn share value to the Comptroller liquidity check.
The critical design choice was the oracle implementation for cYvCurve-3Crypto. Instead of using a manipulation-resistant valuation, it directly read the current WBTC, WETH, and USDT balances sitting inside Curve TriCrypto and translated them into a price with Chainlink spot feeds. Because those balances can be shifted sharply inside one transaction with flash-loaned capital, the reported collateral value was also manipulable inside one transaction.
Inverse then consumed that oracle output in its normal borrow-permission path. Once the manipulated collateral was minted and entered as collateral, the protocol treated it as genuine borrow power and allowed the attacker to take all DOLA cash held by cDOLA.
The vulnerability is an oracle-manipulation attack in a lending protocol. priced the collateral by summing the live WBTC, WETH, and USDT balances of Curve TriCrypto, dividing by LP supply, and multiplying by the Yearn vault . That construction makes the oracle sensitive to transient same-transaction balance distortions. The attacker used an Aave WBTC flash loan to skew TriCrypto balances, minted the affected Yearn-backed collateral, and entered it into Inverse. The Comptroller then used and the market collateral factor to compute account liquidity and approve the DOLA borrow. executed the borrow because the Comptroller check returned success, even though the collateral value was only temporarily inflated. The result was a complete drain of cash and a remaining underwater position that converted the manipulated borrow into protocol bad debt.
0x9959f8f10f59b3b88a5499066a21237e492f193e5ff2950bcc7e6c1f5e1fa60c0x3d2f86c1c289731f56bed95dce20434eff48e3bd4a50cdc007ef5d0a2177a9f7YVCrv3CryptoFeed.latestAnswer()pricePerShareoracle.getUnderlyingPrice(asset)cDOLAcDOLAThe oracle code itself is the first breakpoint. In the verified YVCrv3CryptoFeed source, the feed reads live TriCrypto balances and treats them as current collateral value:
uint256 crvPoolBtcVal = WBTC.balanceOf(address(CRV3CRYPTO)) * uint256(BTCFeed.latestAnswer()) * 1e2;
uint256 crvPoolWethVal = WETH.balanceOf(address(CRV3CRYPTO)) * uint256(ETHFeed.latestAnswer()) / 1e8;
uint256 crvPoolUsdtVal = USDT.balanceOf(address(CRV3CRYPTO)) * uint256(USDTFeed.latestAnswer()) * 1e4;
uint256 crvLPTokenPrice =
(crvPoolBtcVal + crvPoolWethVal + crvPoolUsdtVal) * 1e18 / crv3CryptoLPToken.totalSupply();
return (crvLPTokenPrice * vault.pricePerShare()) / 1e18;
Origin: verified YVCrv3CryptoFeed.latestAnswer() source for 0xe8b3bc58774857732c6c1147bfc9b9e5fb6f427c.
That formula violates the required invariant for lending collateral: borrow power must reflect a manipulation-resistant value, not an instantaneous pool composition that an attacker can reshape with flash-loaned capital.
The second breakpoint is the borrow authorization path. In the Comptroller implementation, borrowAllowed() first ensures the market has a price, then later relies on getHypotheticalAccountLiquidityInternal() for the borrower liquidity check. Inside that liquidity routine, Inverse multiplies the collateral factor, exchange rate, and oracle price into tokensToDenom, then uses that value to accumulate collateral:
if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) {
return uint256(Error.PRICE_ERROR);
}
vars.collateralFactor = Exp({
mantissa: markets[address(asset)].collateralFactorMantissa
});
vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});
vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);
vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});
vars.tokensToDenom = mul_(
mul_(vars.collateralFactor, vars.exchangeRate),
vars.oraclePrice
);
vars.sumCollateral = mul_ScalarTruncateAddUInt(
vars.tokensToDenom,
vars.cTokenBalance,
vars.sumCollateral
);
Origin: verified Comptroller implementation 0x48c5e896d241afd1aee73ae19259a2e234256a85.
Once that manipulated liquidity check passes, cDOLA executes the underlying borrow path:
uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);
if (allowed != 0) {
return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed);
}
...
doTransferOut(borrower, borrowAmount);
...
totalBorrows = vars.totalBorrowsNew;
emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);
Origin: verified CToken.borrowFresh() source for cDOLA at 0x7fcb7dac61ee35b3d4a51117a7c58d53f0a8a670.
The on-chain trace confirms that the exploit followed exactly this code path. The attacker helper contract took a WBTC flash loan, added WBTC into TriCrypto, deposited the resulting LP into Yearn, minted cYvCurve-3Crypto, entered the market, and then borrowed all DOLA from cDOLA:
flashLoan(... WBTC, 2700000000000)
add_liquidity([0, 22500000000, 0], 0)
deposit(5375596969399930881565, attacker_helper)
0x1429...::mint(4906754677503974414310)
0x4dCf...::enterMarkets([0x1429...])
0x7Fcb...::borrow(10133949192393802606886848)
Origin: exploit execution trace for tx 0x958236266991bc3fe3b77feaacea120f172c0708ad01c7a715b255f218f9313c.
The balance diff for that transaction shows the measurable protocol loss directly: cDOLA went from 10133949192393802606886848 DOLA to 0, while the same amount moved into the downstream unwind path through the DOLA metapool. That is the concrete state transition that realizes the exploit.
The attacker cluster consists of EOA 0x7b792e49f640676b3706d666075e903b3a4deec6 and helper contract 0xf508c58ce37ce40a40997c715075172691f92e2d. The EOA first deployed the helper in tx 0xfb5a4d1aef98458f673f301c2e713613662ad621e8f57065a4da58a6401c0b4d. The deployment bytecode preloaded the fixed protocol addresses used by the exploit, which matches the helper role described in the trace.
The main exploit happened in tx 0x958236266991bc3fe3b77feaacea120f172c0708ad01c7a715b255f218f9313c, where the EOA called start() on the helper. The helper borrowed 2700000000000 WBTC base units from Aave, injected 22500000000 WBTC base units into TriCrypto, wrapped the manipulated LP through Yearn and cYvCurve-3Crypto, and then borrowed the entire cDOLA DOLA balance. After obtaining DOLA, the helper unwound through Curve pools, repaid the flash loan plus premium, and retained residual profit in WBTC and USDT.
The final realization happened in two direct withdrawals by the same EOA. Tx 0x9959f8f10f59b3b88a5499066a21237e492f193e5ff2950bcc7e6c1f5e1fa60c moved 5324446541 WBTC base units from the helper contract to the EOA. Tx 0x3d2f86c1c289731f56bed95dce20434eff48e3bd4a50cdc007ef5d0a2177a9f7 moved 99976294967 USDT base units from the helper contract to the EOA. Those two balance diffs close the loop from protocol drain to attacker-controlled profit.
The direct protocol loss recorded in the incident is the full DOLA cash balance of cDOLA: 10133949192393802606886848 base units, with 18 decimals. After the exploit, cDOLA cash was zero. The attacker position was not solvent after the flash loan repayment, which means the manipulated collateral only served to extract DOLA and leave the protocol with bad debt rather than with recoverable value.
The attacker’s realized profit was external to the drained DOLA accounting. The documented post-exploit withdrawals transferred 53.24446541 WBTC and 99,976.294967 USDT to the seed EOA. The root-cause artifact values those proceeds at approximately 1,258,121.46 USD net of gas at the incident block, but the key protocol-side loss remains the drained cDOLA DOLA balance.
0x958236266991bc3fe3b77feaacea120f172c0708ad01c7a715b255f218f9313c0xfb5a4d1aef98458f673f301c2e713613662ad621e8f57065a4da58a6401c0b4d0x9959f8f10f59b3b88a5499066a21237e492f193e5ff2950bcc7e6c1f5e1fa60c, 0x3d2f86c1c289731f56bed95dce20434eff48e3bd4a50cdc007ef5d0a2177a9f7YVCrv3CryptoFeed source: 0xe8b3bc58774857732c6c1147bfc9b9e5fb6f427c0x4dcf7407ae5c07f8681e1659f626e114a76673390x48c5e896d241afd1aee73ae19259a2e234256a85cDOLA CToken source: 0x7fcb7dac61ee35b3d4a51117a7c58d53f0a8a670/workspace/session/artifacts/collector/