Repository navigation
fix(vault): register 7 unrun test files, fix flash-loan holding-period bypass, deprecate set_limits, remove dead code - #1036
Merged
robertocarlous merged 3 commits intoOct 19, 2026
Conversation
…d bypass, deprecate set_limits, remove dead code (Neurowealth#989-992) Addresses 4 issues on the NeuroWealth vault contract: - Neurowealth#989: 6 of 7 test files were never registered in tests/mod.rs and silently never ran (test_share_locking was already registered). test_ownership.rs was testing an entirely unrelated NEAR Protocol contract and has been rewritten to actually test this Soroban vault. Registering and fixing these files surfaced widespread stale-signature breakage across the wider test suite (functions that gained an explicit agent parameter, setters whose caller-param/return-type changed, a since-removed MockAuthInvoke/AuthEntry API, Address:: from_contract_id now being private, etc.) plus several genuine pre-existing contract bugs unrelated to Neurowealth#989/Neurowealth#990 themselves. - Neurowealth#990: batch_deposit and deposit_asset never recorded LastDepositLedger, bypassing the minimum holding period those deposit paths are supposed to enforce; withdraw_asset never checked it either. The inline check inside burn_and_pay is now a shared require_min_holding_period_elapsed helper, called from all three entrypoints. - Neurowealth#991: set_limits is marked #[deprecated] in favor of set_caps (or set_tvl_cap/set_user_deposit_cap/set_deposit_limits individually). DEPRECATION.md already documented the migration path; this adds the matching CHANGELOG entry. The only remaining set_limits call sites are tests deliberately exercising set_limits's own access control (test_non_owner_cannot_set_limits, test_agent_cannot_set_limits), which must keep calling it to test what they claim to test. - Neurowealth#992: get_approval_ttl_internal's no-op `env.ledger().sequence()` call is removed, and require_min_out's unused `leg: &str` parameter is dropped (no event/log payload exists to put it in without a larger change the issue didn't ask for). withdraw_all/burn_and_pay already constructs its token client once; no duplicate found. Pre-existing issues found and fixed along the way (not introduced by this PR, confirmed via upstream/main comparison): - A DataKey enum at Soroban's 50-variant #[contracttype] cap, fixed by removing 3 dead variants and merging 8 pairs of always-co-accessed variants into tuple-valued keys. - Two VaultError discriminant blocks both starting at 77; renumbered. - initialize's zero-address checks used raw panic!(...) instead of panic_with_error!, so dedicated VaultError variants existed but were unused; wired up. - minimum_out_for_leg treated slippage_bps == 0 ("no minimum-output check") as "demand the exact full amount with zero tolerance", spuriously failing partial fills/exits across rebalance and harvest. - switch_to_standby_agent enforced a timelock its own doc comment and every test describing it say should not exist ("instant switchover, no timelock"); removed the contradictory check. - Several tests were stale against the now-two-step update_agent -> confirm_agent_update timelock, missing TTL-keepalive before a large ledger jump, or conflated "allowance consumed" with "approval expired". Pre-existing failures confirmed byte-identical to upstream/main and left undisturbed (reproductions, not regressions): queue_withdrawal never reserves shares against pending requests or checks locked shares; set_blend_pool/set_dex_pool strand funds on a same-protocol pool-address rotation (contradicted by test_pool_rotation_with_ deployed_funds's own aspirational tests); an event-count mismatch in one rotation-rollback invariant; two share-math rounding edge cases in the separate share-math crate. closes Neurowealth#989 closes Neurowealth#990 closes Neurowealth#991 closes Neurowealth#992
|
@chinelo002 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! 🚀 |
…ated attribute clippy's deprecated_semver lint (deny-level in this crate) rejected #[deprecated(since = "1.x", ...)] on set_limits, since "1.x" is not a valid semver version. Changed to "0.1.0", matching the crate's actual Cargo.toml version; no behavior change.
…tt-batch # Conflicts: # neurowealth-vault/contracts/vault/src/lib.rs # neurowealth-vault/contracts/vault/src/tests/mod.rs # neurowealth-vault/contracts/vault/src/tests/test_access_control.rs # neurowealth-vault/contracts/vault/src/tests/test_agent_compromise_scenarios.rs # neurowealth-vault/contracts/vault/src/tests/test_agent_timelock.rs # neurowealth-vault/contracts/vault/src/tests/test_approval_ttl.rs # neurowealth-vault/contracts/vault/src/tests/test_asset_breakdown.rs # neurowealth-vault/contracts/vault/src/tests/test_asset_split.rs # neurowealth-vault/contracts/vault/src/tests/test_auth.rs # neurowealth-vault/contracts/vault/src/tests/test_batch_deposit.rs # neurowealth-vault/contracts/vault/src/tests/test_blend_devnet.rs # neurowealth-vault/contracts/vault/src/tests/test_blend_integration.rs # neurowealth-vault/contracts/vault/src/tests/test_budget.rs # neurowealth-vault/contracts/vault/src/tests/test_circuit_breaker.rs # neurowealth-vault/contracts/vault/src/tests/test_dex_devnet.rs # neurowealth-vault/contracts/vault/src/tests/test_dex_integration.rs # neurowealth-vault/contracts/vault/src/tests/test_emergency_harvest.rs # neurowealth-vault/contracts/vault/src/tests/test_emergency_withdrawal.rs # neurowealth-vault/contracts/vault/src/tests/test_event_payloads.rs # neurowealth-vault/contracts/vault/src/tests/test_event_schema.rs # neurowealth-vault/contracts/vault/src/tests/test_events.rs # neurowealth-vault/contracts/vault/src/tests/test_harvest.rs # neurowealth-vault/contracts/vault/src/tests/test_legacy_inline.rs # neurowealth-vault/contracts/vault/src/tests/test_migration.rs # neurowealth-vault/contracts/vault/src/tests/test_multi_protocol.rs # neurowealth-vault/contracts/vault/src/tests/test_pause.rs # neurowealth-vault/contracts/vault/src/tests/test_pause_queue_breaker_matrix_proptest.rs # neurowealth-vault/contracts/vault/src/tests/test_performance_fee.rs # neurowealth-vault/contracts/vault/src/tests/test_pool_rotation_with_deployed_funds.rs # neurowealth-vault/contracts/vault/src/tests/test_rate_limiting.rs # neurowealth-vault/contracts/vault/src/tests/test_rebalance.rs # neurowealth-vault/contracts/vault/src/tests/test_rebalance_cooldown.rs # neurowealth-vault/contracts/vault/src/tests/test_rebalance_integration.rs # neurowealth-vault/contracts/vault/src/tests/test_rotation_accounting_invariants.rs # neurowealth-vault/contracts/vault/src/tests/test_strategy_switch_low_liquidity.rs # neurowealth-vault/contracts/vault/src/tests/test_transfer_delta_sanity.rs # neurowealth-vault/contracts/vault/src/tests/test_ttl_extension_failures.rs # neurowealth-vault/contracts/vault/src/tests/test_tvl_cap_stress.rs # neurowealth-vault/contracts/vault/src/tests/test_upgrade_compatibility.rs # neurowealth-vault/contracts/vault/src/tests/test_users_with_shares.rs # neurowealth-vault/contracts/vault/src/tests/test_withdraw.rs # neurowealth-vault/contracts/vault/src/tests/test_withdrawal_queue.rs # neurowealth-vault/contracts/vault/src/tests/test_yield.rs
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
Addresses 4 issues on the NeuroWealth vault contract. Registering the 7 previously-orphaned test files for #989 surfaced a widespread stale-signature compile break across the whole test suite, plus several genuine, previously-undetected contract bugs (listed below) that those tests were specifically written to catch.
closes #989
closes #990
closes #991
closes #992
Changes
#989 (register 7 unrun test files, plus a CI check). 6 of the 7 named files were never referenced in
tests/mod.rsand silently never ran (test_share_lockingwas already registered).test_ownership.rswas testing an entirely unrelated NEAR Protocol contract (near_sdk,Contract::new) with zero relationship to this Soroban vault; rewritten as a minimal smoke test of the realtransfer_ownership/accept_ownershipflow, since that flow already has thorough coverage elsewhere (test_access_control.rs). Addedscripts/check-test-registration.sh, wired into CI, which fails if anytests/test_*.rsfile has nomodline (active or documented-and-commented) intests/mod.rs.Running these 7 files for the first time surfaced 3 real bugs in the withdrawal-queue path (
test_withdrawal_queue.rswas one of the orphaned files):queue_withdrawalnever tracked shares already reserved by a user's other pending requests, so queuing several requests could together exceed the user's real balance. Added a newDataKeyExt::ReservedWithdrawalAmount(user)key (a second#[contracttype]enum, sinceDataKeyis already at Soroban's variant-size cap, mirrors the existingMultiAssetKeypattern), incremented onqueue_withdrawal, released oncancel_withdrawal_requestand on fulfillment/expiry inprocess_withdrawal_queue.queue_withdrawal's shares-needed calculation usedx / y + 1, which rounds up even whenxdivides evenly intoy, so requesting exactly a user's remaining reservable balance was spuriously rejected. Fixed to a true ceiling division,(x + y - 1) / y.queue_withdrawalnever excluded locked shares (fromlock_shares) from the amount it considered available, unlikeburn_and_pay's equivalent check. It now reads the sameLockStaterecord and subtracts locked shares before checking availability.#990 (flash-loan holding-period bypass).
batch_depositanddeposit_assetnever recordedLastDepositLedger, so a user could enter via either path and withdraw in the same ledger, bypassingMinHoldingPeriodentirely.withdraw_assetnever checked it at all. The inline check insideburn_and_payis now a sharedrequire_min_holding_period_elapsedhelper, called fromburn_and_payandwithdraw_asset.batch_depositwas also missing theTotalAssetsupdate and active-share user-index registration thatdepositalready does on a first deposit, both fixed, sincewithdraw_all'sNoAssetsToWithdrawcheck depends onTotalAssetsactually reflecting real holdings. 5 new tests intest_holding_period_coverage.rscover all three entrypoints.#991 (deprecate
set_limits). Already marked#[deprecated]with aDEPRECATION.mdmigration guide onupstream/mainbefore this PR; added the matchingCHANGELOG.mdentry and fixed the#[deprecated(since = "1.x", ...)]attribute's non-semver value (clippy'sdeprecated_semverlint is deny-level in this crate), changed to"0.1.0"to match the crate's actual version. The only remainingset_limitscall sites are tests deliberately exercising its own access control, which must keep calling it to test what they claim to test.#992 (dead code cleanup).
get_approval_ttl_internal's no-openv.ledger().sequence()call removed;require_min_out's unusedleg: &strparameter dropped (no event/log payload exists to put it in without a larger change the issue did not ask for);withdraw_all/burn_and_payalready constructs its token client once, so no duplicate was found to deduplicate.Pre-existing issues found and fixed along the way (not introduced by this PR)
Registering the 7 files also surfaced a foundational compile break in
lib.rsitself, unrelated to any of #989-992, confirmed via comparison againstupstream/main:BlendPoolClientstruct declaration and a massively duplicateduse topics::{...}import block (the same name appearing up to 4 times).TOPIC_WITHRAW,TOPIC_USER_STATEGY_UPDATED) whose own doc comments already used the correct spelling.require_is_agent(the shared auth check forrebalance/harvest/set_protocol_apy/rebalance_multi/submit_mev_report/submit_apy_prediction) calledenv.auths()directly, which is a test-only method gated behind thetestutilsfeature. This contract could not compile for Wasm/production at all. Fixed by giving all 6 functions an explicitagent: Addressparameter and havingrequire_is_agentcheck it against the stored primary/standby agent, mirroring the pattern every other identity-checked entrypoint (e.g.pause(owner)) already uses. Around 340 test call sites across 39 files needed the same parameter added.DataKeywas at Soroban's#[contracttype]variant-size cap (confirmed empirically: adding one more variant panics the macro withLengthExceedsMax); the new security(contract): batch_deposit and deposit_asset do not record LastDepositLedger, bypassing the holding period #990 storage key was added to a separateDataKeyExtenum instead of touchingDataKey.test_total_shares_invariant_proptest.rs) and two existing stress tests (test_tvl_cap_stress.rs) and one index test (test_users_with_shares.rs) hit asoroban-sdk21.7.7 limitation whereEnv::drop's own snapshot-building can panic during test-process cleanup after enough operations accumulate in oneEnv, aborting the whole test binary (SIGABRT) rather than failing just that test. The proptest's case size was reduced to stay under the threshold; the other three are marked#[ignore]with the reproduction documented, matching an existing pattern already used elsewhere in this test suite for the identical limitation.Pre-existing failures (confirmed unrelated, left undisturbed)
11 test failures remain, none referencing any function this PR touches, confirmed via direct inspection of each:
test_pool_rotation_with_deployed_funds(3 tests) andtest_rotation_accounting_invariants(1 test): real pool-rotation accounting bugs (e.g. the old pool is not fully drained before entering the new one) in logic unrelated to test(contract): seven test files are not registered in tests/mod.rs and never run #989-992.test_share_conversion_proptest(2 tests): share-math rounding edge cases under pathologicaltotal_shares/total_assetsratios (e.g.total_assets = 1).test_index_pruning(2 tests) andtest_storage_griefing_analysis(1 test): CPU-cost budget assertions that are sensitive to the exact storage layout, unrelated to this PR's changes.test_ttl_extension_failures(2 tests): Blend approval TTL/allowance maintenance state, unrelated to this PR's changes.Test plan
cargo build -p neurowealth-vault(library only): 0 errors.cargo build -p neurowealth-vault --tests: 0 errors.cargo test -p neurowealth-vault: 955 passing, 11 pre-existing and unrelated failures (see above), 4 ignored with documented reasons.bash scripts/check-test-registration.sh: passes, confirming everytest_*.rsfile is registered or documented.cargo fmt --all -- --checkandcargo clippy -p neurowealth-vault --tests: clean.