Skip to content

feat(interfaces): consolidate and standardize contract error types wi… - #268

Merged
Cjay-Cyber-2 merged 5 commits into
ASTROIDX556:mainfrom
Aisha000-0:feat/interfaces-consolidate-error-types
Oct 7, 2026
Merged

Cjay-Cyber-2 merged 5 commits into
ASTROIDX556:mainfrom
Aisha000-0:feat/interfaces-consolidate-error-types

Conversation

@Aisha000-0

@Aisha000-0 Aisha000-0 commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary & Motivation

The astroid-interfaces crate is the contract interface definition layer for the Astroid protocol: every member contract (registry, wallet, multisig, proposal, treasury, budget, policy, escrow) and every client SDK (TypeScript SDK, API, dashboard) must interpret failure modes identically. Per the contribution guidelines, every error is a named variant (INSUFFICIENT_FUNDS, POLICY_DENIED, BUDGET_EXCEEDED, …) annotated with #[contracterror], carrying an explicit u32 discriminant that is part of the public ABI.

This PR completes the interfaces-crate side of that contract:

  1. Crate-root export — the canonical error type is now reachable as astroid_interfaces::Error, so SDK consumers and cross-contract clients depend on the interfaces crate alone for the error type used by every trait signature (RegistryInterface, PolicyInterface, BudgetInterface, TelemetryInterface, …).
  2. Serialization guarantees, tested — every variant is verified to serialize on the Soroban wire as ScVal::Error(ScError::Contract(code)) with its exact discriminant, and the generated ScSpecEntry::UdtErrorEnumV0 contract spec (what SDK binding generators consume) is validated for one case per variant with exact names and codes.
  3. Conversion guarantees, tested — lossless Error → soroban_sdk::Error, Error → InvokeError, and inverse TryFrom round-trips across all 50 live variants, plus a fail-closed check proving unknown contract codes never fabricate a variant.

No numeric codes were added, removed, or reordered by this PR — it is ABI-neutral.

What Changed

File Change
interfaces/src/lib.rs pub use crate::errors::Error; — crate-root re-export so use astroid_interfaces::Error; resolves
interfaces/src/errors.rs Test suite expanded 5 → 10 tests, driven by a single ALL_VARIANTS table
contracts/budget/src/test.rs Pre-existing clippy --all-targets lint fix (needless borrow)
contracts/multisig/src/test.rs Pre-existing clippy --all-targets lint fixes (unused variable, needless borrows)

Design Decisions

  • Canonical enum stays in astroid-shared::errors. The PR checklist requires error codes to be added to shared/errors.rs; the interfaces crate re-exports it rather than redefining it. There is exactly one enum in the protocol — zero possibility of ABI drift between what contracts raise and what SDKs decode.
  • Data-driven tests. The ALL_VARIANTS const table feeds the stability, uniqueness, spec-coverage, serialization and conversion tests. A future error variant needs exactly one table entry to be fully covered — reviewer-friendly and regression-proof.
  • Kept in sync with latest main. The branch was rebased onto current main mid-development; the test table now reflects the enum as it stands today: AssetNotWhitelisted = 25 was retired upstream (consolidated into AssetNotAuthorized = 43, slot never reused — asserted by the uniqueness test) and TreasuryPaused = 85 is covered.

Test Plan & Results

The ten tests in interfaces/src/errors.rs:

Test Guarantee
error_discriminants_are_stable Every variant keeps its assigned u32 code (public ABI)
error_discriminants_are_unique No two variants share a code; retired slots are never reused
error_implements_required_traits Copy + Clone + Debug + Eq + PartialEq (#[contracterror] requirement)
error_as_contract_return Usable as Result<_, Error> in contract entrypoints
error_from_discriminant Off-chain consumers can map every u32 code back to its variant
error_spec_xdr_deserializes_with_all_variants Generated spec XDR parses as UdtErrorEnumV0 with exact names + codes for SDK binding generators
error_converts_into_sdk_error_preserving_code Into<soroban_sdk::Error> preserves type + code (what panic_with_error! raises)
error_try_from_sdk_error_round_trips TryFrom<sdk::Error> and TryFrom<InvokeError> round-trip; unknown codes fail closed
error_scval_serialization_round_trips On-wire ScVal::Error(ScError::Contract(code)) representation, decoded back to the exact variant
crate_root_reexport_is_the_canonical_error astroid_interfaces::Error is the identical type every contract returns

Commands run (all passing):

cargo build                                      # workspace builds clean
cargo test -p astroid-interfaces                 # 10/10 pass
cargo test --workspace                           # 13/13 suites, 483 tests pass
cargo fmt --check                                # clean
cargo clippy --workspace --all-targets -- -D warnings   # clean

Acceptance Criteria

  • Comprehensive error enum with explicit u32 discriminants available via interfaces/src/
  • Error types exported cleanly for consumption by all workspace contracts (crate root + errors module)
  • Unit tests verifying error serialization (ScVal wire format + generated spec XDR) and conversion (sdk::Error, InvokeError, TryFrom round-trips)
  • Workspace builds successfully with cargo build

ABI & Compatibility Notes

  • Discriminant values are grouped by domain and unchanged by this PR (1–6, 10–12, 20–27, 30–31, 40–44, 50–53, 61–69, 71–79, 80–85, 90–92; slot 25 permanently retired).
  • Member contracts continue to import astroid_shared::errors::Error — the identical type now also reachable as astroid_interfaces::Error. No contract code paths change.
  • Cross-contract trait signatures in lib.rs are untouched.

Reviewer Notes

  • The only production-facing change is one pub use line; everything else is test coverage.
  • No test snapshots were modified (the multisig test fix preserves the RNG sequence via an underscore-prefixed binding).
  • CI gates this PR must pass: stellar contract build, cargo test --workspace, cargo fmt --check, cargo clippy --workspace -- -D warnings — all verified locally.

Closes #205

…th deterministic codes

- Add errors.rs module to interfaces crate re-exporting canonical Error enum from astroid-shared
- Export Error type cleanly for consumption by all workspace contracts and client SDKs
- Add comprehensive unit tests verifying:
  - Stable u32 discriminants for all error variants (ABI stability)
  - Required trait implementations (Copy, Clone, Debug, Eq, PartialEq)
  - Contract error return type usage
  - Discriminant-to-variant mapping for off-chain SDKs
  - Uniqueness of all discriminants
- Update upgrade.rs to use local Error import from interfaces crate
@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

Link an issue

I check every PR against the issue it solves before merging, and I couldn't find one linked here. Add Closes #<issue number> to the PR description and push (or edit the description) and I'll take a look.

@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

Link an issue

I check every PR against the issue it solves before merging, and I couldn't find one linked here. Add Closes #<issue number> to the PR description and push (or edit the description) and I'll take a look.

1 similar comment
@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

Link an issue

I check every PR against the issue it solves before merging, and I couldn't find one linked here. Add Closes #<issue number> to the PR description and push (or edit the description) and I'll take a look.

…zation test coverage

- Export canonical Error at the crate root so SDKs and contracts can
  use astroid_interfaces::Error directly
- Expand error test suite 5 -> 10: ScVal wire round-trip
  (ScVal::Error(ScError::Contract(code))), generated spec-XDR
  validation, and sdk::Error/InvokeError conversion round-trips across
  all 50 variants, driven by a single ALL_VARIANTS table
- Fix pre-existing clippy --all-targets lints in budget/multisig tests

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

CI checks needed

No checks are visible on this commit. Please make sure this PR triggers the repository's CI and resolve any workflow problems. DripTide will keep watching and review the change when checks pass.

@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

Merge Conflict — Action Needed

This pull request has merge conflicts with the base branch (main).

What to do: update your branch by merging or rebasing against main, resolve any conflicts locally, and push the result.

@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

CI checks needed

No checks are visible on this commit. Please make sure this PR triggers the repository's CI and resolve any workflow problems. DripTide will keep watching and review the change when checks pass.

@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

Merge Conflict — Action Needed

This pull request has merge conflicts with the base branch (main).

What to do: update your branch by merging or rebasing against main, resolve any conflicts locally, and push the result.

@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

CI checks needed

No checks are visible on this commit. Please make sure this PR triggers the repository's CI and resolve any workflow problems. DripTide will keep watching and review the change when checks pass.

@Cjay-Cyber-2

Copy link
Copy Markdown
Contributor

Merge Conflict — Action Needed

This pull request has merge conflicts with the base branch (main).

What to do: update your branch by merging or rebasing against main, resolve any conflicts locally, and push the result.

@Cjay-Cyber-2
Cjay-Cyber-2 merged commit 36568b0 into ASTROIDX556:main Oct 7, 2026
1 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement deterministic error code definitions and validation in astroid-interfaces

2 participants