Constant Product Manipulation: Future Protocol $4.6M

Constant Product Manipulation: When a Token Breaks the Pool It Was Built For

Aug 19

| 6 min read

constant-product-manipulation-future-protocol-exploit

The Auditor’s Take is a weekly series by Jon Stephens, CEO of Veridise. This article is about a class of bug where a token’s own transfer logic breaks an invariant of the protocol it was written to work with. New take every week. Find Jon at @FormallyJon.

Custom token implementations that add fees or constraints to events like transfers, mints and burns are not unusual. The protocols that interact with such a token, though, were written expecting an ordinary ERC20, and some of them depend on properties the token is now in a position to break. That is the shape of the bug that cost Future Protocol about $4.6 million in July 2025.

TLDR:

  • FPC added logic for one PancakeSwap pair and broke the pool’s key assumptions
  • The fee was burned from the pool’s holdings, not from the seller’s balance
  • The pool was told to refresh its recorded reserves before the incoming tokens arrived
  • It then priced trades as though it held almost none of the token
  • Writing custom logic against a protocol means maintaining that protocol’s invariants

A Token That Special-Cases a Protocol Inherits Its Invariants

Tokens that burn, tax, or rebase when they move come up often enough that we look for them early in a DeFi audit. On its own the behavior is harmless, and what matters is the interaction of these behaviors with external protocols.

A constant product pool provides an automated method of exchanging two tokens. To do so, a relationship between the token balances held in reserve must be maintained, because the pool’s spot price is calculated from it. This assumes, however, that only the pool may adjust those reserve assets. If changes to the reserve balances occur outside of the pool, the pool has no way of automatically recognizing and rectifying it.

The pool enforces solvency through that product: it must be maintained as tokens are added, removed or swapped. A pool holding ordinary tokens satisfies that by construction, since the pool itself may only adjust its reserves, but add a token that can adjust those reserve balances outside the pool’s own logic and the guarantee is gone.

A pool also stores its reserve figures separately from the token balances it actually holds, and the two are allowed to differ. Send tokens directly to a pool and its balance rises while the stored figures sit unchanged. Anyone may reconcile them with one of two functions. sync sets the stored figures to whatever the pool currently holds. skim keeps the figures and hands the extra tokens to whoever called it. Each assumes the pool is carrying a surplus, and a surplus can only push the product up.

Different tokens have reached the same outcome through unrelated code. On BSC in May 2025, a KRC/BUSD pair was drained by repeated transfers followed by a skim call, which let burn logic act against reserves already recorded, per OpenZeppelin. New Gold Protocol took a 35% sell fee from the pool rather than the seller in September 2025. It synced before the seller’s tokens arrived, and lost around $2 million to that flaw and a manipulable oracle, per QuillAudits. BFB lost 396 BNB in July 2026 to zero-value transferFrom calls that burned 5% of a pool’s holdings, about 151 times over, per AMBCrypto.

The Case Those Two Functions Were Not Written For

Both functions assume the pool holds more than its recorded reserves, and that whatever caused the difference has already finished. Neither checks the product, because in that situation the product cannot have fallen.

A token breaks both assumptions by calling sync partway through its own transfer, before it has finished moving tokens, so the stored figures get overwritten from a balance lower than the one the pool will hold a moment later. Nothing corrects them afterwards, and the pool keeps pricing from figures that understate one side, so it sells the other side far too cheaply.

Future Protocol’s FPC token charged a fee on transfers whose recipient was the FPC/USDT pair, which is how a sale reaches the pool. On such a transfer it ran three steps in order: burn the fee from the pool’s holdings, call sync, then transfer the remaining tokens to the pool.

The middle step is the fault. It rewrote the stored reserves at the one moment when the burn had completed and the incoming tokens had not yet arrived. On July 2, 2025 an attacker used that window to leave the recorded FPC reserve at 0.000065 against a USDT reserve that had not moved. The pool then priced FPC as though it were almost gone and paid out about $4.6 million more than the attack cost to set up.

What Makes It Hard to See

Each step is defensible on its own. Burning a fee is legitimate. Calling sync on a pool whose balance has changed is why the function exists. Transferring the remainder to the recipient is the point of the operation. It is the sequence that is wrong.

The token also knows the recipient is a pool, since the branch tests for its address, and it did not take sufficient steps to preserve that pool’s safety. Writing logic that special-cases a protocol means taking on responsibility for that protocol’s key assumptions.

Reviewing the pool in isolation will not settle it, because a pool knows nothing about the tokens that will interact with it, and a sufficiently unusual token will always break something, so the line has to be drawn somewhere. The token is where you catch this. Its interaction with PancakeSwap is right there in the source, and a reviewer who knows how a pool maintains its reserves will see that the ordering is invalid. Interactions of this kind belong in a security review.

How a Senior Auditor Catches It

Threat modeling a token starts from what it does that is not standard, and where that behavior lands. Both questions come before the line-by-line read in a smart contract audit: which protocols does this token special-case, and which of their guarantees does its behavior touch?

For FPC both answers are in the source: the token names a PancakeSwap pair, so the protocol is identified, and the behavior is a burn taken from that pool’s holdings followed by a call that rewrites its stored reserves. The rest is knowing what the pool guarantees, which is that the product of its two reserve balances is maintained, and then reading the token’s sequence against that. Burn and rewrite both land before the incoming tokens do, so the figures the pool keeps are lower than the balances it holds.

Why Manual Review Misses It, and How Tooling Helps

The reasoning is not hard, but it does not scale, because it depends on a reviewer knowing the internals of every protocol a token integrates with, and on holding the token and the protocol in view at once.

The guarantee is small enough to write down and check automatically. OrCa, the specification-guided fuzzer in AuditHub, takes the property that the product of a pool’s reserves must not end a transaction lower than it started, then searches for a sequence of calls that violates it. Pointed at the token and the pool together, in their deployed state, it returns one. The sequence is short: a transfer into the pool is enough, with no swap and no flash loan involved.

What Carries Beyond Future Protocol

Custom logic written against another protocol carries an obligation. FPC’s author implemented behavior specific to PancakeSwap without maintaining the key assumptions PancakeSwap relies on. Any contract that special-cases another one takes on the same duty: understand what the other contract guarantees, and make sure your logic still holds it.

Composition happens without anyone’s approval, which is true of every contract on chain. What sets tokens apart is ubiquity: ERC20 standardization makes a single token easy to integrate, so one implementation can end up inside a great many protocols. And where the author does choose, and writes logic against one named protocol, there is no question where the responsibility sits.

Writing a token with custom transfer logic?

If your token special-cases a protocol, burns on transfer, or otherwise adjusts balances another contract is accounting for, that protocol’s invariants are now yours to maintain. The token can read perfectly well on its own while breaking them.

If you want a second pair of eyes before your next deploy, talk to us.

The Takeaway

Constant product manipulation happens when something other than the pool changes the reserve balances it prices from, and the pool records the change as legitimate. A token that adds logic for one named protocol takes on that protocol’s invariants. Reviewing such a token means checking its behavior against what the protocol it integrates with guarantees.

More by Veridise

Subscribe to our blog

Be the first to get the latest from Veridise — including educational articles on ZK and smart contracts, audit case studies, and updates on our tool development. Delivered twice a month.

smart contract audit cloud

Subscribe to our newsletter

A monthly round-up for protocol teams: new audit reports, research from our lab, and tooling releases from the Veridise team.

One email a month. Unsubscribe in one click

Contact us for a security audit quote

Secure an earlier audit slot by reaching out early.