Configurable range margins + optional deposit whitelist - #233
Conversation
The rate-centered range was a single symmetric constant, so the two sides could not be sized independently even though they do different jobs: the lower margin has to cover the LST's structural discount to its redemption rate, while the upper margin is the drift budget between recenters and also bounds the min(fair,spot) deposit haircut, which grows as discount/(upper + discount). - Replace the constant with rangeLowerBps / rangeUpperBps storage, supplied to initialize and adjustable by MANAGER via setRangeBps. - Move the opening tick range into __V3DexAdapter_init, which now writes the margins before deriving the range from them. Subclass initializers previously computed the range themselves and passed it in, which would have read the margins before they were set. - wstETH / wbETH take maxTwapDeviationBps at initialize too, checked against the supplied upper margin: a TWAP clamped to the top of its band must not land at or past tickUpper, where the fair composition loses a leg and deposits revert. Its default drops to 25bps, which no longer needs setting post-deploy. - Size maxSpotDeviationBps off the measured spot-vs-rate discount instead of inheriting the range width; the two are unrelated. Defaults keep the shipped 50/50 geometry, so behaviour is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an opt-in allowlist for a gated launch. Shares are already non-transferable except by Moolah, so closing the deposit entry point is enough to keep them off non-whitelisted addresses; nothing else needs a gate. Both msg.sender and onBehalf are checked — gating only the caller would let a whitelisted address open a position for anyone. Withdraw, redeemShares, withdrawShares, the Moolah liquidation callback and the BOT paths are deliberately left open. Gating an exit would strand a delisted holder's funds, and gating a seizure would socialise bad debt to lenders; two of the new tests pin that behaviour so a later change cannot quietly extend the gate to those paths. Disabled by default, so existing deployments and tests are unaffected until MANAGER turns it on. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull Request ReviewThis Solidity DeFi PR makes V3 LP range margins independently configurable at initialization and by the MANAGER role, while adding TWAP-band validation for the wstETH and wbETH adapters. It also introduces an optional deposit allowlist in V3Provider, updates proxy initialization arguments, and adds tests covering allowlisted deposits and unrestricted exits/liquidations. Sensitive ContentNo sensitive content detected. Security Issues🟠 [HIGH] Deposit whitelist can be bypassed through existing share-supply paths
Generated by Hashdit Bot. This tool can absolutely NOT replace manual audits. |
Two independent changes to the V3 LP collateral stack, both behaviour-neutral on the shipped defaults.
1. Range margins become deploy-time parameters
The rate-centered range was a single symmetric constant, so the two sides could not be sized independently — even though they do different jobs:
tickUpper, and reaching it closes deposits) and it also bounds themin(fair, spot)deposit haircut, which grows asdiscount / (upper + discount).Changes:
rangeLowerBps/rangeUpperBpsreplace the constant, supplied toinitializeand adjustable by MANAGER viasetRangeBps.__V3DexAdapter_init, which now writes the margins before deriving the range from them. Subclass initializers previously computed the range themselves and passed it in, which would have read the margins before they were set.maxTwapDeviationBpsatinitializetoo, validated against the supplied upper margin: a TWAP clamped to the top of its band must not land at or pasttickUpper, where the fair composition loses a leg and every deposit reverts. Its default drops to 25bps, which removes a post-deploy configuration step.maxSpotDeviationBpsis now sized off the measured spot-vs-rate discount instead of inheriting the range width; the two are unrelated.Defaults keep the shipped 50/50 geometry, so on-chain behaviour is unchanged.
2. Optional deposit whitelist
An opt-in allowlist for a gated launch. Shares are already non-transferable except by Moolah, so closing the deposit entry point is enough to keep them off non-whitelisted addresses; nothing else needs a gate.
Both
msg.senderandonBehalfare checked — gating only the caller would let a whitelisted address open a position for anyone.withdraw,redeemShares,withdrawShares, the Moolah liquidation callback and the BOT paths are deliberately left open: gating an exit would strand a delisted holder's funds, and gating a seizure would socialise bad debt to lenders. Two of the new tests pin that behaviour so a later change cannot quietly extend the gate to those paths.Disabled by default, so existing deployments and tests are unaffected until MANAGER turns it on.
Testing
All 8 suites touching the changed contracts pass — 382 tests, 0 failures. The tick assertions in the existing suites are relational (
tickLower < tickUpper), so they were unaffected by the range split; only the derived default-value assertions needed updating.🤖 Generated with Claude Code