Skip to content

feat(yield-vault): implement guards and tests (#732–#735) - #871

Open
damilareojetunde wants to merge 9 commits into
BCPathway:mainfrom
damilareojetunde:feat/yield-vault-guards-732-735
Open

feat(yield-vault): implement guards and tests (#732–#735)#871
damilareojetunde wants to merge 9 commits into
BCPathway:mainfrom
damilareojetunde:feat/yield-vault-guards-732-735

Conversation

@damilareojetunde

@damilareojetunde damilareojetunde commented Aug 31, 2026

Copy link
Copy Markdown

feat(yield-vault): Implement guard layers and tests (#732#735)

Epic: Yield-Bearing Fee Vaults

Closes #732
Closes #733
Closes #734
Closes #735

This PR implements three guard functions and comprehensive tests for the yield_vault contract, closing issues #732, #733, #734, and #735.


Changes

#732rate_limit_deposits integration

  • Added a rate_limit_deposits guard that hooks into the existing bc_forge_rate_limit module.
  • Enforces a configurable per-address and global deposit rate limit using the "deposit" operation type.
  • Prevents whale manipulation by rejecting deposits that exceed the configured threshold.
  • Returns VaultError::RateLimited when the limit is hit.
  • If no rate limit is configured, deposits pass unchecked (backward compatible).

#733pause_vault_deposits function

  • Added ensure_not_paused guard to the deposit function that checks bc_forge_lifecycle::is_paused.
  • Deposits revert with VaultError::ContractPaused when the vault is paused.
  • Withdrawals are NOT affected — users can always exit, even during a pause.
  • Pauser-role addresses can pause/unpause via the existing bc_forge_lifecycle module.

#734rescue_stuck_funds function

  • Added rescue_tokens(admin, token, to, amount) — admin-only.
  • Transfers any non-underlying SEP-41 token balance held by the vault to the specified recipient.
  • Reverts with VaultError::CannotRescueUnderlying if the requested token matches the vault's core underlying asset (those tokens belong to depositors).
  • Validates amount > 0.
  • Emits a rescue event for auditability.

#735 — Deposit to mint ratio tests

Comprehensive test coverage verifying the share calculation formula:

Test Scenario
test_deposit_to_mint_ratio_initial_deposit_1_to_1 First deposit bootstraps 1:1
test_deposit_to_mint_ratio_secondary_deposit_matches_formula shares = assets × total_shares / total_assets
test_deposit_to_mint_ratio_after_reward_distribution Post-reward: secondary deposit yields fewer shares per token
test_deposit_to_mint_ratio_inexact_division_floors Floor division rounds down in protocol's favour
test_deposit_to_mint_ratio_three_users_pro_rata Multi-user pro-rata share allocation

Additional Changes

  • Removed yield_vault from workspace exclude in root Cargo.toml so it compiles as a workspace member.
  • Updated yield_vault/Cargo.toml with dependencies: bc-forge-admin, bc-forge-lifecycle, bc-forge-rate-limit, bc-forge-ttl.
  • Added cdylib crate type for WASM deployment.
  • Added events.rs module with structured event emission for init, deposit, withdraw, and rescue.

Test Coverage

Guard Happy Path Error Path
Rate limit (#732) Deposits within limit succeed Deposit exceeding limit reverts RateLimited
Pause (#733) Withdraw works while paused; deposit resumes after unpause Deposit reverts ContractPaused when paused
Rescue (#734) Non-underlying tokens rescued to recipient Reverts CannotRescueUnderlying for underlying token; reverts for zero/negative amount; non-admin rejected
Deposit ratio (#735) All formula scenarios pass exactly
Slippage min_shares_out / min_tokens_out respected Reverts when slippage exceeded
Edge cases Zero supply, uninitialized, unknown addresses InvalidAmount, InsufficientBalance, NotInitialized

Files Changed

File Description
Cargo.toml Removed yield_vault from workspace exclude
contracts/yield_vault/Cargo.toml Added admin, lifecycle, rate-limit, ttl deps
contracts/yield_vault/src/lib.rs Full vault implementation with 3 guards + rescue_tokens
contracts/yield_vault/src/events.rs Structured event emission (new)
contracts/yield_vault/src/test.rs 30+ unit tests covering all issues

@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@damilareojetunde Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

samjay8 and others added 6 commits August 31, 2026 10:34
…y#735)

Add three guard layers and comprehensive tests to the yield vault contract:

- BCPathway#732: rate_limit_deposits — integrates with bc_forge_rate_limit module
  to throttle deposit frequency and prevent whale manipulation.
- BCPathway#733: pause_vault_deposits — adds require_not_paused to deposit while
  keeping withdraw always active so users can exit.
- BCPathway#734: rescue_tokens — admin-only function to recover non-underlying
  tokens; reverts if the requested token matches the vault's core
  underlying asset.
- BCPathway#735: deposit-to-mint ratio tests — verifies share calculation across
  initial deposits, secondary deposits, reward distributions, and
  multi-user pro-rata scenarios.

Also removes yield_vault from workspace exclude list and adds dependencies
on bc-forge-admin, bc-forge-lifecycle, bc-forge-rate-limit, and bc-forge-ttl.

Co-Authored-By: Samuel Ojetunde <samjay8@users.noreply.github.com>
Apply rustfmt formatting to events.rs, lib.rs, and test.rs to pass the
CI formatting check.

Co-Authored-By: Samuel Ojetunde <samjay8@users.noreply.github.com>
Co-Authored-By: Samuel Ojetunde <samjay8@users.noreply.github.com>
…ignature)

Co-Authored-By: Samuel Ojetunde <samjay8@users.noreply.github.com>
- Remove & from numeric literals in assert_eq! (E0277: can't compare i128 with &{integer})
- Fix tuple destructuring: setup_and_fund returns 5 values, setup returns 4 (E0308: mismatched types)

Co-Authored-By: Samuel Ojetunde <samjay8@users.noreply.github.com>
- Soroban client auto-unwraps Result return types, so vault.supply(),
  vault.underlying_token(), vault.share_balance() return values directly
- Remove unused import soroban_sdk::testutils::Ledger
- Prefix unused variable underlying with underscore

Co-Authored-By: Samuel Ojetunde <samjay8@users.noreply.github.com>
@freebuff-web
freebuff-web Bot force-pushed the feat/yield-vault-guards-732-735 branch from e32e771 to da91224 Compare August 31, 2026 10:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants