Skip to content

feat(provider): assert expectedCenterRate on rebalance - #227

Merged
razww merged 2 commits into
audit/v3-lp-fixesfrom
feat/v3-rebalance-center-rate-guard
Aug 6, 2026
Merged

feat(provider): assert expectedCenterRate on rebalance#227
razww merged 2 commits into
audit/v3-lp-fixesfrom
feat/v3-rebalance-center-rate-guard

Conversation

@razww

@razww razww commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

📄 Description

Adds a BOT-asserted center-rate guard to rebalance. The BOT reads the live LST↔native rate via the new
adapter.centerRate() view and passes it back as expectedCenterRate; if the on-chain rate deviates from
it by more than maxCenterRateDeviationBps, the call reverts (CenterRateDeviationTooHigh).

🧠 Rationale

The range center comes from the on-chain LST↔native rate, but the fair-NAV loss caps measure the rebalance
before/after in that same rate frame — so a rate anomaly between the BOT's build and on-chain execution
is invisible to them, and the position could be recentered (and inventory converted) around a bad anchor.
This guard bounds the anchor independently, symmetric with the existing targetSqrtPriceX96 spot-deviation
gate. Both sides opt in (expectedCenterRate != 0 per-call, maxCenterRateDeviationBps != 0 globally); 0
preserves prior behavior, so it's backward-compatible and storage is append-only (upgrade-safe).

🧪 Example / Testing

Doc-faithful counter-tests in SlisBNBV3Provider.t.sol (real slippage/target floors, not zeros):

  • test_rebalance_revertsOnCenterRateMismatch — otherwise-valid params + a 2%-off expectedCenterRate still reverts (guard fires before any burn/mint).
  • test_rebalance_passesWithinCenterRateBandexpectedCenterRate == centerRate() clears the guard; the full recenter completes and stays value-neutral.
  • test_rebalance_centerRateGuardOffByDefault — default band 0 ignores a wrong rate while the real slippage/target guards still apply.

Full provider suite green (forge test --match-path "test/provider/*" → 376 passed; needs BSC_RPC/ETH_RPC).

🧬 Changes Summary

  • rebalance gains an expectedCenterRate param (adapter, IV3DexAdapter, V3Provider._guardedRebalance, and the slisBNB/wstETH/wbETH wrappers); the assertion fires before any mint.
  • New maxCenterRateDeviationBps storage (append-only) + MANAGER setter + event; new CenterRateDeviationTooHigh error.
  • New centerRate() view (adapter + interface) so the BOT can read the live rate to pass back.
  • All existing rebalance call sites pass 0 (unchanged behavior).

🤖 Generated with Claude Code

rebalance takes an expectedCenterRate the BOT reads via the new adapter
centerRate() view and passes back; if the live LST↔native rate deviates from
it by more than maxCenterRateDeviationBps the call reverts. This bounds the
range anchor against a rate anomaly between build and execution — invisible to
the fair-NAV loss caps, which measure in the same rate frame.

Both sides opt in (expectedCenterRate != 0 per-call, maxCenterRateDeviationBps
!= 0 globally); 0 preserves prior behavior. Adds the MANAGER setter, the
centerRate() getter, and doc-faithful counter-tests (real slippage/target
floors, not zeros). Storage is append-only (upgrade-safe).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@razww
razww requested a review from qingyang-lista August 5, 2026 09:20
v0.1.1 false-positived V3DexAdapter's __gap consumption (it read the __gap
array shrink 45->44 as a type change at the gap slot). v0.1.2 is __gap-aware:
the standard pattern — shrink __gap and place the new variable in the freed
slot — validates as UPGRADE SAFE, so the committed maxCenterRateDeviationBps
layout passes without contorting the storage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@razww
razww merged commit 4499ac2 into audit/v3-lp-fixes Aug 6, 2026
8 checks 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