ThunderLoan::deposit erroneously calculates a flash loan fee and calls assetToken.updateExchangeRate(calculatedFee) during a standard liquidity deposit. Because no flash loan fee is actually collected during deposit(), updating the exchange rate artificially inflates AssetToken::s_exchangeRate on every deposit, breaking share-to-asset accounting conservation and leading to protocol insolvency.
In src/protocol/ThunderLoan.sol, the deposit() function mints AssetToken shares to the liquidity provider and then immediately updates the exchange rate as if a flash loan fee had been paid:
Exchange rate updates should only occur during flashloan() when actual fee revenue is added to the pool. Updating s_exchangeRate inside deposit() causes the newly minted shares (as well as existing shares) to immediately claim more underlying tokens than were actually deposited into AssetToken.
Formal state-transition verification (INV-5: Share-Price Monotonicity Guard) confirms that a standard deposit increases assetToken.getExchangeRate() without any flash-loan fee entering the reserve:
You can also verify this in Foundry by adding the following test to test/unit/ThunderLoanTest.t.sol:
Manual Review, Foundry, Neuro-Symbolic Formal Verification (Z3).
Remove the fee calculation and updateExchangeRate call from ThunderLoan::deposit:
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.