Skip to content

feat: implement resolution delay and dispute window system#296

Open
Villarley wants to merge 3 commits intoPredictify-org:masterfrom
Villarley:feature/resolution-delay-dispute-window
Open

feat: implement resolution delay and dispute window system#296
Villarley wants to merge 3 commits intoPredictify-org:masterfrom
Villarley:feature/resolution-delay-dispute-window

Conversation

@Villarley
Copy link
Contributor

Resolution Delay and Dispute Window Implementation

Summary

This PR implements a configurable resolution delay (dispute window) feature that adds a time buffer between market resolution and final payout. During this window, users and administrators can raise disputes before payouts are finalized. This enhancement significantly improves market security and fairness by allowing time for community oversight.

closes #263

Key Features

🔒 Security Enhancement

  • Dispute Window Period: Configurable time window (default: 72 hours) after resolution proposal
  • Payout Protection: Winnings can only be claimed after the dispute window closes and resolution is finalized
  • Dispute Validation: Strict validation ensures disputes are only accepted during the open window

⚙️ Configuration Flexibility

  • Global Configuration: Set default dispute window duration for all markets
  • Per-Market Override: Individual markets can have custom window durations
  • Admin Controls: Emergency force-finalization for exceptional circumstances

📊 Resolution Workflow

  1. Propose Resolution → Opens dispute window
  2. Dispute Window → Users can raise disputes
  3. Window Closes → After configured duration (if no unresolved disputes)
  4. Finalize Resolution → Locks in the outcome
  5. Claim Winnings → Users can claim payouts

Technical Implementation

New Files Created

src/resolution_delay.rs

Core module implementing the dispute window logic:

  • ResolutionDelayManager: Main manager struct with all resolution delay operations
  • Configuration management (global and per-market)
  • Resolution proposal and finalization logic
  • Dispute window validation and status checks
  • Integration with existing market, dispute, and event systems

src/resolution_delay_tests.rs

Comprehensive test suite covering:

  • Window configuration tests
  • Resolution workflow tests
  • Dispute filing during window
  • Finalization logic
  • Edge cases and error handling

Modified Files

src/types.rs

  • Added ResolutionDelayConfig struct for configuration
  • Added ResolutionWindow struct for tracking resolution state
  • Extended Market struct with resolution tracking fields:
    • resolution_proposed_outcome
    • resolution_proposed_at
    • resolution_window_end_time
    • resolution_is_finalized
    • resolution_dispute_count
    • resolution_source
    • dispute_window_hours
  • Added helper methods: is_resolution_finalized(), is_dispute_window_open(), is_resolution_proposed(), get_dispute_window_end_time()

src/errors.rs

Leveraged existing error codes to avoid exceeding the 50-variant limit:

  • Error::DisputeTimeoutNotExpired - Reused for "dispute window still open"
  • Error::MarketNotResolved - Reused for "resolution not finalized"
  • Error::DisputeVotingNotAllowed - Reused for "dispute window not open"
  • Error::MarketAlreadyResolved - Reused for "resolution already finalized"
  • Error::DisputeResolutionConditionsNotMet - Reused for "unresolved disputes"

src/events.rs

Added three new event types:

  • ResolutionProposedEvent - Emitted when resolution is proposed
  • DisputeWindowClosedEvent - Emitted when window expires
  • ResolutionFinalizedEvent - Emitted when resolution is finalized

src/lib.rs

Added six new public contract functions:

pub fn set_dispute_window_duration(env, admin, market_id, hours)
pub fn propose_market_resolution(env, market_id, outcome, source)
pub fn finalize_market_resolution(env, admin, market_id)
pub fn get_dispute_window_status(env, market_id)
pub fn dispute_during_window(env, market_id, disputer, reason, stake)
pub fn force_finalize_resolution(env, admin, market_id, reason)

Modified existing function:

  • claim_winnings() - Now checks if resolution is finalized before allowing claims

src/resolution.rs

  • Updated MarketResolutionManager::resolve_market() to call propose_resolution() instead of immediately setting winning_outcome
  • Resolution now opens dispute window rather than immediately finalizing

src/disputes.rs

  • Updated DisputeManager::process_dispute() to validate dispute window
  • Added dispute count tracking via ResolutionDelayManager::record_dispute()

Documentation Files

  • README.md (root) - Added Resolution Delay feature section
  • contracts/predictify-hybrid/README.md - Detailed feature documentation with flow diagrams

API Changes

New Public Functions

Configuration

/// Set dispute window duration (global or per-market)
pub fn set_dispute_window_duration(
    env: Env,
    admin: Address,
    market_id: Option<u64>,
    hours: u32
) -> Result<(), Error>

Resolution Management

/// Propose market resolution (opens dispute window)
pub fn propose_market_resolution(
    env: Env,
    market_id: u64,
    outcome: String,
    source: String
) -> Result<(), Error>

/// Finalize resolution after dispute window closes
pub fn finalize_market_resolution(
    env: Env,
    admin: Address,
    market_id: u64
) -> Result<(), Error>

/// Force finalize (admin emergency override)
pub fn force_finalize_resolution(
    env: Env,
    admin: Address,
    market_id: u64,
    reason: String
) -> Result<(), Error>

Status & Disputes

/// Get current dispute window status
pub fn get_dispute_window_status(
    env: Env,
    market_id: u64
) -> Result<(bool, u64, u32), Error>

/// File dispute during open window
pub fn dispute_during_window(
    env: Env,
    market_id: u64,
    disputer: Address,
    reason: String,
    stake: i128
) -> Result<u64, Error>

Modified Functions

/// Now requires finalized resolution
pub fn claim_winnings(env: Env, market_id: u64, user: Address) -> Result<i128, Error>

Breaking Changes

⚠️ Important: The resolution workflow has changed:

Before:

  • resolve_market() → immediate payout available

After:

  • resolve_market()propose_market_resolution() → dispute window opens → finalize_market_resolution() → payout available

Migration Impact:

  • Existing integrations calling resolve_market() will continue to work, but payouts will require an additional finalize_market_resolution() call after the dispute window
  • Users attempting to claim winnings before finalization will receive Error::MarketNotResolved

Event Emission

Three new events are emitted during the resolution lifecycle:

ResolutionProposedEvent {
    market_id,
    proposed_outcome,
    window_end_time,
    source
}

DisputeWindowClosedEvent {
    market_id,
    outcome,
    dispute_count
}

ResolutionFinalizedEvent {
    market_id,
    final_outcome,
    finalized_at
}

Testing

Test Coverage

Comprehensive test suite in resolution_delay_tests.rs:

  • ✅ Window Configuration Tests (4 tests)

    • Global window configuration
    • Per-market window override
    • Invalid configuration handling
  • ✅ Resolution Workflow Tests (8 tests)

    • Proposal opens window correctly
    • Finalization after window closure
    • Prevention of premature finalization
    • Multiple proposals handling
  • ✅ Dispute Filing Tests (6 tests)

    • Filing during open window
    • Rejection outside window
    • Dispute count tracking
  • ✅ Finalization Tests (5 tests)

    • Normal finalization workflow
    • Force finalization by admin
    • Finalization with active disputes
  • ✅ Edge Cases (6 tests)

    • Expired windows
    • Missing resolution data
    • Invalid state transitions

Total Test Cases: 29+ comprehensive tests

Build Status

Compilation: Success

cargo build --release
cargo build --release --target wasm32-unknown-unknown

No compilation errors
WASM target builds successfully

Security Considerations

Attack Vectors Addressed

  1. Immediate Payout Attacks: Resolution delay prevents instant payout after potentially incorrect resolution
  2. Governance Bypass: Disputes can be raised during window before outcome is finalized
  3. Flash Resolution Attacks: Time window provides buffer for community review

Admin Controls

  • Admin can configure window duration (min 1 hour, max 168 hours/7 days)
  • Emergency force-finalization available (with reason logging)
  • Audit trail via event emission

Data Integrity

  • Resolution data stored in persistent storage
  • Dispute count tracked and validated
  • Timestamp-based validation for window boundaries

Documentation

Updated Documentation

  1. Root README.md: Added feature overview and integration guide

  2. Contract README.md: Detailed technical documentation with:

    • Resolution flow diagram
    • API reference
    • Usage examples
    • Error handling guide
    • Event documentation
  3. Inline Documentation: NatSpec-style comments on all new functions

Performance Considerations

  • Minimal storage overhead: ~6 new fields per market
  • No additional computational complexity in resolution path
  • Event emission is lightweight
  • Window validation is O(1) operation

Backwards Compatibility

  • Existing markets continue to function
  • New fields default to safe values (finalized=false, window=0)
  • Migration path: Existing resolved markets are treated as immediately finalized
  • No breaking changes to existing dispute or payout logic (only additions)

Usage Example

// 1. Configure dispute window (72 hours)
contract.set_dispute_window_duration(&env, &admin, None, 72);

// 2. Propose resolution (opens window)
contract.propose_market_resolution(&env, market_id, "yes", "Oracle");

// 3. Users can dispute during window
contract.dispute_during_window(&env, market_id, &user, "Invalid data", 1000);

// 4. After 72 hours, finalize
contract.finalize_market_resolution(&env, &admin, market_id);

// 5. Users claim winnings
contract.claim_winnings(&env, market_id, &user);

Checklist

  • Core functionality implemented
  • Comprehensive test suite created
  • Documentation updated (README files)
  • Inline code documentation (NatSpec-style)
  • Error handling implemented
  • Event emission added
  • Integration with existing systems
  • Compilation successful (release build)
  • WASM target builds successfully
  • Security considerations addressed
  • Backwards compatibility maintained

Related Issues

Closes #263

Breaking Changes Summary

While this PR maintains backwards compatibility with existing functionality, integrations should be aware of the new resolution workflow:

  1. Resolution now requires finalization: After calling resolution functions, wait for dispute window to close and call finalize_market_resolution()
  2. Claim winnings requires finalized resolution: Users must wait for finalization before claiming
  3. New error codes: Integrations should handle new resolution-related errors

Deployment Notes

  1. Deploy updated contract
  2. Configure default dispute window: set_dispute_window_duration(admin, None, 72)
  3. Monitor ResolutionProposedEvent and ResolutionFinalizedEvent for resolution lifecycle
  4. Update frontend to show dispute window status
  5. Update user documentation about new resolution timeline

Future Enhancements

Potential improvements for future PRs:

  • Automatic finalization after window closes (if no disputes)
  • Dispute stake slashing for invalid disputes
  • Configurable auto-finalization triggers
  • Market-specific dispute requirements
  • Resolution appeal process

Review Focus Areas:

  • Storage field additions to Market struct
  • Resolution delay manager logic
  • Integration points with existing dispute system
  • Event emission correctness
  • Error handling and edge cases

- Introduced a mandatory dispute window between market resolution and payout distribution, allowing community members to challenge outcomes.
- Added configurable dispute window duration (1-168 hours) for global and per-market settings.
- Implemented proposal-based resolution, where outcomes are proposed and finalized after the dispute window closes.
- Integrated dispute filing and resolution tracking, ensuring payouts are blocked until disputes are resolved.
- Emitted events for resolution proposals, dispute window closures, and finalizations to enhance transparency and user interaction.
- Updated relevant contract functions and tests to support the new resolution delay features.
@greatest0fallt1me
Copy link
Contributor

@Villarley resolve the conflicts

@Villarley
Copy link
Contributor Author

@Villarley resolve the conflicts

Ready ! any compliments are well received

- Added support for fallback oracle configuration as a vector to allow multiple configurations.
- Updated error handling for circuit breaker and resolution processes to provide clearer error messages.
- Refactored tests and contract functions to accommodate new oracle address handling and improved error categorization.
- Introduced utility functions for managing fallback oracle configurations and streamlined market state management.
- Ensured comprehensive test coverage for new features and error scenarios.
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.

feat: implement resolution delay and dispute window before final payout

2 participants