Skip to content

docs: record the one-sided target pair check for the Celo LP swap - #349

Merged
DavidMinarsch merged 1 commit into
mainfrom
docs/celo-lp-swap-runbook-step
Aug 30, 2026
Merged

docs: record the one-sided target pair check for the Celo LP swap#349
DavidMinarsch merged 1 commit into
mainfrom
docs/celo-lp-swap-runbook-step

Conversation

@DavidMinarsch

Copy link
Copy Markdown
Contributor

Operational follow-up to vulnerabilities list entry 37.

LPSwapCelo already guards a pre-existing target pair whose reserves are skewed, by deriving minimum amounts from the TWAP-protected removal. It does not cover a pair seeded on one side only: the router branches on reserves, and a (X, 0) pair is neither the both-zero case nor quotable, so UniswapV2Library.quote reverts INSUFFICIENT_LIQUIDITY before the minimums are consulted.

The guard is bypassed rather than triggered — which is why the revert reads as unrelated to slippage, and why this is worth writing down rather than leaving to be diagnosed live. Creating and seeding the pair is permissionless.

Nothing is at risk when it happens. The transaction is atomic, so the source LP removal rolls back. But the pair keeps its state, so retries fail identically until it is repaired — and the repair is permissionless too, so it needs no privileged key or governance action.

Recorded in the two places an operator would look

  • A pre-flight block on proposal_23_transfer_lp_token_celo.sh, which is the script actually run — with the cast call to read the reserves and the dust-plus-sync() repair.
  • Runbook §3.4, alongside §3.3's V3 initialize() front-run, which is the same family of problem on the V3 side.

No code change.

LPSwapCelo guards a pre-existing target pair whose reserves are skewed, by
deriving minimum amounts from the TWAP-protected removal. It does not cover a
pair seeded on one side only: the router branches on reserves, and a (X, 0) pair
is neither the both-zero case nor quotable, so UniswapV2Library.quote reverts
INSUFFICIENT_LIQUIDITY before the minimums are consulted. The guard is bypassed
rather than triggered, which is why the revert reads as unrelated to slippage -
and creating and seeding the pair is permissionless.

Nothing is lost when it happens: the transaction is atomic so the source LP
removal rolls back. But the pair keeps its state, so retries fail identically
until it is repaired - and the repair is permissionless too, needing no
privileged key.

Recorded in the two places an operator would look: a pre-flight block on
proposal_23, which is the script actually run, with the cast call to read the
reserves and the dust-plus-sync repair; and as runbook section 3.4, alongside the
V3 initialize() front-run it mirrors.
@DavidMinarsch
DavidMinarsch merged commit e1c3e0e into main Aug 30, 2026
3 checks passed
@DavidMinarsch
DavidMinarsch deleted the docs/celo-lp-swap-runbook-step branch August 30, 2026 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant