
Date: August 2, 2026
Chain: BNB Chain
Loss: 693,529.79 USDC, about $694K, paid out of LpdFi's protocol-owned liquidity
Class: spot-price valuation of deposits and redemptions from the same manipulable pool
At 15:59:59 UTC on August 2, 2026, an attacker opened a position in LpdFi, the yield protocol built around the LOOPSDAO (LPD) token on BNB Chain, by depositing 214,171.5 LPD. The protocol recorded that deposit as 140,324,732 dollars of principal. One second later, at 16:00:00 UTC, the next block crossed into a new interest period, and the attacker claimed a full period of interest on that principal.
Paying the claim took nearly all of LpdFi's liquidity. The protocol burned about 1.68 million of its own PancakeSwap LP tokens and handed 693,529.79 USDC, about $694,000, to the attacker. Both numbers came from the same place: LpdFi priced the deposit and sized the payout from the live reserves of a single LPD/USDC pool, and the attacker controlled those reserves for exactly as long as each transaction needed.
LpdFi let users deposit LPD and earn interest in USDC. According to BlockSec's analysis, a deposit was valued at the current LPD/USDC spot price and stored as uAmount, a dollar-denominated principal. Interest accrued once per "issue," a daily accounting period, with total interest capped against the recorded principal. When a user claimed, the protocol removed liquidity from the LPD/USDC PancakeSwap pair using LP tokens it held itself, then split the USDC between the claimant and a fee address.
That made the protocol's own LP position the treasury. Every USDC an interest claim paid out came from burning LP tokens the protocol owned, so the size of that LP position was the limit on what a single claim could take.
Defimon's alert traces the price to Lpd.price(), which reads the LPD/USDC pair's spot reserves directly, with no time-weighted average and no guard against manipulation. BlockSec describes the same reserves doing two separate jobs. In buy(), the token price set the dollar value of a new deposit, so the principal moved with whatever the pool said at that moment. In claimInterest(), the payout ran through removeLp(), which sized the LP burn from the pool's live USDC reserve at claim time.
The lesson sits right there in those two functions. Spot reserves on an automated market maker describe what one block's trades left behind, and anyone with enough capital, including borrowed capital, can set them. A protocol that values deposits from them lets a depositor choose the value of their own deposit. One that sizes redemptions from them lets the claimant shape how much backing each dollar of payout consumes. LpdFi did both from the same pool, and never compared a position's recorded principal against what was actually backing it.
The attack used two transactions from the attacker's wallet, 0x5d289266d85EF671561bA3F253FB79327C193f33, through an attack contract at 0x7f5ad0a998dcb3f5006f0d152bebc055979ef711. In the first, the contract borrowed USDC from 17 different lenders and pools, every one of them repaid before the transaction ended, and added 116,495 USDC from the attacker's own wallet. It swapped 43,714,602.62 USDC into the LPD/USDC pair and received 4,788,064.49 LPD. Chainalysis reported that the roughly $44 million in borrowed funds pushed LPD's price on the DEX up about 71 times, which let about $2 million worth of tokens pass for a $140 million deposit.
At that inflated price, the contract called buy() and deposited 214,171.52 LPD into LpdFi, which recorded 140,324,732 of principal, according to BlockSec and Defi Nerd's alert. It then sold 4,116,503.68 LPD back into the pair for 43,612,169.55 USDC and repaid every lender. The price fell back, but the principal stayed on the books at its inflated value.
The second transaction landed in the very next block, 113613924, at 16:00:00 UTC. BlockSec explains that this block crossed an issue boundary, so one period of interest on the inflated principal became claimable. The attack contract borrowed 730,607.76 USDC, sent 3,440.99 USDC straight to the pair, and called sync() to update its reserves. According to BlockSec, that nudged the pair's recorded USDC reserve from 718,619.89 to 722,060.88 and reduced how many LP tokens removeLp() needed to burn, which kept the redemption within the protocol's actual LP balance instead of reverting.
Then it called claimInterest(0). BlockSec puts the claimable interest at 701,623.66 USDC for a single issue. LpdFi burned 1,678,049.36 LP tokens, received 700,535.14 USDC and 4,059,427.51 LPD from the pair, kept the LPD, sent 7,005.35 USDC to its fee address, and paid the remaining 693,529.79 USDC to the attack contract. BlockSec notes that the burn took about 97% of the pair's total LP supply. The contract repaid its 730,607.76 USDC loan and sent 689,529.79 USDC to the attacker's wallet.
The attacker put 116,495 USDC into the first transaction and took 689,529.79 USDC out of the second, which is why some tallies, such as Nominis's August report at $573,000, come in lower than the roughly $690,000 to $700,000 that Defimon, ExVul, BlockSec and Chainalysis reported. The figure in this post is what left LpdFi's liquidity for the attacker.
According to AMLBot, most of the funds were swapped from USDC to BNB and sent to Tornado Cash, and the attacker's gas money had come from Tornado Cash as well. Chainalysis reported that the proceeds went through Relay before reaching Tornado Cash. As of October 20, 2026, we hadn't found a post-mortem or recovery statement from the LpdFi or LOOPSDAO team.
Olympix reads LpdFi as an attacker would, as states, transitions and entry points, and it takes in what the protocol is for, interest on deposits paid from protocol-owned liquidity, to infer the invariants the code relies on but never states. The states that matter here are each order's recorded principal and the protocol's LP balance, and every entry point that can change either one is a path worth mapping. Olympix's static analysis surfaces the signal: a value read from getReserves() on a pool anyone can trade against, flowing into stored principal in buy() and into the size of an LP burn in removeLp(), with no time-weighting or bound in between.
The invariant is plain: a position should never be able to withdraw more backing than it contributed. BugPoCer works from that rule outward. It runs Counterexample-Guided Invariant Refutation, inferring the invariant from how buy(), claimInterest() and removeLp() fit together, and executing paths until one breaks it. Paths that never touch the pair's reserves drop out, and the ones that remain all pass through a swap or a direct transfer to the pair before a call into LpdFi.
The counterexample it returns is this attack in miniature. Swap into the pair to raise the LPD price, call buy() so the principal records at the inflated value, swap back out, advance one issue, adjust the reserve with a transfer and sync(), and call claimInterest(). BugPoCer reports that sequence with the minimal conditions, enough borrowed USDC to move the price and a single period boundary, plus a generated Forge test that replays it, showing the protocol paying out far more USDC than the deposit was worth. That's the August 2 drain, produced in development instead of on mainnet.
Olympix has flagged this class before in other codebases, where a contract trusts a spot price that the caller can push in the same transaction. It runs automatically as code is written, at every merge and before release, so a valuation path tied to live pool reserves shows up the day it's added.
LpdFi's interest math only worked if the principal underneath it was real, and the only thing deciding the principal was a pool reserve that changed with every trade. Valuing deposits from a manipulation-resistant price and checking each claim against what the position actually contributed would have closed both halves of this attack. To see how Olympix maps the paths from an AMM reserve into your own accounting and hands back a runnable counterexample for each one that breaks, book a technical walkthrough.
Protocol: LpdFi (LOOPSDAO / LPD)
Chain: BNB Chain
Date: August 2, 2026, 15:59:59 UTC (setup) and 16:00:00 UTC (claim)
Loss: 693,529.79 USDC paid by LpdFi to the attack contract
Attacker EOA: 0x5d28...3f33
Attack contract: 0x7f5a...f711
LpdFi contract (victim): 0xce6a...295e
LPD token: 0x3876...3604
LPD/USDC PancakeSwap pair: 0x8534...f210
Fee address: 0x4c0c...7242
Setup tx (inflated deposit): 0xbb5b...3588
Exploit tx (interest claim): 0x70bb...15d6
Blocks: 113613923 and 113613924
BlockSec: Weekly Web3 Security Incident Roundup (MOKE Token and LpdFi Exploits)
Defimon Alerts: LpdFi Loss ~$690K
Chainalysis: Hexagate Detects $700K Exploit Against LpdFi
Nominis: Monthly Report, Crypto Exploits and Attacks in August 2026