Perps: fix the funding rate at pool creation and cap it - #172
Merged
Merged
Conversation
The pool's authority could change the funding rate at any time with
set_funding_rate, with no upper bound. The lighter side of open interest is
paid funding out of `liquidity`, so the authority could open a small position on
that side from any wallet, raise the rate, and close the position to take the
liquidity providers' deposits. They could then liquidate the heavier side's
positions, whose collateral the funding had consumed.
- set_funding_rate is removed from all three versions (Quasar discriminator 7
is retired).
- initialize_pool refuses a funding rate above MAX_FUNDING_RATE_PER_SECOND
(277, just under 0.1% of a position's size per hour), with the existing
InvalidParameter error.
- New tests:
- initialize_pool_rejects_funding_rate_above_the_maximum
- operator_on_the_lighter_side_earns_only_the_fixed_rate: a wallet the
operator controls holds a short against a larger long for an hour at the
maximum rate, and is paid exactly the fixed rate.
- The funding tests now run at the maximum rate. The liquidity-inflation test
holds its position for ten years at that rate instead of 1,000 seconds at an
uncapped one.
Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The attack
set_funding_ratelet the pool's authority change the funding rate at any time, with no upper bound. The lighter side of open interest is paid funding out ofliquidity, which is the liquidity providers' deposits. So the authority could:open_positionaccepts any signer, and the program can't tell which wallets belong to the authority.set_funding_ratewith a huge rate.liquidity; the only limit is thatliquiditycan't go below zero (PoolInsolvent).The Perpetual Futures chapter in quicknode/solana-book says the program gives the operator "no path to anyone's collateral". This PR makes that true.
The fix
set_funding_rateis removed from the Anchor, Anchor v1 and Quasar versions. Quasar's discriminator 7 is retired.initialize_poolrefuses a funding rate aboveMAX_FUNDING_RATE_PER_SECOND, which is 277: just under 0.1% of a position's size per hour. It uses the existingInvalidParametererror, the same wayMAX_LEVERAGE_CEILINGis enforced.Tests
initialize_pool_rejects_funding_rate_above_the_maximum: 278 is refused and 277 is accepted.operator_on_the_lighter_side_earns_only_the_fixed_rate: a wallet the operator controls holds a 1,000 USDC short against a 10,000 USDC long for an hour at the maximum rate. It asserts that the wallet receives exactlysize × 277 × 3600 ÷ 10⁹(0.9972 USDC), and in the Anchor versions thatliquidityfalls by exactly that much.liquiditywell above the withheld minimum. The test's assertions on what the attacker and the victim get back are unchanged.set_funding_rate_settles_at_the_old_rate_firstonly_authority_can_set_funding_rateChecks
cargo fmtis clean.cargo check --testspasses for all three versions.The book change follows once this merges, as a PR stacked on quicknode/solana-book#190.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Generated by Claude Code