redeemPosition rounding turns fixed deposits noisy
The failure sat in round-based settlement logic, not in the SEA token itself and not in the Uniswap V2 style pair. The vulnerable adapter proxy at 0xa70f31c06f921019237fc00b1417217dae5c37c5 used round state when calculating redemption, then let the caller walk from getUserRoundInfo into redeemPosition with inflated entitlement.
That is where fixed deposits stop behaving like fixed deposits. A user puts in the same USDT lot each time, but the adapter’s round maths can shift the visible claim away from the actual settled balance. Once redemption is tied to round accounting rather than settled value, small errors stop being small. They compound.
In this case, the helper contract deposited 3,000 USDT per loop after a 300 USDT swap step, then redeemed SEA through the adapter. The same pattern repeated 12 times in one transaction. The owner-only flash-loan entrypoint and callback wiring removed the capital constraint that would normally make repeated misuse expensive.
The settlement adapter turns a fixed USDT lot into a moving SEA claim
The adapter’s behaviour matters because it sits between deposit state and token redemption. It queried round information, then pulled through router and pair data during redemption. That gives the contract more than one place to go wrong. If the round value and the actual entitlement drift apart, the redemption path can pay out on stale or inflated assumptions.
The exploit transaction shows the adapter handling the same selectors over and over: 0x987217bc for the settlement function, 0x49525c23 for round info, and 0xf046d966 for redeemPosition(). The repetition is the clue. The attacker did not need a fancy sequence. They only needed the adapter to keep accepting the same fixed deposit while recalculating SEA in a way that favoured the caller.
That is a classic local logic fault. The attack did not need to break the token contract, forge reserves, or bend the pair. It only needed a redemption formula that treated round state as if it were settled value.
Flash-loan loops expose the gap between round state and actual entitlement
Flash-loan funding makes this sort of flaw ugly very quickly. Aave’s flashLoanSimple supplied 3,300 USDT, which was enough to run the loop from start to finish inside one transaction. There was no need to hold capital between iterations, which is what would usually slow down a bad redemption path and make the economics less convenient.
Each loop used the same pattern: deposit 3,000 USDT, query round info, redeem SEA, then continue. The total transaction ended with the attacker EOA holding 13,904.941068 USDT. That is the sort of number that usually means the math was doing something it should not.
The net loss landed on the SEA/USDT pair, which lost 13,906.591068 USDT and ended up with 129,202,760.357336 SEA. That is the practical consequence of bad round logic in a settlement adapter. Once redemption pays out too much SEA, the sale path turns the mistake into liquid USDT before the contract has a chance to notice.
The SEA/USDT sale path makes the rounding error cash out cleanly
Redemption alone does not complete the damage. The SEA had to be sold back through the SEA/USDT pair at 0xeeb9c6b73a9ba397fbea320d9e4cce7b8ac10513. That sale path matters because it converts an accounting bug into a balance shift the attacker can keep.
The adapter query path also pulled router and pair reserves during redemption, which suggests the contract was using market state while calculating what to release. If that calculation is off, selling the redeemed SEA back into the pair locks in the difference. The attacker does not need to hold the token position. They only need the redemption to over-credit SEA before the swap back to USDT.
Recovered traces point to repeated calls into the same helper selectors and repeated SEA transfers to treasury-side and other addresses in the redemption path. The exact internal formula is not cleanly recoverable, but the behaviour is plain enough. A fixed deposit should not unlock a larger SEA claim just because the round counter moved.
Close the hole by tying redemption to settled balance, not round maths
Redemption should be bounded by settled USDT balance, not by a round-derived estimate that can drift under same-transaction reuse. If round data still has a role, it needs to be advisory only. The payout must be checked against what is actually settled and withdrawable at the point of redemption.
A practical control is to compute entitlement from finalised balance, then cap redemption at that value before any token transfer. Pair or router reads should not be able to inflate the amount being released. If round state is needed for user accounting, keep it separate from the transfer calculation.
The safer boundary is simple: a deposit round can inform state, but it cannot mint a bigger claim than the settled amount that backed it. Once that line is blurred, flash-loan loops do the rest with very little effort.




