feat: emergency pause, multi-pool router, loop-cap docs, proptest invariants#206
Open
obanai9 wants to merge 1 commit into
Open
feat: emergency pause, multi-pool router, loop-cap docs, proptest invariants#206obanai9 wants to merge 1 commit into
obanai9 wants to merge 1 commit into
Conversation
…iants Implements four issues in one pass: ## Dgetsylver#45 – D4: Emergency pause admin role (blend_leverage) - Added `Admin` and `Paused` keys to `DataKey` in `storage.rs`. - Added `set_admin`, `get_admin`, `set_paused`, `is_paused` helpers in `storage.rs`. - `__constructor` now accepts a ninth init arg (`admin: Address`) and persists it. - New public methods on `BlendLeverageStrategy`: - `pause()` – admin-gated; blocks deposits and harvest, emits `(pause, state) → true`. - `unpause()` – admin-gated; resumes normal operation, emits `(pause, state) → false`. - `paused()` – read-only view returning current pause state. - `get_admin()` – read-only view returning the admin address. - `deposit()` and `harvest()` return `StrategyError::NotAuthorized` immediately when paused; `withdraw()` is unaffected, preserving user access to funds at all times. Closes Dgetsylver#45 ## Dgetsylver#48 – D7: Multi-pool / multi-asset router contract - New crate `contracts/strategies/router/` (cdylib, soroban-sdk 25.3.0). - `PoolRouter` contract (`src/lib.rs`): - Maintains a registry of strategy addresses with net-APY snapshots (basis points). - `deposit(amount, from, preferred_strategy?)` – pulls asset from user, queries the router's existing balance in the chosen strategy for accurate share pricing, deposits via `StrategyClient`, and issues proportional virtual shares to the user. - Deterministic pool selection: iterates the registry and picks the highest `net_apy_bps`; ties broken by insertion order for stability. - User override: if `preferred_strategy` is `Some` and registered, it is used directly. - `withdraw(amount, from, to)` – burns virtual shares proportionally; strategy sends equity directly to `to` without routing through the router. - `balance(from)` – returns `user_vs / total_vs × strategy.balance(router)`. - Admin methods: `add_strategy`, `remove_strategy`, `update_apy`, `set_admin`. - View helpers: `best_strategy()`, `strategies()`, `admin()`, `asset()`. - Events: `(RouterDeposit, from)` and `(RouterWithdraw, from)`. - `src/storage.rs`: `StrategyEntry`, `UserPosition`, per-strategy virtual-share tracking, per-user position persistence with 120-day TTL extension. - `README.md`: architecture description, virtual-share accounting example, migration path for existing single-pool depositors (withdraw + re-deposit flow), routing algorithm docs. Closes Dgetsylver#48 ## Dgetsylver#49 – D8: Document (and name) the 20-loop hard cap (blend_leverage) - Added `MAX_LOOPS: u32 = 20` constant to `constants.rs` with a full rationale comment covering (1) Soroban instruction budget, (2) diminishing marginal returns, and (3) the distinction between the safety ceiling and the operator-tunable `target_loops`. - `leverage.rs`: `loop_step_count` now uses `MAX_LOOPS + 1` instead of the bare literal `21`, and carries an expanded doc-comment referencing all three reasons plus the README. - `README.md` (new): module-level documentation for the blend_leverage strategy including a loop-progression table, the full loop-cap rationale, init-arg reference, and a summary of key invariants. Closes Dgetsylver#49 ## Dgetsylver#50 – D9: Property / invariant tests for leverage math (blend_leverage) - Added `proptest = "1"` to `[dev-dependencies]` in `Cargo.toml`. - New test module `src/test_proptest.rs` with `ProptestConfig::with_cases(1_000)`: 1. `inv_total_supply_gte_total_borrow` – supply ≥ borrow for any (initial, c, n). 2. `inv_net_equity_equals_initial` – supply − borrow = initial always. 3. `inv_leverage_bounded_by_geometric_series` – supply ≤ initial / (1 − c). 4. `inv_hf_monotone_in_c_factor` – higher c_factor → higher or equal HF for fixed b/d positions and rates. 5. `inv_compute_step_supply_equals_balance` – supply leg always equals `balance`. 6. `inv_compute_step_final_borrow_is_zero` – final step borrow is exactly 0. 7. `inv_no_panic_on_extreme_inputs` – `compute_totals` does not panic on large i128 values; saturating `checked_mul` keeps outputs non-negative. - Registered the module in `lib.rs` under `#[cfg(test)]`. Closes Dgetsylver#50
|
@obanai9 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! 🚀 |
Collaborator
|
Hey @obanai9 , thanks for your contribution ! Could you please make a PR per issue ? |
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.
Summary
Implements four issues in a single PR, all changes confined to
contracts/strategies/:#45 – D4: Emergency pause admin role
storage.rs: addedAdminandPausedkeys toDataKey; new helpersset_admin,get_admin,set_paused,is_paused.lib.rs: ninth constructor argadmin: Address; new public methodspause(),unpause(),paused(),get_admin().pause()andunpause()are gated by the admin address set at init and emit an on-chain event(pause, state) → bool.deposit()andharvest()returnStrategyError::NotAuthorizedwhen paused;withdraw()is unaffected so users can always exit.#48 – D7: Multi-pool / multi-asset router contract
contracts/strategies/router/(Soroban cdylib).PoolRouterstores a registry of strategy addresses with net-APY snapshots (bps) updated by the admin.deposit(amount, from, preferred_strategy?)— queries the router's pre-deposit balance for accurate share pricing, picks the highest-APY strategy deterministically (or uses user override), issues proportional virtual shares.withdraw(amount, from, to)— burns virtual shares, strategy sends equity directly toto.balance(from)— returnsuser_vs / total_vs × strategy.balance(router).add_strategy,remove_strategy,update_apy,set_admin.README.mdcovers architecture, virtual-share accounting, routing algorithm, and migration path for existing single-pool depositors.#49 – D8: Document (and name) the 20-loop hard cap
constants.rs: newMAX_LOOPS: u32 = 20with a full rationale comment (Soroban instruction budget, diminishing returns, safety-ceiling vs. operator knob).leverage.rs:loop_step_countusesMAX_LOOPS + 1instead of bare21; doc-comment references all three reasons.README.md(new): module-level strategy documentation including a loop-progression table, full loop-cap rationale, init-arg reference, and key-invariants summary.#50 – D9: Property / invariant tests for leverage math
Cargo.toml: addedproptest = "1"to dev-dependencies.src/test_proptest.rswithProptestConfig::with_cases(1_000)— seven invariants:total_supply >= total_borrowtotal_supply - total_borrow == initial(net equity)total_supply <= initial / (1 − c)(geometric-series bound)c_factorcompute_stepsupply leg always equalsbalancecompute_stepfinal borrow is exactly 0checked_mul)Test plan
cargo test -p blend_leverage_strategy— existing unit tests pass; proptest runs 1 000 cases per property.cargo check -p blend_leverage_router— router contract compiles without errors.BlendLeverageStrategy::pause()blocksdeposit()andharvest();withdraw()succeeds.PoolRouter::depositroutes to highest-APY strategy; user override selects preferred pool.Closes #45
Closes #48
Closes #49
Closes #50