Skip to content

refactor: name every precondition as a guard - #273

Open
hpmaxi wants to merge 13 commits into
refactor/namesfrom
refactor/guards
Open

hpmaxi wants to merge 13 commits into
refactor/namesfrom
refactor/guards

Conversation

@hpmaxi

@hpmaxi hpmaxi commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #324

The vault, the share token, the oracle and the compliance contract checked most preconditions inline, often halfway down a function, so a reader had to read the whole body to learn when a call is refused. A few vault totals still used plain addition or saturating subtraction, and the oracle read its configuration with a bare unwrap.

Now each precondition is a function in the contract's guards module, named for the condition it checks. Each entrypoint calls its guards first, in the same order as before, and then does its work, so every refused call fails with the same error. The remaining totals use checked math with named errors, and a missing oracle configuration fails with NotInitialized.

Changes

  • The vault, the share token, the oracle and the compliance contract check every precondition through a named guard
  • The token's and the oracle's entrypoints run their guards before they extend their instance
  • The old refuse_*, require_* and check_* helpers are guards now; the lock policy still decides a holder's standing, and the guards call it
  • Each guard has a unit test for a case it accepts and a case it refuses
  • The deposit escrow and the settlement counters fail with AmountTooLarge instead of overflowing
  • The wind-down snapshot and the economic supply fail with AccountingMismatch instead of saturating, and deposited capital fails on overflow
  • A wind-down round's credit and a holder's wind-down payout fail with AccountingMismatch if they would go below zero
  • A missing oracle configuration fails with NotInitialized instead of trapping
  • Four vault test names say holder instead of controller

Deviations

  • Deposited capital can be negative once exits are priced above the capital it counts, so it refuses only overflow, not a value below zero.
  • The token's and the oracle's finish_setup check that setup is open before the hand-over check, as the vault does. Every state fails with the same error as before.
  • Checks that need a computed value (coverage, a round's supply, an entitlement) call their guard where the value exists, not at the top.

Acceptance criteria

  • No entrypoint in the vault, the share token, the oracle or the compliance contract has an inline if … { panic_with_error!(…) } precondition left
  • Each guard has a unit test: it passes when its condition holds and refuses with its error when it does not
  • The listed totals fail with AmountTooLarge or AccountingMismatch instead of overflowing or saturating
  • A missing oracle configuration fails with a named error
  • Every existing test passes unchanged, and the harness passes on a local network

Test plan

Automated tests

  1. cargo test --locked: 661 passed (426 vault, 96 oracle, 75 token, 33 compliance, 6 identity verifier, 19 timelock, 6 storage). The 583 tests at the base pass unchanged; four of them are renamed.
  2. cargo clippy --locked --all-targets -- -D warnings on the eight crates, and on the vault with --features short_wind_down: clean.
  3. The Wasm upgrade tests (cargo test -p async-vault -p nav-oracle --features upgrade_wasm with_wasm, after the builds in docs/TESTING.md) pass against the new token and oracle builds.
  4. CI runs the harness deploy, happy path and guards on a local network.

Manual verification

  1. Start a local network: docker run --rm -d -p 8000:8000 --name stellar-local stellar/quickstart --local --enable core,rpc.
  2. Run stellar contract build, then CARGO_TARGET_DIR=target/short-wind-down stellar contract build --package async-vault --features short_wind_down.
  3. Run npm run build:clients, then HARNESS_NETWORK=local npm run deploy -w scripts/harness.
  4. Run test:happy-path, test:guards and test:wind-down with npm run <script> -w scripts/harness.
  5. You should see 24, 48 and 6 tests pass. The vault's Wasm is 71,553 bytes (was 71,793), the token's 42,464 (was 42,444), the oracle's 33,215 (was 33,079) and the compliance contract's 24,536 (was 24,514). Only the oracle's contract interface changes, by one error.

Breaking changes

Fresh deployments only.

  • nav_oracle: a new error, NotInitialized = 3026, for a missing configuration. A constructed oracle always has one, so no call reaches it today.
  • async_vault: on states no valid call sequence reaches, a few totals now fail with AmountTooLarge or AccountingMismatch where they trapped, returned a saturated value or produced a negative payout.

No entrypoint, argument, event or other error changes. The console needs no change.

Checklist

  • Self-reviewed my own diff
  • Tests added or updated
  • Docs updated (if applicable)
  • No unrelated changes bundled in

Screenshots

None.

@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
strata-vault-kit-app Ready Ready Preview Oct 23, 2026 3:32pm UTC

Request Review

@hpmaxi
hpmaxi marked this pull request as ready for review October 19, 2026 23:36

This branch was successfully deployed

1 active deployment
Preview — 394677c0 Deployed Oct 23, 2026 by vercel[bot]
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.

2 participants