# Availability of deposit invariant can be bypassed

PrelaunchPoints computes claimedAmount from contract ETH balance, so donating ETH before claim mints extra lpETH, bypassing the pre-activation deposit invariant.

- Payout: Contest reward
- Severity: high
- Program: LoopFi
- Credited: 0xnev
- Disclosed: 2024-06-12
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2024-05-loop-findings/issues/33
- Library page: https://bugbountylibrary.com/r/c4%3A2024-05-loop%3AH-01
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic

**Target:** PrelaunchPoints.sol claim/convertAllETH flow
**Root cause:** claim() sets claimedAmount to address(this).balance instead of the actual ETH received from the LRT swap, so any donated ETH is credited to the claimer. convertAllETH derives totalLpETH from balance, letting donations inflate the mint ratio.
**Steps:**
1. Lock a position with an allowed wrapped LRT before loopActivation.
2. In one tx: send ETH directly to PrelaunchPoints (donation).
3. Call `claim()`/`claimAndStake()`; `_fillQuote` swaps LRT to ETH.
4. claimedAmount = address(this).balance includes donated ETH; lpETH.deposit()/stake() mints claimedAmount worth of lpETH.
5. Alt: front-run `convertAllETH()` with a 1 ETH donation so totalLpETH=101 vs 100 supply; back-run by claiming 10 positions each minting 1.01 lpETH.
**How found:** Read the main invariants (deposits active only before contracts set) and traced claim()/convertAllETH() balance-based accounting to spot that direct ETH donations are credited to claimers.
**Exploitation:** Attacker donates ETH to the contract then claims a previously locked LRT position in the same transaction, receiving lpETH for the donated ETH without locking it before loopActivation, bypassing onlyBeforeDate and the 1:1 invariant.
**Escalation:** Multiple lock positions amplify the ratio inflation in the convertAllETH sandwich variant.
**Insight:** When a contract derives user credit from address(this).balance rather than the measured swap output, any unsolicited ETH transfer becomes claimable — check every balance-based accounting path for donation/sandwich inflation.
