Metapool LP Normalization and Path-Equivalence Discipline

  • Name: Metapool LP normalization and path-equivalence discipline
  • Category: stable-swap metapool design note / LP-token unit-discipline reference / deployment-equivalence checklist / invariant-review note
  • Summary: Curve-style metapools that hold a base-pool LP token are only safe if the protocol keeps one explicit economic truth for that LP receipt token across every route that can quote it, swap it, mint it, burn it, or unwrap it. The base-pool LP token is not a flat stablecoin slot; it is a drifting claim whose value depends on base-pool virtual price. Healthy designs therefore centralize LP normalization, prove path equivalence across swap(), swapUnderlying(), quote helpers, and add/remove-liquidity flows, and treat live library linkage as part of solvency rather than a release-detail afterthought. The sharp review split is what raw LP units moved?, what normalized economic value should those units mean on this path?, and which exact deployed library or bytecode enforced that mapping? This note is the positive-design companion to LP-token scaling mismatch when the practical question becomes how should a protocol keep one LP-token truth across metapool math so path drift does not become a standing arbitrage against reserves?

Why this note exists

  • Metapool failures are easy to misremember as one missing multiply or divide, but the deeper lesson is that the protocol stopped treating the base-pool LP token as one security object with one canonical value transformation.
  • Nerve preserved the clean vulnerable path versus correct path form: swap() overpaid raw 3LP, then swapUnderlying() and the base pool still honored the correct virtual-price truth.
  • Synapse preserved the same AMM-side bug with a bridge-halt near miss layered on top, showing that operator intervention can contain monetization but does not make the pool math healthy.
  • Saddle preserved the deployment-side lesson: source patches and audit awareness were not enough when one live pool still pointed at stale vulnerable library code.
  • The durable design question is therefore not merely where do we apply getVirtualPrice()? It is how do we keep every path, every deployment artifact, and every reviewed implementation committed to the same LP-token truth before reserves go live?

What this note means by LP normalization and path equivalence

  • LP normalization means every path that handles a base-pool LP receipt token explicitly translates between raw LP-token units and normalized economic value with the same rule.
  • Path equivalence means all economically equivalent routes through the metapool family — direct swap, underlying swap, quote view, remove-liquidity leg, reverse route, simulation, and router logic — agree on that translation and therefore cannot disagree about what one raw LP share is worth.
  • The design target is not never use base-pool LP tokens in metapools. It is never let one route treat the LP token as a drifting receipt claim while another route quietly treats it as a unit-price stablecoin.

Three metapool review questions teams should not collapse

1. What raw LP units actually moved?

  • The first question is mechanical: how many raw base-pool LP receipt units left or entered the metapool on this path?
  • This is the token transfer / reserve delta / bookkeeping units question, not yet the economic-value question.
  • Reviews go wrong when teams start talking as if raw LP units are already self-explanatory value.

2. What normalized economic value should those units mean on this path?

  • The second question is economic: after applying the base pool’s virtual-price rule, what value do those raw LP units represent inside metapool pricing, reserve accounting, and invariant updates?
  • Synapse and Nerve are the clean reminders that the pool sent this many LP units and those LP units meant this much normalized value are separate facts. The exploit opened when swap() and sibling paths stopped agreeing on the second fact.
  • This is the real path-equivalence question. Two routes can move the same asset identifier yet still disagree about what that movement is economically worth.

3. Which exact deployed library or bytecode enforced that mapping?

  • The third question is deployment reality: which live helper, linked library, or implementation hash actually performed the raw-LP-to-normalized-value translation for funds at risk?

  • Saddle is the clean reminder that the repository now contains the right rule and the live pool used the right rule are separate facts.

  • If teams collapse this into the first two questions, they can correctly describe the intended math while still leaving production funds behind stale linkage.

  • The practical discipline is to answer all three questions in order: what units moved, what value should those units mean, and what live code proved that meaning. A metapool is only as healthy as the weakest of those three answers.

The five questions a healthy metapool design should answer

1. What is the canonical value object for the base-pool LP token?

  • Reviewers should be able to say in one sentence how raw LP shares map to normalized value and where that mapping lives.
  • It uses virtual price somewhere in MetaSwapUtils is not enough. The protocol should expose a readable rule for raw LP in -> normalized economic value and normalized value -> raw LP out.
  • If different helpers imply slightly different answers, the pool already has multiple truths.

2. Which routes are supposed to be economically equivalent?

  • A healthy review inventories every route that can touch the LP token: swap(), swapUnderlying(), quote views, add/remove-liquidity helpers, router simulations, and any base-pool unwrap / rewrap path.
  • The question is not only does each function look locally reasonable? It is would two routes that are meant to express the same economic trade agree about what just happened?
  • Route equivalence should be explicit enough that a reviewer can write down the expected fee-only difference between forward and reverse paths under unchanged market state.

3. Where is the invariant updated from normalized value rather than raw receipt units?

  • The metapool’s D, reserve accounting, and later quote paths must consume the economically normalized quantity, not an unscaled raw LP amount.
  • If one path updates reserve or invariant state before normalization, the pool starts compounding accounting fiction rather than merely misquoting one trade.
  • This is why the family is more dangerous than bad spot quote: once D moves off reality, later paths inherit the lie.

4. What proves the live deployment still uses the reviewed normalization logic?

  • Metapool safety depends on linked libraries and deployed bytecode, not just repository source.
  • If the system patched a helper in source control but one live pool still points at old library code, the vulnerability is still present in the only place that matters.
  • Healthy deployments therefore treat library-address inventories, implementation hashes, and post-deploy verification as part of solvency review.

5. How does the system fail before loopable path drift becomes a reserve drain?

  • Mathematical review and runtime containment should overlap.
  • A healthy system still keeps emergency pause criteria, route-level disablement, and a fleet inventory of all pools sharing the same math so one discovered path mismatch does not become repeated self-arbitrage across many deployments.
  • The design goal is not to replace correct math with ops. It is to prevent one normalization mistake from becoming a many-loop harvest.

What sound design looks like

  • One canonical LP-normalization helper exists.
    • Raw base-pool LP shares are translated into economic value in one place, and all quote, execution, and accounting paths reuse it.
  • Path families are reviewed as one object.
    • swap(), swapUnderlying(), reverse swaps, add/remove-liquidity helpers, and router views are reviewed as economically equivalent route families rather than as isolated functions.
  • Invariant updates consume normalized value, not raw receipt units.
    • Reserve accounting and D updates only happen after the protocol has translated the LP receipt token into the same value domain the rest of the pool uses.
  • Deployment provenance is inside the trust boundary.
    • Teams know which live pools depend on which library addresses and can prove the deployed bytecode matches the reviewed fix.
  • Raw units, normalized value, and live implementation stay visibly separate.
    • Reviews preserve what moved, what it meant, and what deployed code enforced that meaning as three explicit checks instead of one fuzzy the LP path looked fine conclusion.
  • Round-trip route discipline is testable.
    • Same-state forward and reverse routes are expected to lose fees, not print value, and the test harness encodes that expectation directly.
  • The clean reviewer question is: if two different paths touch the same base-pool LP token today, what evidence proves they still share one normalization rule and one reserve-update truth?

Useful positive design shapes

1. Canonical raw-LP ←> normalized-value helpers

  • Treat the base-pool LP token as a special asset type with named conversion helpers instead of scattered inline arithmetic.
  • Both LP in and LP out transformations should be explicit, commented, and reused by execution and view paths.
  • This is the simplest positive-design answer to one branch forgot virtual-price scaling.

2. Route-equivalence harnesses

  • Maintain tests that compare economically equivalent paths under unchanged state: direct swap versus underlying swap, vulnerable-looking route versus reverse route, add-then-remove cycles, and router simulations versus execution.
  • The result should be bounded by fees and slippage assumptions, never by unexplained positive PnL.
  • These tests catch disagreements between individually plausible functions better than local unit tests do.

3. Invariant-after-normalization assertions

  • Assert that D, reserves, and post-trade state move according to normalized value that actually entered or left the pool.
  • If one first trade can push D below economically correct state, the system should fail immediately in tests.
  • This keeps mis-normalized first leg from silently becoming corrupted state for every later leg.

4. Deployment-linked library inventories

  • Track every live metapool, its implementation hash, and every library address it links.
  • Release review should fail if the inventory cannot prove which pools still depend on old math helpers.
  • This is the operational answer to Saddle-style fixed in source, still broken in production risk.

5. Herd-response playbooks for sibling forks and deployments

  • If a sibling Curve/Saddle-style deployment lands a normalization exploit, teams should already know every internal pool sharing that code family and how to pause or disable them quickly.
  • Metapool math bugs rarely stay isolated once the primitive is public.
  • Good response starts with knowing the full herd, not just the first wounded pool.

Design questions worth asking first

  • What raw base-pool LP units can move on each route, and where are those movements measured directly in reserve accounting?
  • Where is the single canonical transformation between raw base-pool LP units and normalized economic value defined?
  • Which paths are supposed to be equivalent for that LP token, and where is that equivalence tested directly?
  • Do reserve and invariant updates consume normalized value only after the translation is applied?
  • Can a same-state forward route plus reverse route ever make money before fees because two helpers disagree about LP-token truth?
  • Which live pools still depend on older normalization libraries or implementation hashes?
  • If a sibling protocol disclosed this bug family tomorrow, how quickly could operators enumerate and disable every internal deployment sharing the same math?

Red flags

  • The LP token is basically another stablecoin slot.
  • swap() and swapUnderlying() are different enough that they do not need tight equivalence tests.
  • The source repo is fixed without a live deployment / library inventory.
  • The first quote is slightly off but the pool can recover later.
  • The reverse path is handled elsewhere when that elsewhere is exactly where the accounting disagreement will cash out.
  • We will pause if needed without knowing every linked deployment that shares the vulnerable helper.

Failure-prevention checklist

  • Centralize base-pool LP normalization in one named helper or library routine and make every route reuse it.
  • Differential-test direct swap, underlying swap, quote views, router simulations, and add/remove-liquidity paths for the same economic trade.
  • Add round-trip properties requiring same-state forward and reverse routes to lose only fees and slippage, never produce unexplained profit.
  • Assert that invariant and reserve updates occur after normalization and remain consistent with economically normalized inflow / outflow, not raw LP-token units.
  • Keep a live inventory of metapools, implementation hashes, and linked library addresses so reviewed fixes can be matched to production bytecode.
  • Treat patched source and patched deployment as separate release gates; do not close an incident until both are verified.
  • Predefine emergency disablement for every pool sharing a normalization helper so a public exploit in one deployment can trigger herd-level containment.
  • Review routers and offchain quoting logic too; if offchain tooling assumes different normalization than execution, it can hide path drift until real value is live.

Audit prompts

  • What exact helper maps raw base-pool LP shares to normalized value, and do all execution and view paths call it?
  • Where does outgoing LP-token math invert the same rule that incoming LP-token math uses, and is that symmetry tested directly?
  • If a trader swaps through swap() and immediately reverses through swapUnderlying() under unchanged state, what exact test proves the result is fee loss rather than profit?
  • Can one under-normalized first trade corrupt D or reserves so later trades pay from the same accounting lie?
  • Which live pools still link older MetaSwapUtils-style helpers or equivalent libraries despite source patches?
  • Do deployment manifests, bytecode verification, and monitoring make linked-library provenance visible to responders?
  • Are offchain quote paths, routers, and simulations guaranteed to use the same normalization semantics as onchain execution?
  • If a public exploit lands in a sibling fork, what exact inventory and runbook enumerates every affected internal deployment before attackers do?

Lessons that should already be standard

  • A base-pool LP token is a drifting receipt claim, not a plain stablecoin slot wearing different branding.
  • What moved, what it was worth, and what live code enforced that worth are three different review facts. Collapsing them is how teams miss Synapse/Nerve-style path drift and Saddle-style stale deployment at the same time.
  • Path equivalence is a solvency property. If two routes disagree about the LP token’s value, the pool is already an arbitrage machine against itself.
  • Invariant corruption is the real compounding risk. Mis-normalization does not just misquote once; it can move reserve state onto false footing for every later trade.
  • Deployment provenance is part of pool safety. A fixed repository does not matter if a live pool still links stale math.
  • Herd-level response should be standard for forked metapool families. One public exploit in the code family is evidence against every sibling deployment until proven otherwise.
  • Reviewers should read metapool LP handling as one security object: normalization helpers, route equivalence, invariant updates, library linkage, and emergency disablement all decide whether reserves stay money-good.

Negative exemplar cluster

  • Synapse — the AMM-side exploit primitive already worked, but bridge-halt intervention contained the final monetization.
  • Nerve — the clean path-mismatch form where one vulnerable path and one correct path disagreed about the same 3LP truth.
  • Saddle — the deployment-survivor form where stale library linkage re-exposed the same bug after the broader family was already known.

How this note complements the exploit corpus

Internal linkages

Control surface

  • The decisive control surface is every place raw base-pool LP receipt units become pool-accounting value: quote helpers, swap execution, invariant updates, reverse routes, linked libraries, and deployment manifests.
  • The review boundary is sharper if teams preserve three separate checks across that surface: what raw LP units moved, what normalized value those units should mean, and which exact deployed helper enforced that conversion for live funds.
  • Protocols get materially safer when those facts remain one explicit object — one normalization rule, one route-equivalence harness, one deployment inventory, and one herd-response plan — instead of a collection of locally plausible helpers.
  • The most useful review question for this note is blunt: if two routes touch the same LP receipt token today, what proves they still honor one value truth before the pool spends reserves against it?

Sources