Closes #829
Adds an integration suite that snapshots the Soroban authorization required by every
state-changing entrypoint of PredictifyHybrid. Rather than only asserting "authorized
succeeds / unauthorized fails", each test inspects env.auths() after the call and pins
which address the host actually required an authorization from.
This catches two regressions a pass/fail test misses: a require_auth silently dropped
(auth set becomes empty), and an auth subject rebound to the wrong argument.
Writing the suite surfaced three real authorization defects and a set of pre-existing build breakages that stopped the crate compiling at all. Both are fixed here so the suite can run.
Tests
tests/auth_snapshot.rs(new) — 24 tests: committed-snapshot assertions for 13 entrypoints, auth-boundary assertions for 3, read-only entrypoints pinned to no auth, plus edge cases (wrong-subject binding, subject tracking across users, non-admin rejection,#[should_panic]no-auth traps). The fixture registers a real Stellar Asset Contract so stake transfers commit.Cargo.toml— registered theauth_snapshottest target.
Authorization fixes
Soroban rejects a second require_auth on an already-authorized frame
(Error(Auth, ExistingValue)). Three paths authorized the same address twice — entrypoint
and inner manager — so they could never succeed on-chain:
fees.rs— redundantadmin.require_auth()inFeeManager::collect_fees. It was#[cfg(not(test))]-gated, so unit tests masked it while production builds hit it.disputes.rs— redundantuser.require_auth()inDisputeManager::dispute_market.rate_limiter.rs— redundantuser.require_auth()inrate_limit_voting/rate_limit_disputes.
Auth strength is unchanged: each is still enforced by the calling entrypoint
(require_primary_admin for admin paths, user.require_auth() for user paths).
Build restoration
The crate did not compile on master: e5db2d8 collapsed lib.rs to a "minimal working
version" and later PRs re-added call sites without restoring their definitions.
lib.rs— restored 14 droppedmoddeclarations; theinitialize/deposit/withdraw/get_balanceentrypoints; the admin-auth helpers (stored_primary_admin,require_primary_admin{,_or_panic},require_initialized_admin_root,require_admin_permission); theSYM_*/PERCENTAGE_DENOMINATORconstants and theresolution_timeout_reached/automatic_oracle_result_unavailablehelpers. Removed duplicate imports, fixed 7 invalidAddressderefs, repointedcapabilities().resolution.rs— repaired a mis-merge that spliced a payout-distribution body intoimpl ResolutionOutcomeCacheand intodetermine_outcome_from_oracle_data; restored the cache methods 6 modules call,ResolutionAnalytics/MedianResolutionResult, and theOracleResolutionManagerimpl boundary.market_id_generator.rs— restored the clean file from28c8db4.err.rs— removed a duplicateReplayedOverride; added 6 declared-nowhere variants; catch-all arms ondescription()/code().storage.rs— removed a duplicateAdminOverrideNonce; addedPlaceBetsIdemandAntiGriefFloor.gas.rs—Env::budget()is test-only, soBudgetGuarddegrades to a no-op outside tests; fixed an oversizedsymbol_short!and an invalidDefaultderive.upgrade_manager.rs— fixed au32/u64branch mismatch.
| Entrypoint | Subject | Verified by |
|---|---|---|
create_market, resolve_market_manual, collect_fees, set_platform_fee, set_treasury, set_global_claim_period, set_market_claim_period, extend_deadline |
admin | committed snapshot |
sweep_unclaimed_winnings |
admin | auth boundary |
vote, place_bet, cancel_bet |
user | committed snapshot |
claim_winnings, dispute_market |
user | auth boundary |
get_market, get_market_bet_stats |
none | committed snapshot |
Committed snapshot — the call is driven through a fully satisfied happy path and the auth
is read back from env.auths(). Auth boundary — the host rolls back recorded auths when a
call traps or returns Err, so entrypoints needing state the fixture does not build assert
instead that an authorized call gets past require_auth while an unauthorized one traps.
None. The suite is test-only, and the three fixes remove redundant authorization calls without weakening any check.
cargo test -p predictify-hybrid --test auth_snapshottest result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
cargo build -p predictify-hybrid --lib also succeeds, where it previously failed with ~40
parse and resolution errors.
- Auth strength is unchanged — every removed call was a redundant second authorization within the same frame.
- Out of scope — several
#[cfg(test)]modules undersrc/still fail to compile from pre-existing API drift, andtests/err_stability.rsneeds nightly (variant_count). - Local Windows builds hit a MinGW
export ordinal too largelink error on thecdylibwhentestutilsis enabled; run locally withcrate-type = ["lib"]. Linux CI is unaffected.