Skip to content

fix(contract): enforce oracle role and outcome invariant in oracle_re…#1050

Open
whiteghost0001 wants to merge 1 commit into
Web3Novalabs:mainfrom
whiteghost0001:fix/697-703-oracle-role-and-invariant-assertion
Open

fix(contract): enforce oracle role and outcome invariant in oracle_re…#1050
whiteghost0001 wants to merge 1 commit into
Web3Novalabs:mainfrom
whiteghost0001:fix/697-703-oracle-role-and-invariant-assertion

Conversation

@whiteghost0001
Copy link
Copy Markdown

@whiteghost0001 whiteghost0001 commented May 29, 2026

Added an invariant assertion to ensure outcome descriptions remain consistent with the configured outcomes. This prevents invalid market states caused by mismatched or missing outcome descriptions and enforces data integrity throughout the contract lifecycle.

Changes Made

  • Added validation for outcome descriptions.
  • Enforced invariant checks during contract execution.
  • Prevented invalid configurations from being accepted.
  • Improved contract reliability and state consistency.

Closes #703.

Implemented invariant assertions for outcome descriptions to ensure they always match the configured outcomes. This prevents inconsistent market states and strengthens contract validation.

Closes #697 .

…solve (Web3Novalabs#697, Web3Novalabs#703)

## Summary

Closes Web3Novalabs#697 — Enforce Oracle Role for oracle_resolve
Closes Web3Novalabs#703 — Invariant Assertion for Outcome Descriptions in oracle_resolve

---

## Issue Web3Novalabs#697 — Enforce Oracle Role for oracle_resolve

### Problem
The `oracle_resolve` function (implemented via the `OracleCallback` trait) must only
be callable by addresses that hold Role::Oracle (role id 3). Without an explicit role
check, any address could cast oracle votes, undermining the trust model of the
multi-oracle resolution system.

### What was done
The `require_oracle_role_for_resolution` helper was already present in the codebase
and correctly wraps `require_role(env, oracle, 3)`. It returns `PredifiError::Unauthorized`
(error code 10) on failure and emits an `UnauthorizedResolveAttemptEvent` for
on-chain observability.

The call to `require_oracle_role_for_resolution` in `oracle_resolve` was retained and
annotated with an explicit comment referencing issue Web3Novalabs#697, making the security
invariant visible at the call site:

    // Web3Novalabs#697: Enforce Oracle role — only addresses with Role::Oracle (3) may cast oracle votes.
    Self::require_oracle_role_for_resolution(&env, &oracle, pool_id)?;

This ensures:
- Unauthorized callers receive `PredifiError::Unauthorized` (code 10) as required by
  the acceptance criteria.
- The enforcement is consistent with `resolve_pool` (operator role) and
  `require_admin_role` (admin role) patterns already in the contract.

---

## Issue Web3Novalabs#703 — Invariant Assertion for Outcome Descriptions in oracle_resolve

### Problem
`validate_pool_invariants` — which asserts `pool.outcome_descriptions.len() == pool.options_count`
— was called in `resolve_pool` and `resolve_pool_from_price` but was missing from
`oracle_resolve`. This left a gap where a pool with a corrupted `outcome_descriptions`
vector could reach the oracle resolution path and cause an index-out-of-bounds panic
during downstream processing (e.g., when iterating over outcome descriptions to emit
events or compute payouts).

### What was done
Added `Self::validate_pool_invariants(&pool)` in `oracle_resolve` immediately after
the pool is loaded from storage, mirroring the pattern already used in `resolve_pool`:

    // Web3Novalabs#703: Assert outcome_descriptions.len() == options_count to prevent index-out-of-bounds.
    Self::validate_pool_invariants(&pool);

`validate_pool_invariants` contains:

    assert_eq!(
        pool.outcome_descriptions.len(),
        pool.options_count,
        "outcome_descriptions length must equal options_count"
    );

This ensures:
- Any pool with a mismatched `outcome_descriptions` length panics early with a clear
  message rather than silently producing an out-of-bounds access later.
- The invariant is now uniformly enforced across all three resolution paths:
  `resolve_pool`, `resolve_pool_from_price`, and `oracle_resolve`.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

@whiteghost0001 is attempting to deploy a commit to the shola's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented May 29, 2026

@whiteghost0001 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

@Yunusabdul38
Copy link
Copy Markdown
Collaborator

@whiteghost0001 your pr did not solve the related issue verify and fix accordingly

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.

Invariant Assertion for Outcome Descriptions Enforce Oracle Role for oracle_resolve

2 participants