Skip to content

fix(contracts): restore compilation across all four contract crates - #1416

Draft
broda-spendy wants to merge 1 commit into
Junirezz:mainfrom
broda-spendy:fix/1303-rust-merge-corruption
Draft

broda-spendy wants to merge 1 commit into
Junirezz:mainfrom
broda-spendy:fix/1303-rust-merge-corruption

Conversation

@broda-spendy

Copy link
Copy Markdown
Contributor

Summary

main does not compile. This restores cargo check --workspace --all-targets --locked to green, and brings the test suite from "never compiled" to 488 of 517 passing.

main:      cargo check --all  ->  error: mismatched closing delimiter (lib.rs:1375)
                                  error: cannot find attribute `contracterror` (bridge-compat)
                                  ... 21 errors in bridge-compat alone
  • cargo fmt --all -- --check — clean (was failing with 14 diffs in bridge-compat).
  • cargo check --workspace --all-targets --locked — clean.
  • cargo test --all — 488 passed, 29 failed (was: 0 compiled).
  • cargo build -p mock-strategy --target wasm32-unknown-unknown --release — clean.

What was broken

Merge damage. A botched merge of two divergent total_assets() bodies (a328ce8, "Merge branch 'main' into hardening") left a validate_price_data(...) call with a dangling ) and two conflicting oracle-price paths interleaved. I restored the main-side version, which is what the surrounding signature and helpers expect. Separately, is_performance_fee_enabled was missing a closing }, which swallowed the following ~1200 lines into the function body — that one predates a328ce8 and is present in both parents. DataKeyExt::Risk(RiskExtKey) was declared twice. bridge-compat used #[contracterror] without importing it, which accounted for all 21 of its errors.

Stale Cargo.lock. 8154517 added bridge-compat to the workspace but never regenerated the lock file, so cargo --locked failed outright in CI. Regenerated.

errors.rs exceeded the error-enum cap. ScSpecUdtErrorEnumV0 allows at most 50 cases. errors.rs declared 53, so #[contracterror] panicked with LengthExceedsMax — and because that panic aborts the derive, every use crate::errors::VaultError downstream failed too, which is what produced the 478-site cascade. Commit 8154517 took it from 50 to 53.

The file's own comments already document the constraint twice, and RescueUnauthorized = 50 notes that the rescue flow deliberately reuses existing codes to stay inside it. I applied the same pattern: the three performance-fee codes reuse existing codes with matching semantics, documented inline.

Numeric codes 1–50 are unchanged, so the integrator contract in docs/api/ERROR_CODE_CATALOG.md is untouched. The catalog documents 1–49 and never mentioned 50–53. Nothing is deployed on any network (every contract ID in deployments/ is empty) and there are no git tags, so there is no live ABI to break. I flagged the semantics I chose in the diff comments for review.

Nine error variants that never existed. Commit 1412333 introduced strategy_validation.rs, governance_validation.rs, rounding_consistency.rs, and operational_safety_tests.rs, all referencing nine VaultError variants that appear in no revision of errors.rs. I checked every revision — the referencing side is the broken one. Mapped each to the closest existing code by semantics (InvalidStrategyResponse→InvalidAmount, InsufficientGovernanceVotes→QuorumNotReached, and so on) following the same reuse convention.

SDK 22 limits. symbol_short! rejects topics over 9 characters and contract function names over 32. Renamed vault_pause/vault_unpause/pause_fail to vpaused/vunpause/paufail (matching the paused/unpaused topics pause/unpause already publish) and strategy_switch_cooldown_remaining (34) to strategy_switch_cooldown_left.

ABI changes worth your review

Three, all consequences of making the code compile:

  • utilization_bps and effective_fee_bps now return Result<i128, VaultError>. They call total_assets, which is already fallible — the previous signature was unsound. report_benji_yield was updated.
  • strategy_switch_cooldown_remaining → strategy_switch_cooldown_left (name-length limit; no caller existed).
  • total_assets is unchanged in behaviour; only its callers gained ?.

Not fixed — please triage separately

29 tests fail on assertion values, not compilation. These are pre-existing behavioural drift, not something this branch introduces: I verified the failing tests are byte-identical to upstream/main. Examples — test_vault_with_benji_strategy expects 50 assets but gets 25; fee_math::test_fee_invariant_large_balances trips fee overflow on amount.checked_mul(fee_bps). The 10 oracle_failure_tests are a cluster worth one issue on their own.

Also untouched: contracts/vault/ROUNDING_POLICY.md and docs/DYNAMIC_FEES.md reference event topics I renamed, and strategy_switch_cooldown_remaining may appear in frontend code — worth a grep before deploy.

Notes

  • Cargo.lock is tracked in this repo, so regenerating it is part of the fix.
  • Local runs used the x86_64-pc-windows-gnu toolchain. mingw cannot link a Windows cdylib (export ordinal too large), so test binaries were built with crate-type temporarily reduced to rlib; the manifests are unchanged in this PR. CI builds on Linux.
  • Two test-only helpers were updated to the SDK 22 API: Address::from_string(&String::new(env)) could never have compiled, and the bridge-compat tests read instance storage outside a contract invocation, which SDK 22 rejects.

Closes #1303

main did not compile. \cargo check --all\ now passes and 488 of 517 tests pass.

Merge damage: a botched merge of two divergent total_assets() bodies in lib.rs left a validate_price_data() call with a dangling delimiter; is_performance_fee_enabled was missing a closing brace that swallowed the following ~1200 lines; DataKeyExt::Risk was declared twice; bridge-compat used #[contracterror] without importing it (all 21 of its errors); Cargo.lock had no bridge-compat entry, so --locked failed outright.

errors.rs declared 53 variants, but the Soroban error-enum spec caps an enum at 50 cases, so #[contracterror] panicked with LengthExceedsMax and took down every use of VaultError with it. Commit 8154517 pushed it from 50 to 53. The three performance-fee codes now reuse existing codes with matching semantics, following the pattern errors.rs already documents for the oracle and rescue flows. Codes 1-50 are unchanged, so the integrator contract in docs/api/ERROR_CODE_CATALOG.md is unaffected.

Nine error variants referenced from commit 1412333 were never declared in any revision of errors.rs. Mapped each onto the closest existing code. Also fixed an over-length contract function name, three over-length symbol_short! topics, and tests reading instance storage outside a contract invocation.
@drips-wave

drips-wave Bot commented Sep 25, 2026

Copy link
Copy Markdown

@broda-spendy 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! 🚀

Learn more about application limits

This branch has not been deployed

No deployments
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.

Rust contract source corruption from merge conflicts breaks local compilation

1 participant