Description
INVARIANTS.md states the core vault property: VaultMeta.balance is always >= 0 and <= i128::MAX, and lists deduct / batch_deduct among the balance-mutating functions. The existing suite (contracts/vault/src/test.rs, test_idempotency.rs) exercises specific cases, but there are no randomized property/invariant tests that assert the accounting holds across arbitrary input sequences. This issue adds property-based tests that pin the documented invariants for the deduction path.
The contract logic to validate lives in deduct (contracts/vault/src/lib.rs:637) and batch_deduct (:725), where the batch performs a full validation pass — accumulating total and running with checked_add/checked_sub (:766–:767) — before any transfer.
Requirements and context
Functional (properties to assert)
- Over any sequence of valid
deduct calls, the sum of successfully deducted amounts never exceeds the initial deposited balance, and balance() is never negative.
- For
batch_deduct over a random Vec<DeductItem> (within MAX_BATCH_SIZE = 50), the final balance equals initial_balance - sum(item.amount) when the batch succeeds, and equals the unchanged initial balance when any item fails validation (atomicity — no partial application).
- A
batch_deduct whose cumulative total exceeds the balance returns VaultError::InsufficientBalance and mutates nothing.
i128 boundary inputs (amounts near i128::MAX, balances near the cap) never panic the host outside the documented Overflow error path.
Non-functional / repo conventions
- This repo currently has no property-testing dependency. Add
proptest as a [dev-dependencies] entry in contracts/vault/Cargo.toml (Soroban unit tests run on the host target, so proptest is fine for #[cfg(test)]). Keep generated case counts modest so cargo test and cargo tarpaulin stay within the 120s per-binary timeout configured in tarpaulin.toml.
- Tests must use the existing test harness style (the
soroban_sdk Env, registered token contract, and helpers already used in contracts/vault/src/test.rs).
- New tests must not lower workspace coverage below the 95% gate.
Acceptance criteria
Suggested execution
1. Fork the repo and create a branch
git checkout -b test/vault-deduct-invariants
2. Implement changes
contracts/vault/Cargo.toml — add proptest under [dev-dependencies].
contracts/vault/src/lib.rs — register the new test module.
3. Write/extend tests in contracts/vault/src/test_invariants.rs:
- a
proptest! generating random valid deduction sequences asserting the sum/non-negative properties;
- a
proptest! generating random Vec<DeductItem> (bounded by MAX_BATCH_SIZE) asserting exact post-balance on success and unchanged balance on validation failure;
- explicit boundary cases at
i128::MAX.
4. Test and commit
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --workspace
./scripts/check-wasm-size.sh
./scripts/coverage.sh
Example commit message
test(vault): add proptest invariants for deduct and batch_deduct accounting
Guidelines
- Coverage must stay >= 95% (
scripts/coverage.sh), CI-enforced via .github/workflows/coverage.yml.
- Keep
INVARIANTS.md accurate — if a property test reveals a doc gap, update the document and reference the new tests.
- Keep generated case counts bounded so coverage runs inside the tarpaulin 120s timeout.
- Timeframe: 96 hours.
Description
INVARIANTS.mdstates the core vault property:VaultMeta.balanceis always>= 0and<= i128::MAX, and listsdeduct/batch_deductamong the balance-mutating functions. The existing suite (contracts/vault/src/test.rs,test_idempotency.rs) exercises specific cases, but there are no randomized property/invariant tests that assert the accounting holds across arbitrary input sequences. This issue adds property-based tests that pin the documented invariants for the deduction path.The contract logic to validate lives in
deduct(contracts/vault/src/lib.rs:637) andbatch_deduct(:725), where the batch performs a full validation pass — accumulatingtotalandrunningwithchecked_add/checked_sub(:766–:767) — before any transfer.Requirements and context
Functional (properties to assert)
deductcalls, the sum of successfully deducted amounts never exceeds the initial deposited balance, andbalance()is never negative.batch_deductover a randomVec<DeductItem>(withinMAX_BATCH_SIZE = 50), the final balance equalsinitial_balance - sum(item.amount)when the batch succeeds, and equals the unchanged initial balance when any item fails validation (atomicity — no partial application).batch_deductwhose cumulative total exceeds the balance returnsVaultError::InsufficientBalanceand mutates nothing.i128boundary inputs (amounts neari128::MAX, balances near the cap) never panic the host outside the documentedOverflowerror path.Non-functional / repo conventions
proptestas a[dev-dependencies]entry incontracts/vault/Cargo.toml(Soroban unit tests run on the host target, soproptestis fine for#[cfg(test)]). Keep generated case counts modest socargo testandcargo tarpaulinstay within the 120s per-binary timeout configured intarpaulin.toml.soroban_sdkEnv, registered token contract, and helpers already used incontracts/vault/src/test.rs).Acceptance criteria
proptestadded tocontracts/vault/Cargo.tomldev-dependencies; build stays green.contracts/vault/src/test_invariants.rsmodule (registered with#[cfg(test)] mod test_invariants;inlib.rs) holds the property tests.batch_deductis all-or-nothing — failure leaves balance exactly unchanged.i128boundary inputs are covered and only ever surfaceVaultError::Overflow/InsufficientBalance, never an unhandled host panic.cargo test --workspacepasses;./scripts/coverage.shstays >= 95%.Suggested execution
1. Fork the repo and create a branch
2. Implement changes
contracts/vault/Cargo.toml— addproptestunder[dev-dependencies].contracts/vault/src/lib.rs— register the new test module.3. Write/extend tests in
contracts/vault/src/test_invariants.rs:proptest!generating random valid deduction sequences asserting the sum/non-negative properties;proptest!generating randomVec<DeductItem>(bounded byMAX_BATCH_SIZE) asserting exact post-balance on success and unchanged balance on validation failure;i128::MAX.4. Test and commit
cargo fmt --all -- --check cargo clippy --all-targets --all-features -- -D warnings cargo test --workspace ./scripts/check-wasm-size.sh ./scripts/coverage.shExample commit message
Guidelines
scripts/coverage.sh), CI-enforced via.github/workflows/coverage.yml.INVARIANTS.mdaccurate — if a property test reveals a doc gap, update the document and reference the new tests.