From aa0d0577c7715074cbcda8910cebe71634f5f32e Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:05:08 +0530 Subject: [PATCH 1/8] refactor: Integrate resolution management into Predictify Hybrid contract, simplifying market finalization and oracle result fetching --- contracts/predictify-hybrid/src/lib.rs | 118 +++---------------------- 1 file changed, 12 insertions(+), 106 deletions(-) diff --git a/contracts/predictify-hybrid/src/lib.rs b/contracts/predictify-hybrid/src/lib.rs index 6c0e06d0..530ebac2 100644 --- a/contracts/predictify-hybrid/src/lib.rs +++ b/contracts/predictify-hybrid/src/lib.rs @@ -36,6 +36,9 @@ use types::ExtensionStats; // Fee management module pub mod fees; use fees::{FeeManager, FeeCalculator, FeeValidator, FeeUtils, FeeTracker, FeeConfigManager}; +use resolution::{OracleResolutionManager, MarketResolutionManager}; + +pub mod resolution; #[contract] pub struct PredictifyHybrid; @@ -144,30 +147,10 @@ impl PredictifyHybrid { // Finalize market after disputes pub fn finalize_market(env: Env, admin: Address, market_id: Symbol, outcome: String) { - admin.require_auth(); - - // Verify admin - let stored_admin: Address = env - .storage() - .persistent() - .get(&Symbol::new(&env, "Admin")) - .expect("Admin not set"); - - // Use error helper for admin validation - errors::helpers::require_admin(&env, &admin, &stored_admin); - - let mut market: Market = env - .storage() - .persistent() - .get(&market_id) - .expect("Market not found"); - - // Use error helper for outcome validation - errors::helpers::require_valid_outcome(&env, &outcome, &market.outcomes); - - // Set final outcome - market.winning_outcome = Some(outcome); - env.storage().persistent().set(&market_id, &market); + match resolution::MarketResolutionManager::finalize_market(&env, &admin, &market_id, &outcome) { + Ok(_) => (), // Success + Err(e) => panic_with_error!(env, e), + } } // Allows users to vote on a market outcome by staking tokens @@ -180,59 +163,10 @@ impl PredictifyHybrid { // Fetch oracle result to determine market outcome pub fn fetch_oracle_result(env: Env, market_id: Symbol, oracle_contract: Address) -> String { - // Get the market from storage - let mut market: Market = env - .storage() - .persistent() - .get(&market_id) - .unwrap_or_else(|| { - panic!("Market not found"); - }); - - // Check if the market has already been resolved - if market.oracle_result.is_some() { - panic_with_error!(env, Error::MarketAlreadyResolved); - } - - // Check if the market ended (we can only fetch oracle result after market ends) - let current_time = env.ledger().timestamp(); - if current_time < market.end_time { - panic_with_error!(env, Error::MarketClosed); - } - - // Get the price from the appropriate oracle using the factory pattern - let oracle = match OracleFactory::create_oracle( - market.oracle_config.provider.clone(), - oracle_contract, - ) { - Ok(oracle) => oracle, - Err(e) => panic_with_error!(env, e), - }; - - let price = match oracle.get_price(&env, &market.oracle_config.feed_id) { - Ok(p) => p, - Err(e) => panic_with_error!(env, e), - }; - - // Determine the outcome based on the price and threshold using OracleUtils - let outcome = match OracleUtils::determine_outcome( - price, - market.oracle_config.threshold, - &market.oracle_config.comparison, - &env, - ) { - Ok(result) => result, + match resolution::OracleResolutionManager::fetch_oracle_result(&env, &market_id, &oracle_contract) { + Ok(resolution) => resolution.oracle_result, Err(e) => panic_with_error!(env, e), - }; - - // Store the result in the market - market.oracle_result = Some(outcome.clone()); - - // Update the market in storage - env.storage().persistent().set(&market_id, &market); - - // Return the outcome - outcome + } } // Allows users to dispute the market result by staking tokens @@ -245,38 +179,10 @@ impl PredictifyHybrid { // Resolves a market by combining oracle results and community votes pub fn resolve_market(env: Env, market_id: Symbol) -> String { - // Get the market from storage - let mut market = match MarketStateManager::get_market(&env, &market_id) { - Ok(market) => market, + match resolution::MarketResolutionManager::resolve_market(&env, &market_id) { + Ok(resolution) => resolution.final_outcome, Err(e) => panic_with_error!(env, e), - }; - - // Validate market for resolution - if let Err(e) = MarketValidator::validate_market_for_resolution(&env, &market) { - panic_with_error!(env, e); } - - // Retrieve the oracle result - let oracle_result = match &market.oracle_result { - Some(result) => result.clone(), - None => panic_with_error!(env, Error::OracleUnavailable), - }; - - // Calculate community consensus - let community_consensus = MarketAnalytics::calculate_community_consensus(&market); - - // Determine final result using hybrid algorithm - let final_result = - MarketUtils::determine_final_result(&env, &oracle_result, &community_consensus); - - // Set winning outcome - MarketStateManager::set_winning_outcome(&mut market, final_result.clone()); - - // Update the market in storage - MarketStateManager::update_market(&env, &market_id, &market); - - // Return the final result - final_result } // Resolve a dispute and determine final market outcome From 4c261283fd77f983717bc1c82da49dd0e27eae75 Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:05:20 +0530 Subject: [PATCH 2/8] feat: Add AdminNotSet error to enhance error handling in Predictify Hybrid contract --- contracts/predictify-hybrid/src/errors.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contracts/predictify-hybrid/src/errors.rs b/contracts/predictify-hybrid/src/errors.rs index 9fdf84bc..459d86bc 100644 --- a/contracts/predictify-hybrid/src/errors.rs +++ b/contracts/predictify-hybrid/src/errors.rs @@ -81,6 +81,8 @@ pub enum Error { OraclePriceOutOfRange = 33, /// Oracle comparison operation failed OracleComparisonFailed = 34, + /// Admin not set + AdminNotSet = 50, // ===== VALIDATION ERRORS (51-70) ===== /// Invalid outcome specified for voting or resolution @@ -199,7 +201,8 @@ impl Error { Error::InternalError | Error::StorageError | Error::ArithmeticError - | Error::InvalidState => ErrorCategory::System, + | Error::InvalidState + | Error::AdminNotSet => ErrorCategory::System, } } @@ -266,6 +269,7 @@ impl Error { Error::StorageError => "Storage operation failed", Error::ArithmeticError => "Arithmetic overflow or underflow occurred", Error::InvalidState => "Invalid contract state", + Error::AdminNotSet => "Admin not set in contract", } } @@ -319,6 +323,7 @@ impl Error { Error::StorageError => "STORAGE_ERROR", Error::ArithmeticError => "ARITHMETIC_ERROR", Error::InvalidState => "INVALID_STATE", + Error::AdminNotSet => "ADMIN_NOT_SET", } } From 119b22033d8c9981fabf67da7f617d17d68c4747 Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:05:33 +0530 Subject: [PATCH 3/8] feat: Implement resolution system methods in Predictify Hybrid contract for enhanced market resolution and analytics --- contracts/predictify-hybrid/src/lib.rs | 110 ++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/contracts/predictify-hybrid/src/lib.rs b/contracts/predictify-hybrid/src/lib.rs index 530ebac2..54ce8ab2 100644 --- a/contracts/predictify-hybrid/src/lib.rs +++ b/contracts/predictify-hybrid/src/lib.rs @@ -36,7 +36,7 @@ use types::ExtensionStats; // Fee management module pub mod fees; use fees::{FeeManager, FeeCalculator, FeeValidator, FeeUtils, FeeTracker, FeeConfigManager}; -use resolution::{OracleResolutionManager, MarketResolutionManager}; +use resolution::{OracleResolutionManager, MarketResolutionManager, MarketResolutionAnalytics, OracleResolutionAnalytics, ResolutionUtils}; pub mod resolution; @@ -193,6 +193,114 @@ impl PredictifyHybrid { } } + // ===== RESOLUTION SYSTEM METHODS ===== + + // Get oracle resolution for a market + pub fn get_oracle_resolution(env: Env, market_id: Symbol) -> Option { + match OracleResolutionManager::get_oracle_resolution(&env, &market_id) { + Ok(resolution) => resolution, + Err(_) => None, + } + } + + // Get market resolution for a market + pub fn get_market_resolution(env: Env, market_id: Symbol) -> Option { + match MarketResolutionManager::get_market_resolution(&env, &market_id) { + Ok(resolution) => resolution, + Err(_) => None, + } + } + + // Get resolution analytics + pub fn get_resolution_analytics(env: Env) -> resolution::ResolutionAnalytics { + match resolution::MarketResolutionAnalytics::calculate_resolution_analytics(&env) { + Ok(analytics) => analytics, + Err(_) => resolution::ResolutionAnalytics::default(), + } + } + + // Get oracle statistics + pub fn get_oracle_stats(env: Env) -> resolution::OracleStats { + match resolution::OracleResolutionAnalytics::get_oracle_stats(&env) { + Ok(stats) => stats, + Err(_) => resolution::OracleStats::default(), + } + } + + // Validate resolution for a market + pub fn validate_resolution(env: Env, market_id: Symbol) -> resolution::ResolutionValidation { + let mut validation = resolution::ResolutionValidation { + is_valid: true, + errors: vec![&env], + warnings: vec![&env], + recommendations: vec![&env], + }; + + // Get market + let market = match MarketStateManager::get_market(&env, &market_id) { + Ok(market) => market, + Err(_) => { + validation.is_valid = false; + validation.errors.push_back(String::from_str(&env, "Market not found")); + return validation; + } + }; + + // Check resolution state + let state = resolution::ResolutionUtils::get_resolution_state(&env, &market); + let (eligible, reason) = resolution::ResolutionUtils::get_resolution_eligibility(&env, &market); + + if !eligible { + validation.is_valid = false; + validation.errors.push_back(reason); + } + + // Add recommendations based on state + match state { + resolution::ResolutionState::Active => { + validation.recommendations.push_back(String::from_str(&env, "Market is active, wait for end time")); + } + resolution::ResolutionState::OracleResolved => { + validation.recommendations.push_back(String::from_str(&env, "Oracle resolved, ready for market resolution")); + } + resolution::ResolutionState::MarketResolved => { + validation.recommendations.push_back(String::from_str(&env, "Market already resolved")); + } + resolution::ResolutionState::Disputed => { + validation.recommendations.push_back(String::from_str(&env, "Resolution disputed, consider admin override")); + } + resolution::ResolutionState::Finalized => { + validation.recommendations.push_back(String::from_str(&env, "Resolution finalized")); + } + } + + validation + } + + // Get resolution state for a market + pub fn get_resolution_state(env: Env, market_id: Symbol) -> resolution::ResolutionState { + match MarketStateManager::get_market(&env, &market_id) { + Ok(market) => resolution::ResolutionUtils::get_resolution_state(&env, &market), + Err(_) => resolution::ResolutionState::Active, + } + } + + // Check if market can be resolved + pub fn can_resolve_market(env: Env, market_id: Symbol) -> bool { + match MarketStateManager::get_market(&env, &market_id) { + Ok(market) => resolution::ResolutionUtils::can_resolve_market(&env, &market), + Err(_) => false, + } + } + + // Calculate resolution time for a market + pub fn calculate_resolution_time(env: Env, market_id: Symbol) -> u64 { + match MarketStateManager::get_market(&env, &market_id) { + Ok(market) => resolution::ResolutionUtils::calculate_resolution_time(&env, &market), + Err(_) => 0, + } + } + // Get dispute statistics for a market pub fn get_dispute_stats(env: Env, market_id: Symbol) -> disputes::DisputeStats { match DisputeManager::get_dispute_stats(&env, market_id) { From 6c82e119731486c028b24682689dc7666c03879e Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:05:45 +0530 Subject: [PATCH 4/8] feat: Introduce comprehensive resolution management system in Predictify Hybrid contract, including oracle and market resolution methods, validation, and analytics --- contracts/predictify-hybrid/src/resolution.rs | 783 ++++++++++++++++++ 1 file changed, 783 insertions(+) create mode 100644 contracts/predictify-hybrid/src/resolution.rs diff --git a/contracts/predictify-hybrid/src/resolution.rs b/contracts/predictify-hybrid/src/resolution.rs new file mode 100644 index 00000000..5f50c493 --- /dev/null +++ b/contracts/predictify-hybrid/src/resolution.rs @@ -0,0 +1,783 @@ +use soroban_sdk::{contracttype, symbol_short, vec, Address, Env, Map, String, Symbol, Vec}; + +use crate::errors::Error; +use crate::markets::{MarketAnalytics, MarketStateManager, MarketUtils, MarketValidator, CommunityConsensus}; +use crate::oracles::{OracleFactory, OracleUtils}; +use crate::types::*; + +/// Resolution management system for Predictify Hybrid contract +/// +/// This module provides a comprehensive resolution system with: +/// - Oracle resolution functions and utilities +/// - Market resolution logic and validation +/// - Resolution analytics and statistics +/// - Resolution helper utilities and testing functions +/// - Resolution state management and tracking + +// ===== RESOLUTION TYPES ===== + +/// Resolution state enumeration +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[contracttype] +pub enum ResolutionState { + /// Market is active, no resolution yet + Active, + /// Oracle result fetched, pending final resolution + OracleResolved, + /// Market fully resolved with final outcome + MarketResolved, + /// Resolution disputed + Disputed, + /// Resolution finalized after dispute + Finalized, +} + +/// Oracle resolution result +#[derive(Clone, Debug)] +#[contracttype] +pub struct OracleResolution { + pub market_id: Symbol, + pub oracle_result: String, + pub price: i128, + pub threshold: i128, + pub comparison: String, + pub timestamp: u64, + pub provider: OracleProvider, + pub feed_id: String, +} + +/// Market resolution result +#[derive(Clone, Debug)] +pub struct MarketResolution { + pub market_id: Symbol, + pub final_outcome: String, + pub oracle_result: String, + pub community_consensus: CommunityConsensus, + pub resolution_timestamp: u64, + pub resolution_method: ResolutionMethod, + pub confidence_score: u32, +} + +/// Resolution method enumeration +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[contracttype] +pub enum ResolutionMethod { + /// Oracle only resolution + OracleOnly, + /// Community consensus only + CommunityOnly, + /// Hybrid oracle + community + Hybrid, + /// Admin override + AdminOverride, + /// Dispute resolution + DisputeResolution, +} + +/// Resolution analytics +#[derive(Clone, Debug)] +#[contracttype] +pub struct ResolutionAnalytics { + pub total_resolutions: u32, + pub oracle_resolutions: u32, + pub community_resolutions: u32, + pub hybrid_resolutions: u32, + pub average_confidence: i128, + pub resolution_times: Vec, + pub outcome_distribution: Map, +} + +/// Resolution validation result +#[derive(Clone, Debug)] +#[contracttype] +pub struct ResolutionValidation { + pub is_valid: bool, + pub errors: Vec, + pub warnings: Vec, + pub recommendations: Vec, +} + +// ===== ORACLE RESOLUTION ===== + +/// Oracle resolution management +pub struct OracleResolutionManager; + +impl OracleResolutionManager { + /// Fetch oracle result for a market + pub fn fetch_oracle_result( + env: &Env, + market_id: &Symbol, + oracle_contract: &Address, + ) -> Result { + // Get the market from storage + let mut market = MarketStateManager::get_market(env, market_id)?; + + // Validate market for oracle resolution + OracleResolutionValidator::validate_market_for_oracle_resolution(env, &market)?; + + // Get the price from the appropriate oracle using the factory pattern + let oracle = OracleFactory::create_oracle( + market.oracle_config.provider.clone(), + oracle_contract.clone(), + )?; + + let price = oracle.get_price(env, &market.oracle_config.feed_id)?; + + // Determine the outcome based on the price and threshold using OracleUtils + let outcome = OracleUtils::determine_outcome( + price, + market.oracle_config.threshold, + &market.oracle_config.comparison, + env, + )?; + + // Create oracle resolution record + let resolution = OracleResolution { + market_id: market_id.clone(), + oracle_result: outcome.clone(), + price, + threshold: market.oracle_config.threshold, + comparison: market.oracle_config.comparison.clone(), + timestamp: env.ledger().timestamp(), + provider: market.oracle_config.provider.clone(), + feed_id: market.oracle_config.feed_id.clone(), + }; + + // Store the result in the market + MarketStateManager::set_oracle_result(&mut market, outcome.clone()); + MarketStateManager::update_market(env, market_id, &market); + + Ok(resolution) + } + + /// Get oracle resolution for a market + pub fn get_oracle_resolution(env: &Env, market_id: &Symbol) -> Result, Error> { + // For now, return None since we don't store complex types in storage + // In a real implementation, you would store this in a more sophisticated way + Ok(None) + } + + /// Validate oracle resolution + pub fn validate_oracle_resolution(_env: &Env, resolution: &OracleResolution) -> Result<(), Error> { + // Validate price is positive + if resolution.price <= 0 { + return Err(Error::InvalidInput); + } + + // Validate threshold is positive + if resolution.threshold <= 0 { + return Err(Error::InvalidInput); + } + + // Validate outcome is not empty + if resolution.oracle_result.is_empty() { + return Err(Error::InvalidInput); + } + + Ok(()) + } + + /// Calculate oracle confidence score + pub fn calculate_oracle_confidence(resolution: &OracleResolution) -> u32 { + OracleResolutionAnalytics::calculate_confidence_score(resolution) + } +} + +// ===== MARKET RESOLUTION ===== + +/// Market resolution management +pub struct MarketResolutionManager; + +impl MarketResolutionManager { + /// Resolve a market by combining oracle results and community votes + pub fn resolve_market(env: &Env, market_id: &Symbol) -> Result { + // Get the market from storage + let mut market = MarketStateManager::get_market(env, market_id)?; + + // Validate market for resolution + MarketResolutionValidator::validate_market_for_resolution(env, &market)?; + + // Retrieve the oracle result + let oracle_result = market.oracle_result.as_ref() + .ok_or(Error::OracleUnavailable)? + .clone(); + + // Calculate community consensus + let community_consensus = MarketAnalytics::calculate_community_consensus(&market); + + // Determine final result using hybrid algorithm + let final_result = MarketUtils::determine_final_result(env, &oracle_result, &community_consensus); + + // Determine resolution method + let resolution_method = MarketResolutionAnalytics::determine_resolution_method( + &oracle_result, + &community_consensus, + ); + + // Calculate confidence score + let confidence_score = MarketResolutionAnalytics::calculate_confidence_score( + &oracle_result, + &community_consensus, + &resolution_method, + ); + + // Create market resolution record + let resolution = MarketResolution { + market_id: market_id.clone(), + final_outcome: final_result.clone(), + oracle_result, + community_consensus, + resolution_timestamp: env.ledger().timestamp(), + resolution_method, + confidence_score, + }; + + // Set winning outcome + MarketStateManager::set_winning_outcome(&mut market, final_result.clone()); + MarketStateManager::update_market(env, market_id, &market); + + Ok(resolution) + } + + /// Finalize market with admin override + pub fn finalize_market( + env: &Env, + admin: &Address, + market_id: &Symbol, + outcome: &String, + ) -> Result { + // Validate admin permissions + MarketResolutionValidator::validate_admin_permissions(env, admin)?; + + // Get the market + let mut market = MarketStateManager::get_market(env, market_id)?; + + // Validate outcome + MarketResolutionValidator::validate_outcome(env, outcome, &market.outcomes)?; + + // Create resolution record + let resolution = MarketResolution { + market_id: market_id.clone(), + final_outcome: outcome.clone(), + oracle_result: market.oracle_result.clone().unwrap_or_else(|| String::from_str(env, "")), + community_consensus: MarketAnalytics::calculate_community_consensus(&market), + resolution_timestamp: env.ledger().timestamp(), + resolution_method: ResolutionMethod::AdminOverride, + confidence_score: 100, // Admin override has full confidence + }; + + // Set final outcome + MarketStateManager::set_winning_outcome(&mut market, outcome.clone()); + MarketStateManager::update_market(env, market_id, &market); + + Ok(resolution) + } + + /// Get market resolution + pub fn get_market_resolution(env: &Env, market_id: &Symbol) -> Result, Error> { + // For now, return None since we don't store complex types in storage + // In a real implementation, you would store this in a more sophisticated way + Ok(None) + } + + /// Validate market resolution + pub fn validate_market_resolution(env: &Env, resolution: &MarketResolution) -> Result<(), Error> { + MarketResolutionValidator::validate_market_resolution(env, resolution) + } +} + +// ===== RESOLUTION VALIDATION ===== + +/// Oracle resolution validation +pub struct OracleResolutionValidator; + +impl OracleResolutionValidator { + /// Validate market for oracle resolution + pub fn validate_market_for_oracle_resolution(env: &Env, market: &Market) -> Result<(), Error> { + // Check if the market has already been resolved + if market.oracle_result.is_some() { + return Err(Error::MarketAlreadyResolved); + } + + // Check if the market ended (we can only fetch oracle result after market ends) + let current_time = env.ledger().timestamp(); + if current_time < market.end_time { + return Err(Error::MarketClosed); + } + + Ok(()) + } + + /// Validate oracle resolution + pub fn validate_oracle_resolution(_env: &Env, resolution: &OracleResolution) -> Result<(), Error> { + // Validate price is positive + if resolution.price <= 0 { + return Err(Error::InvalidInput); + } + + // Validate threshold is positive + if resolution.threshold <= 0 { + return Err(Error::InvalidInput); + } + + // Validate outcome is not empty + if resolution.oracle_result.is_empty() { + return Err(Error::InvalidInput); + } + + Ok(()) + } +} + +/// Market resolution validation +pub struct MarketResolutionValidator; + +impl MarketResolutionValidator { + /// Validate market for resolution + pub fn validate_market_for_resolution(env: &Env, market: &Market) -> Result<(), Error> { + // Check if market is already resolved + if market.winning_outcome.is_some() { + return Err(Error::MarketAlreadyResolved); + } + + // Check if oracle result is available + if market.oracle_result.is_none() { + return Err(Error::OracleUnavailable); + } + + // Check if market has ended + let current_time = env.ledger().timestamp(); + if current_time < market.end_time { + return Err(Error::MarketClosed); + } + + Ok(()) + } + + /// Validate admin permissions + pub fn validate_admin_permissions(env: &Env, admin: &Address) -> Result<(), Error> { + let stored_admin: Address = env + .storage() + .persistent() + .get(&Symbol::new(env, "Admin")) + .unwrap_or_else(|| panic!("Admin not set")); + + if admin != &stored_admin { + return Err(Error::Unauthorized); + } + + Ok(()) + } + + /// Validate outcome + pub fn validate_outcome(_env: &Env, outcome: &String, valid_outcomes: &Vec) -> Result<(), Error> { + if !valid_outcomes.contains(outcome) { + return Err(Error::InvalidOutcome); + } + + Ok(()) + } + + /// Validate market resolution + pub fn validate_market_resolution(env: &Env, resolution: &MarketResolution) -> Result<(), Error> { + // Validate final outcome is not empty + if resolution.final_outcome.is_empty() { + return Err(Error::InvalidInput); + } + + // Validate confidence score is within range + if resolution.confidence_score > 100 { + return Err(Error::InvalidInput); + } + + // Validate timestamp is reasonable + let current_time = env.ledger().timestamp(); + if resolution.resolution_timestamp > current_time { + return Err(Error::InvalidInput); + } + + Ok(()) + } +} + +// ===== RESOLUTION ANALYTICS ===== + +/// Oracle resolution analytics +pub struct OracleResolutionAnalytics; + +impl OracleResolutionAnalytics { + /// Calculate oracle confidence score + pub fn calculate_confidence_score(resolution: &OracleResolution) -> u32 { + // Base confidence for oracle resolution + let mut confidence: u32 = 80; + + // Adjust based on price deviation from threshold + let deviation = ((resolution.price - resolution.threshold).abs() as f64) / (resolution.threshold as f64); + + if deviation > 0.1 { + // High deviation - lower confidence + confidence = confidence.saturating_sub(20); + } else if deviation < 0.05 { + // Low deviation - higher confidence + confidence = confidence.saturating_add(10); + } + + confidence.min(100) + } + + /// Get oracle resolution statistics + pub fn get_oracle_stats(env: &Env) -> Result { + // For now, return default stats since we don't store complex types + Ok(OracleStats::default()) + } +} + +/// Market resolution analytics +pub struct MarketResolutionAnalytics; + +impl MarketResolutionAnalytics { + /// Determine resolution method + pub fn determine_resolution_method( + oracle_result: &String, + community_consensus: &CommunityConsensus, + ) -> ResolutionMethod { + if oracle_result == &community_consensus.outcome { + if community_consensus.percentage > 70 { + ResolutionMethod::Hybrid + } else { + ResolutionMethod::OracleOnly + } + } else { + if community_consensus.percentage > 80 && community_consensus.total_votes >= 10 { + ResolutionMethod::CommunityOnly + } else { + ResolutionMethod::OracleOnly + } + } + } + + /// Calculate confidence score + pub fn calculate_confidence_score( + oracle_result: &String, + community_consensus: &CommunityConsensus, + method: &ResolutionMethod, + ) -> u32 { + match method { + ResolutionMethod::OracleOnly => 85, + ResolutionMethod::CommunityOnly => { + let base_confidence = community_consensus.percentage as u32; + base_confidence.min(90) + } + ResolutionMethod::Hybrid => { + let oracle_confidence = 85; + let community_confidence = community_consensus.percentage as u32; + ((oracle_confidence + community_confidence) / 2).min(95) + } + ResolutionMethod::AdminOverride => 100, + ResolutionMethod::DisputeResolution => 75, + } + } + + /// Calculate resolution analytics + pub fn calculate_resolution_analytics(env: &Env) -> Result { + // For now, return default analytics since we don't store complex types + Ok(ResolutionAnalytics::default()) + } + + /// Update resolution analytics + pub fn update_resolution_analytics(_env: &Env, _resolution: &MarketResolution) -> Result<(), Error> { + // For now, do nothing since we don't store complex types + Ok(()) + } +} + +// ===== RESOLUTION UTILITIES ===== + +/// Resolution utility functions +pub struct ResolutionUtils; + +impl ResolutionUtils { + /// Get resolution state for a market + pub fn get_resolution_state(_env: &Env, market: &Market) -> ResolutionState { + if market.winning_outcome.is_some() { + ResolutionState::MarketResolved + } else if market.oracle_result.is_some() { + ResolutionState::OracleResolved + } else if market.total_dispute_stakes() > 0 { + ResolutionState::Disputed + } else { + ResolutionState::Active + } + } + + /// Check if market can be resolved + pub fn can_resolve_market(env: &Env, market: &Market) -> bool { + market.has_ended(env.ledger().timestamp()) && + market.oracle_result.is_some() && + market.winning_outcome.is_none() + } + + /// Get resolution eligibility + pub fn get_resolution_eligibility(env: &Env, market: &Market) -> (bool, String) { + if !market.has_ended(env.ledger().timestamp()) { + return (false, String::from_str(env, "Market has not ended")); + } + + if market.oracle_result.is_none() { + return (false, String::from_str(env, "Oracle result not available")); + } + + if market.winning_outcome.is_some() { + return (false, String::from_str(env, "Market already resolved")); + } + + (true, String::from_str(env, "Eligible for resolution")) + } + + /// Calculate resolution time + pub fn calculate_resolution_time(env: &Env, market: &Market) -> u64 { + let current_time = env.ledger().timestamp(); + if current_time > market.end_time { + current_time - market.end_time + } else { + 0 + } + } + + /// Validate resolution parameters + pub fn validate_resolution_parameters(_env: &Env, market: &Market, outcome: &String) -> Result<(), Error> { + // Validate outcome is in market outcomes + if !market.outcomes.contains(outcome) { + return Err(Error::InvalidOutcome); + } + + // Validate market is not already resolved + if market.winning_outcome.is_some() { + return Err(Error::MarketAlreadyResolved); + } + + Ok(()) + } +} + +// ===== RESOLUTION TESTING ===== + +/// Resolution testing utilities +pub struct ResolutionTesting; + +impl ResolutionTesting { + /// Create test oracle resolution + pub fn create_test_oracle_resolution(env: &Env, market_id: &Symbol) -> OracleResolution { + OracleResolution { + market_id: market_id.clone(), + oracle_result: String::from_str(env, "yes"), + price: 2500000, + threshold: 2500000, + comparison: String::from_str(env, "gt"), + timestamp: env.ledger().timestamp(), + provider: OracleProvider::Pyth, + feed_id: String::from_str(env, "BTC/USD"), + } + } + + /// Create test market resolution + pub fn create_test_market_resolution(env: &Env, market_id: &Symbol) -> MarketResolution { + MarketResolution { + market_id: market_id.clone(), + final_outcome: String::from_str(env, "yes"), + oracle_result: String::from_str(env, "yes"), + community_consensus: CommunityConsensus { + outcome: String::from_str(env, "yes"), + votes: 6, + total_votes: 10, + percentage: 60, + }, + resolution_timestamp: env.ledger().timestamp(), + resolution_method: ResolutionMethod::Hybrid, + confidence_score: 80, + } + } + + /// Validate resolution structure + pub fn validate_resolution_structure(resolution: &MarketResolution) -> Result<(), Error> { + if resolution.final_outcome.is_empty() { + return Err(Error::InvalidInput); + } + + if resolution.confidence_score > 100 { + return Err(Error::InvalidInput); + } + + Ok(()) + } + + /// Simulate resolution process + pub fn simulate_resolution_process( + env: &Env, + market_id: &Symbol, + oracle_contract: &Address, + ) -> Result { + // Fetch oracle result + let _oracle_resolution = OracleResolutionManager::fetch_oracle_result(env, market_id, oracle_contract)?; + + // Resolve market + let market_resolution = MarketResolutionManager::resolve_market(env, market_id)?; + + Ok(market_resolution) + } +} + +// ===== STATISTICS TYPES ===== + +/// Oracle statistics +#[derive(Clone, Debug)] +#[contracttype] +pub struct OracleStats { + pub total_resolutions: u32, + pub successful_resolutions: u32, + pub average_confidence: i128, + pub provider_distribution: Map, +} + +impl Default for OracleStats { + fn default() -> Self { + Self { + total_resolutions: 0, + successful_resolutions: 0, + average_confidence: 0, + provider_distribution: Map::new(&soroban_sdk::Env::default()), + } + } +} + +impl Default for ResolutionAnalytics { + fn default() -> Self { + Self { + total_resolutions: 0, + oracle_resolutions: 0, + community_resolutions: 0, + hybrid_resolutions: 0, + average_confidence: 0, + resolution_times: Vec::new(&soroban_sdk::Env::default()), + outcome_distribution: Map::new(&soroban_sdk::Env::default()), + } + } +} + +// ===== MODULE TESTS ===== + +#[cfg(test)] +mod tests { + use super::*; + use soroban_sdk::testutils::{Address as _, Ledger, LedgerInfo}; + + #[test] + fn test_oracle_resolution_manager_fetch_result() { + let env = Env::default(); + let market_id = Symbol::new(&env, "test_market"); + let oracle_contract = Address::generate(&env); + + // This test would require a mock oracle setup + // For now, we'll test the validation logic + let resolution = ResolutionTesting::create_test_oracle_resolution(&env, &market_id); + assert_eq!(resolution.oracle_result, String::from_str(&env, "yes")); + assert_eq!(resolution.price, 2500000); + } + + #[test] + fn test_market_resolution_manager_resolve_market() { + let env = Env::default(); + let market_id = Symbol::new(&env, "test_market"); + + // This test would require a complete market setup + // For now, we'll test the resolution structure + let resolution = ResolutionTesting::create_test_market_resolution(&env, &market_id); + assert_eq!(resolution.final_outcome, String::from_str(&env, "yes")); + assert_eq!(resolution.resolution_method, ResolutionMethod::Hybrid); + } + + #[test] + fn test_resolution_utils_get_state() { + let env = Env::default(); + let admin = Address::generate(&env); + let market = Market::new( + &env, + admin, + String::from_str(&env, "Test Market"), + vec![&env, String::from_str(&env, "yes"), String::from_str(&env, "no")], + env.ledger().timestamp() + 86400, + OracleConfig { + provider: OracleProvider::Pyth, + feed_id: String::from_str(&env, "BTC/USD"), + threshold: 2500000, + comparison: String::from_str(&env, "gt"), + }, + ); + + let state = ResolutionUtils::get_resolution_state(&env, &market); + assert_eq!(state, ResolutionState::Active); + } + + #[test] + fn test_resolution_analytics_determine_method() { + let env = Env::default(); + let oracle_result = String::from_str(&env, "yes"); + let community_consensus = CommunityConsensus { + outcome: String::from_str(&env, "yes"), + votes: 6, + total_votes: 10, + percentage: 60, + }; + + let method = MarketResolutionAnalytics::determine_resolution_method(&oracle_result, &community_consensus); + assert_eq!(method, ResolutionMethod::Hybrid); + } + + #[test] + fn test_resolution_testing_utilities() { + let env = Env::default(); + let market_id = Symbol::new(&env, "test_market"); + + let oracle_resolution = ResolutionTesting::create_test_oracle_resolution(&env, &market_id); + assert!(oracle_resolution.oracle_result == String::from_str(&env, "yes")); + + let market_resolution = ResolutionTesting::create_test_market_resolution(&env, &market_id); + assert!(ResolutionTesting::validate_resolution_structure(&market_resolution).is_ok()); + } + + #[test] + fn test_resolution_performance() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Test multiple resolution operations + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + // Multiple oracle resolution calls + client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + // Multiple market resolution calls + client.resolve_market(&test.market_id); + // Multiple analytics calls + client.get_resolution_analytics(); + // No performance assertions (no std::time) + } +} \ No newline at end of file From 44aa4ac0d2825e213134a080f26861762dfce126 Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:05:58 +0530 Subject: [PATCH 5/8] test: Add extensive resolution system tests for Predictify Hybrid contract, covering oracle result fetching, market resolution, validation, state management, and performance metrics --- contracts/predictify-hybrid/src/test.rs | 458 ++++++++++++++++++++++++ 1 file changed, 458 insertions(+) diff --git a/contracts/predictify-hybrid/src/test.rs b/contracts/predictify-hybrid/src/test.rs index defc477e..f0bd5a02 100644 --- a/contracts/predictify-hybrid/src/test.rs +++ b/contracts/predictify-hybrid/src/test.rs @@ -1721,3 +1721,461 @@ fn test_testing_utilities() { assert_eq!(breakdown.fee_amount, 20_000_000); assert_eq!(breakdown.user_payout_amount, 980_000_000); } + +// ===== RESOLUTION SYSTEM TESTS ===== + +#[test] +fn test_oracle_resolution_manager_fetch_result() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + // Get market end time + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + // Advance time past end time + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + // Fetch oracle result + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + let outcome = client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + + // Verify the outcome + assert_eq!(outcome, String::from_str(&test.env, "yes")); + + // Test get_oracle_resolution + let oracle_resolution = client.get_oracle_resolution(&test.market_id); + assert!(oracle_resolution.is_some()); +} + +#[test] +fn test_market_resolution_manager_resolve_market() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + // Add some votes + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + test.env.mock_all_auths(); + + let token_sac_client = StellarAssetClient::new(&test.env, &test.token_test.token_id); + for i in 0..5 { + let voter = Address::generate(&test.env); + token_sac_client.mint(&voter, &10_0000000); + client.vote( + &voter, + &test.market_id, + &String::from_str(&test.env, "yes"), + &1_0000000, + ); + } + + // Get market end time and advance time + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + // Fetch oracle result first + client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + + // Resolve market + let final_result = client.resolve_market(&test.market_id); + assert_eq!(final_result, String::from_str(&test.env, "yes")); + + // Test get_market_resolution + let market_resolution = client.get_market_resolution(&test.market_id); + assert!(market_resolution.is_some()); +} + +#[test] +fn test_resolution_validation() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Test validation before market ends + let validation = client.validate_resolution(&test.market_id); + assert!(!validation.is_valid); + assert!(!validation.errors.is_empty()); + + // Test validation after market ends but before oracle resolution + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + let validation = client.validate_resolution(&test.market_id); + assert!(validation.is_valid); + assert!(!validation.recommendations.is_empty()); +} + +#[test] +fn test_resolution_state_management() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Test initial state + let state = client.get_resolution_state(&test.market_id); + assert_eq!(state, crate::resolution::ResolutionState::Active); + + // Test can_resolve_market + let can_resolve = client.can_resolve_market(&test.market_id); + assert!(!can_resolve); + + // Test after market ends + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + let can_resolve = client.can_resolve_market(&test.market_id); + assert!(!can_resolve); // Still can't resolve without oracle result + + // Test after oracle resolution + client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + let state = client.get_resolution_state(&test.market_id); + assert_eq!(state, crate::resolution::ResolutionState::OracleResolved); + + let can_resolve = client.can_resolve_market(&test.market_id); + assert!(can_resolve); + + // Test after market resolution + client.resolve_market(&test.market_id); + let state = client.get_resolution_state(&test.market_id); + assert_eq!(state, crate::resolution::ResolutionState::MarketResolved); +} + +#[test] +fn test_resolution_analytics() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Test initial analytics + let analytics = client.get_resolution_analytics(); + assert_eq!(analytics.total_resolutions, 0); + + // Test oracle stats + let oracle_stats = client.get_oracle_stats(); + assert_eq!(oracle_stats.total_resolutions, 0); + + // Resolve a market + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + client.resolve_market(&test.market_id); + + // Test updated analytics + let analytics = client.get_resolution_analytics(); + assert_eq!(analytics.total_resolutions, 1); +} + +#[test] +fn test_resolution_time_calculation() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Test resolution time before market ends + let resolution_time = client.calculate_resolution_time(&test.market_id); + assert_eq!(resolution_time, 0); + + // Test resolution time after market ends + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + let advance_time = 3600; // 1 hour + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + advance_time, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + let resolution_time = client.calculate_resolution_time(&test.market_id); + assert_eq!(resolution_time, advance_time); +} + +#[test] +fn test_resolution_method_determination() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Add votes to create different scenarios + test.env.mock_all_auths(); + let token_sac_client = StellarAssetClient::new(&test.env, &test.token_test.token_id); + + // Scenario 1: Oracle and community agree + for i in 0..6 { + let voter = Address::generate(&test.env); + token_sac_client.mint(&voter, &10_0000000); + client.vote( + &voter, + &test.market_id, + &String::from_str(&test.env, "yes"), + &1_0000000, + ); + } + + for i in 0..4 { + let voter = Address::generate(&test.env); + token_sac_client.mint(&voter, &10_0000000); + client.vote( + &voter, + &test.market_id, + &String::from_str(&test.env, "no"), + &1_0000000, + ); + } + + // Resolve market + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + let final_result = client.resolve_market(&test.market_id); + + // Verify resolution method + let market_resolution = client.get_market_resolution(&test.market_id); + assert!(market_resolution.is_some()); + + let resolution = market_resolution.unwrap(); + assert_eq!(resolution.final_outcome, String::from_str(&test.env, "yes")); + assert!(resolution.confidence_score > 0); +} + +#[test] +fn test_resolution_error_handling() { + let test = PredictifyTest::setup(); + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Test resolution of non-existent market + let non_existent_market = Symbol::new(&test.env, "non_existent"); + + // These should not panic but return None or default values + let oracle_resolution = client.get_oracle_resolution(&non_existent_market); + assert!(oracle_resolution.is_none()); + + let market_resolution = client.get_market_resolution(&non_existent_market); + assert!(market_resolution.is_none()); + + let state = client.get_resolution_state(&non_existent_market); + assert_eq!(state, crate::resolution::ResolutionState::Active); + + let can_resolve = client.can_resolve_market(&non_existent_market); + assert!(!can_resolve); + + let resolution_time = client.calculate_resolution_time(&non_existent_market); + assert_eq!(resolution_time, 0); +} + +#[test] +fn test_resolution_with_disputes() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Add votes and resolve market + test.env.mock_all_auths(); + let token_sac_client = StellarAssetClient::new(&test.env, &test.token_test.token_id); + for i in 0..5 { + let voter = Address::generate(&test.env); + token_sac_client.mint(&voter, &10_0000000); + client.vote( + &voter, + &test.market_id, + &String::from_str(&test.env, "yes"), + &1_0000000, + ); + } + + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + client.resolve_market(&test.market_id); + + // Add dispute + let dispute_stake: i128 = 10_0000000; + test.env.mock_all_auths(); + client.dispute_result(&test.user, &test.market_id, &dispute_stake); + + // Test resolution state with dispute + let state = client.get_resolution_state(&test.market_id); + assert_eq!(state, crate::resolution::ResolutionState::Disputed); + + // Test validation with dispute + let validation = client.validate_resolution(&test.market_id); + assert!(validation.is_valid); + assert!(!validation.recommendations.is_empty()); +} + +#[test] +fn test_resolution_performance() { + let test = PredictifyTest::setup(); + test.create_test_market(); + + let client = PredictifyHybridClient::new(&test.env, &test.contract_id); + + // Test multiple resolution operations + let market = test.env.as_contract(&test.contract_id, || { + test.env + .storage() + .persistent() + .get::(&test.market_id) + .unwrap() + }); + + test.env.ledger().set(LedgerInfo { + timestamp: market.end_time + 1, + protocol_version: 22, + sequence_number: test.env.ledger().sequence(), + network_id: Default::default(), + base_reserve: 10, + min_temp_entry_ttl: 1, + min_persistent_entry_ttl: 1, + max_entry_ttl: 10000, + }); + + // Multiple oracle resolution calls should be fast + let start_time = std::time::Instant::now(); + client.fetch_oracle_result(&test.market_id, &test.pyth_contract); + let oracle_time = start_time.elapsed(); + + // Multiple market resolution calls should be fast + let start_time = std::time::Instant::now(); + client.resolve_market(&test.market_id); + let market_time = start_time.elapsed(); + + // Multiple analytics calls should be fast + let start_time = std::time::Instant::now(); + client.get_resolution_analytics(); + let analytics_time = start_time.elapsed(); + + // Verify reasonable performance (these are just sanity checks) + assert!(oracle_time.as_millis() < 1000); + assert!(market_time.as_millis() < 1000); + assert!(analytics_time.as_millis() < 1000); +} From f42c4385d43f0051f7e9a91a86c460c52332afef Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:07:49 +0530 Subject: [PATCH 6/8] feat: Add contracttype attribute to CommunityConsensus struct in Predictify Hybrid contract for enhanced type management --- contracts/predictify-hybrid/src/markets.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/predictify-hybrid/src/markets.rs b/contracts/predictify-hybrid/src/markets.rs index ca3d2fca..3287a3bb 100644 --- a/contracts/predictify-hybrid/src/markets.rs +++ b/contracts/predictify-hybrid/src/markets.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{token, vec, Address, Env, Map, String, Symbol, Vec}; +use soroban_sdk::{contracttype, token, vec, Address, Env, Map, String, Symbol, Vec}; use crate::errors::Error; use crate::oracles::{OracleFactory, OracleUtils}; @@ -517,6 +517,7 @@ pub struct UserStats { /// Community consensus statistics #[derive(Clone, Debug)] +#[contracttype] pub struct CommunityConsensus { pub outcome: String, pub votes: u32, From 45314a0705095a610255986712d79af8605ed46d Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:07:57 +0530 Subject: [PATCH 7/8] feat: Add contracttype attribute to MarketResolution struct in Predictify Hybrid contract for improved type management --- contracts/predictify-hybrid/src/resolution.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/predictify-hybrid/src/resolution.rs b/contracts/predictify-hybrid/src/resolution.rs index 5f50c493..c6365a4a 100644 --- a/contracts/predictify-hybrid/src/resolution.rs +++ b/contracts/predictify-hybrid/src/resolution.rs @@ -48,6 +48,7 @@ pub struct OracleResolution { /// Market resolution result #[derive(Clone, Debug)] +#[contracttype] pub struct MarketResolution { pub market_id: Symbol, pub final_outcome: String, From 40fbc7d91c988fd5fedd4eee4951b0226942bb98 Mon Sep 17 00:00:00 2001 From: 1nonlypiece Date: Sun, 6 Jul 2025 16:08:07 +0530 Subject: [PATCH 8/8] test: Remove performance assertions in resolution performance test for no_std compatibility and verify successful operation instead --- contracts/predictify-hybrid/src/test.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/contracts/predictify-hybrid/src/test.rs b/contracts/predictify-hybrid/src/test.rs index f0bd5a02..9f72962c 100644 --- a/contracts/predictify-hybrid/src/test.rs +++ b/contracts/predictify-hybrid/src/test.rs @@ -2160,22 +2160,15 @@ fn test_resolution_performance() { }); // Multiple oracle resolution calls should be fast - let start_time = std::time::Instant::now(); client.fetch_oracle_result(&test.market_id, &test.pyth_contract); - let oracle_time = start_time.elapsed(); // Multiple market resolution calls should be fast - let start_time = std::time::Instant::now(); client.resolve_market(&test.market_id); - let market_time = start_time.elapsed(); // Multiple analytics calls should be fast - let start_time = std::time::Instant::now(); client.get_resolution_analytics(); - let analytics_time = start_time.elapsed(); - // Verify reasonable performance (these are just sanity checks) - assert!(oracle_time.as_millis() < 1000); - assert!(market_time.as_millis() < 1000); - assert!(analytics_time.as_millis() < 1000); + // Verify the operations completed successfully (performance testing removed for no_std compatibility) + let analytics = client.get_resolution_analytics(); + assert_eq!(analytics.total_resolutions, 1); }