Skip to content

Share inflation: the minimum is counted in both divisors, and tracked state is not enough - #162

Merged
mikemaccana merged 1 commit into
mainfrom
claude/sleepy-faraday-o7pmq1
Sep 23, 2026
Merged

mikemaccana merged 1 commit into
mainfrom
claude/sleepy-faraday-o7pmq1

Conversation

@mikemaccana

@mikemaccana mikemaccana commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Depends on quicknode/solana-program-examples#152. Merge that first. This PR names two tests that exist only on that branch, test_donation_cannot_round_a_later_deposit_to_zero and test_inflating_liquidity_through_own_trades_does_not_pay, and describes the behavior it ships.

Two first-deposit defenses in the companion repository did not work the way the book said:

  • Token swap: it minted later deposits against the bare LP supply while withdrawals divided by supply plus the floor.
  • Perpetual futures: it divided by the bare supply both ways, so the withheld 1,000 shares locked nothing. A provider who was also the pool's only trader could pay funding into liquidity and take part of the next deposit. Against the old program the attacker spent about 1,000 USDC and withdrew about 1,500.

The companion PR counts the minimum in every share divisor, and these chapters follow it.

  • Constant-Product AMM:
    • Alice's deposit and withdrawal now name the same divisor.
    • The inflation-attack bullet now gives the attack's price: a donation of about 101 times the victim's deposit, with 100/101 of it lost to the floor. It also explains why the floor must be in both divisors and names the test that runs the attack.
    • The rules list and the What You Learnt list are updated to match.
  • Perpetual Futures:
    • Carol's paragraph now says both handlers count the withheld shares.
    • The failure mode explains that pricing shares against liquidity stops a vault donation but not a provider's own funding payments, and gives the test's numbers.
  • The Adversary: the "Ignore donations" defense now says a recorded pool size stops donations only while nothing else the attacker controls can raise it, with the perpetual futures pool as the example.

Rebased onto current main, where the Adversary section and Carol's paragraph had been rewritten. main's text is kept, with these additions merged into it. npm run lint, node scripts/check-figure-geometry.mjs and npm run build-pdf all pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HagqhpPNqcywT37qqgnFey

… state is not enough

The companion repository's token swap minted later deposits against the
bare LP supply while withdrawals divided by supply plus the floor, and its
perpetual futures divided by the bare supply both ways, so the withheld
1,000 shares locked nothing. Both now count the minimum in every share
divisor (quicknode/solana-program-examples, branch
claude/sleepy-faraday-o7pmq1), and the chapters follow.

- Constant-Product AMM: Alice's deposit and withdrawal name the same
  divisor, and the inflation-attack bullet states the price of the attack
  (a donation of about 101 times the victim's deposit, 100/101 of it lost
  to the floor), why the floor must be in both divisors, and the test that
  runs it.
- Perpetual Futures: pricing shares against liquidity stops a vault
  donation, but a provider who is also the only trader can grow liquidity
  with their own funding payments. Carol's paragraph and the failure mode
  now say so, and what the locked minimum does about it, with the test's
  numbers.
- The Adversary: recording the pool's size ignores donations only while
  nothing else the attacker controls can raise the recorded figure, and
  the perpetual futures pool is the example.

Claude-Session: https://claude.ai/code/session_01HagqhpPNqcywT37qqgnFey
@mikemaccana
mikemaccana force-pushed the claude/sleepy-faraday-o7pmq1 branch from 811a3b7 to 1598200 Compare September 23, 2026 00:21
@mikemaccana mikemaccana changed the title Clarify MINIMUM_LIQUIDITY's role in deposit and withdrawal divisors Share inflation: the minimum is counted in both divisors, and tracked state is not enough Sep 23, 2026
@mikemaccana
mikemaccana merged commit f4298ea into main Sep 23, 2026
1 check passed
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