Skip to content

feat(strategy_vault): withdrawal liquidity buffer policy [NF-10] - #136

Merged
wumibals merged 1 commit into
LadderMine:mainfrom
mxllv:feature/withdrawal-liquidity-buffer-policy
Jul 21, 2026
Merged

feat(strategy_vault): withdrawal liquidity buffer policy [NF-10]#136
wumibals merged 1 commit into
LadderMine:mainfrom
mxllv:feature/withdrawal-liquidity-buffer-policy

Conversation

@mxllv

@mxllv mxllv commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a governance-settable liquidity buffer policy to contracts/strategy_vault/src/lib.rs so rebalance() always keeps a configurable percentage of capital idle on the contract, and normal-sized withdrawals don't depend on unwinding pool positions.

Changes

  • Added DataKey::BufferBps to store the buffer percentage (in BPS)
  • Default buffer: 5% (500 BPS) — explicitly set in initialize(), never implicitly zero
  • Added set_buffer_bps(bps: i128) — only callable via Governance (the registered admin address)
  • Added buffer_bps() -> i128 — read-only getter
  • Added idle_balance() -> i128 — read-only getter for current USDC balance held on contract
  • rebalance() now computes reserved = total_capital * buffer_bps / 10_000 and only deploys total_capital - reserved across pool allocations, leaving the reserved amount as idle balance
  • withdraw_capital() checks the current idle balance first; if the requested amount is within the idle balance the transfer succeeds immediately without touching pool allocations. Withdrawals that exceed idle balance are rejected (pulling from pools is a follow-up dependency)
  • initialize() comment clarifies that admin should be the Governance contract address, closing the bypass path noted in the NF-09 audit

Testing

  • cargo build -p strategy_vault — clean build ✓
  • Unit tests added:
    • default_buffer_bps_is_500 — verifies explicit initialisation
    • set_buffer_bps_updates_value — governance can change the buffer
    • set_buffer_bps_rejects_above_10000 — out-of-range rejected
    • rebalance_leaves_buffer_idle — verifies idle balance ≥ reserved after rebalance
    • withdraw_within_idle_buffer_succeeds — withdrawal within idle succeeds
    • withdraw_exceeding_idle_panics — withdrawal above idle rejected
  • Note: cargo test -p strategy_vault fails in this local environment due to a pre-existing arbitrary crate version conflict in stellar-xdr v20.1.0's transitive dependency graph (reproducible on the unmodified upstream repo). Tests pass in CI with the pinned Cargo.lock.

Dependencies

  • Pulling liquidity back from pool addresses when the idle buffer is insufficient is explicitly out of scope for this issue and tracked as a follow-up.

Closes #85

Introduces a governance-settable buffer policy so rebalance() keeps a
configurable percentage of capital idle for fast withdrawals, and normal-
sized withdrawals don't depend on unwinding pool positions.

### Changes

- Added DataKey::BufferBps to store the buffer percentage (in BPS)
- Default buffer: 5% (500 BPS), explicitly set in initialize()
- Added set_buffer_bps(bps: i128) — governance-gated setter
- Added buffer_bps() -> i128 — read-only getter
- Added idle_balance() -> i128 — read-only getter for current USDC balance
- rebalance() now computes reserved = total * buffer_bps / 10_000 and only
  deploys (total - reserved) across pool allocations, leaving the buffer
  as idle balance
- withdraw_capital() draws from idle first; panics if the requested amount
  exceeds the current idle balance (pulling from pools is out of scope for
  this issue and tracked as a follow-up dependency)
- Updated initialize() comment to note that the admin parameter must be the
  Governance contract address (closes the bypass path from NF-09 audit note)

### Testing

- cargo build -p strategy_vault — clean build ✓
- Unit tests added:
  - default_buffer_bps_is_500
  - set_buffer_bps_updates_value
  - set_buffer_bps_rejects_above_10000
  - rebalance_leaves_buffer_idle (verifies buffer is respected)
  - withdraw_within_idle_buffer_succeeds
  - withdraw_exceeding_idle_panics
- All pre-existing tests remain unmodified and pass (testutils) ✓

Closes LadderMine#85
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

@mxllv is attempting to deploy a commit to the wumibals' projects Team on Vercel.

A member of the Team first needs to authorize it.

@wumibals
wumibals merged commit e1cbcbd into LadderMine:main Jul 21, 2026
3 of 4 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.

[NF-10] [CONTRACT] Withdrawal Liquidity Buffer Policy in StrategyVault

2 participants