diff --git a/.env.mainnet b/.env.mainnet new file mode 100644 index 00000000..b4d30591 --- /dev/null +++ b/.env.mainnet @@ -0,0 +1,4 @@ +NETWORK=mainnet +DEPLOYER_SECRET_KEY="SB..." +ADMIN_ADDRESS="GB..." +ORACLE_CONTRACT="..." \ No newline at end of file diff --git a/API_DOCUMENTATION.md b/API_DOCUMENTATION.md new file mode 100644 index 00000000..ff8c30fa --- /dev/null +++ b/API_DOCUMENTATION.md @@ -0,0 +1,712 @@ +# Predictify Hybrid API Documentation + +> **Version:** v1.0.0 +> **Platform:** Stellar Soroban +> **Audience:** Developers integrating with Predictify Hybrid smart contracts + +--- + +## 📋 Table of Contents + +1. [API Overview](#api-overview) +2. [API Versioning](#api-versioning) +3. [Core API Reference](#core-api-reference) +4. [Data Structures](#data-structures) +5. [Error Codes](#error-codes) +6. [Integration Examples](#integration-examples) +7. [Troubleshooting Guide](#troubleshooting-guide) +8. [Support and Resources](#support-and-resources) + +--- + +## 🚀 API Overview + +The Predictify Hybrid smart contract provides a comprehensive API for building prediction market applications on the Stellar network. The API supports market creation, voting, dispute resolution, oracle integration, and administrative functions. + +### Key Features + +- **Market Management**: Create, extend, and resolve prediction markets +- **Voting System**: Stake-based voting with proportional payouts +- **Dispute Resolution**: Community-driven dispute and resolution system +- **Oracle Integration**: Support for Reflector, Pyth, and custom oracles +- **Fee Management**: Automated fee collection and distribution +- **Admin Governance**: Administrative functions for contract management + +--- + +## 📚 API Versioning + +### Current Version: v1.0.0 + +The Predictify Hybrid smart contract follows semantic versioning (SemVer) for API compatibility and contract upgrades. This section provides comprehensive information about API versions, compatibility, and migration strategies. + +### 🏷️ Version Schema + +We use **Semantic Versioning (SemVer)** with the format `MAJOR.MINOR.PATCH`: + +- **MAJOR** (1.x.x): Breaking changes that require client updates +- **MINOR** (x.1.x): New features that are backward compatible +- **PATCH** (x.x.1): Bug fixes and optimizations + +### 📋 Version History + +#### v1.0.0 (Current) - Production Release +**Release Date:** 2025-01-15 +**Status:** ✅ Active + +**Core Features:** +- Complete prediction market functionality +- Oracle integration (Reflector, Pyth) +- Voting and dispute resolution system +- Fee collection and distribution +- Admin governance functions +- Comprehensive validation system + +**API Endpoints:** +- `initialize(admin: Address)` - Contract initialization +- `create_market(...)` - Market creation +- `vote(...)` - User voting +- `dispute_market(...)` - Dispute submission +- `claim_winnings(...)` - Claim payouts +- `collect_fees(...)` - Admin fee collection +- `resolve_market(...)` - Market resolution + +**Breaking Changes from v0.x.x:** +- Renamed `submit_vote()` to `vote()` +- Updated oracle configuration structure +- Modified dispute threshold calculation +- Enhanced validation error codes + +### 🔄 Compatibility Matrix + +| Client Version | Contract v1.0.x | Contract v0.9.x | Contract v0.8.x | +|----------------|-----------------|-----------------|------------------| +| Client v1.0.x | ✅ Full | ⚠️ Limited | ❌ Incompatible | +| Client v0.9.x | ⚠️ Limited | ✅ Full | ✅ Full | +| Client v0.8.x | ❌ Incompatible | ⚠️ Limited | ✅ Full | + +**Legend:** +- ✅ **Full**: Complete compatibility, all features supported +- ⚠️ **Limited**: Basic functionality works, some features unavailable +- ❌ **Incompatible**: Not supported, upgrade required + +### 🚀 Upgrade Strategies + +#### For Contract Upgrades + +**1. Backward Compatible Updates (MINOR/PATCH)** +```bash +# Deploy new version alongside existing +soroban contract deploy \ + --wasm target/wasm32-unknown-unknown/release/predictify_hybrid_v1_1_0.wasm \ + --network mainnet + +# Update contract references gradually +# Old version continues to work +``` + +**2. Breaking Changes (MAJOR)** +```bash +# 1. Deploy new contract version +# 2. Migrate critical state (if supported) +# 3. Update all client applications +# 4. Deprecate old contract + +# Migration example +soroban contract invoke \ + --id $NEW_CONTRACT_ID \ + --fn migrate_from_v0 \ + --arg old_contract=$OLD_CONTRACT_ID +``` + +#### For Client Applications + +**JavaScript/TypeScript Example:** +```typescript +// Version-aware client initialization +const contractVersion = await getContractVersion(contractId); + +if (contractVersion.startsWith('1.0')) { + // Use v1.0 API + await contract.vote(marketId, outcome, stake); +} else if (contractVersion.startsWith('0.9')) { + // Use legacy API + await contract.submit_vote(marketId, outcome, stake); +} else { + throw new Error(`Unsupported contract version: ${contractVersion}`); +} +``` + +### 📖 API Documentation by Version + +#### Current API (v1.0.x) + +**Core Functions:** +- **Market Management**: `create_market()`, `extend_market()`, `resolve_market()` +- **Voting Operations**: `vote()`, `claim_winnings()` +- **Dispute System**: `dispute_market()`, `vote_on_dispute()` +- **Oracle Integration**: `submit_oracle_result()`, `update_oracle_config()` +- **Admin Functions**: `collect_fees()`, `update_config()`, `pause_contract()` + +**Data Structures:** +- `Market`: Core market data structure +- `Vote`: User vote representation +- `OracleConfig`: Oracle configuration +- `DisputeThreshold`: Dynamic dispute thresholds + +**Error Codes:** +- 100-199: User operation errors +- 200-299: Oracle errors +- 300-399: Validation errors +- 400-499: System errors + +#### Legacy API (v0.9.x) + +**Deprecated Functions:** +- `submit_vote()` → Use `vote()` in v1.0+ +- `create_prediction_market()` → Use `create_market()` in v1.0+ +- `get_market_stats()` → Use `get_market_analytics()` in v1.0+ + +### 🔍 Version Detection + +**Check Contract Version:** +```bash +# Using Soroban CLI +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_version \ + --network mainnet +``` + +**JavaScript/TypeScript:** +```typescript +import { Contract } from '@stellar/stellar-sdk'; + +const getContractVersion = async (contractId: string): Promise => { + try { + const result = await contract.call('get_version'); + return result.toString(); + } catch (error) { + // Fallback for older contracts without version endpoint + return '0.9.0'; + } +}; +``` + +### 🛡️ Deprecation Policy + +**Timeline:** +- **Announcement**: 90 days before deprecation +- **Warning Period**: 60 days with deprecation warnings +- **End of Support**: 30 days notice before complete removal + +**Current Deprecations:** +- `submit_vote()`: Deprecated in v1.0.0, removal planned for v2.0.0 +- `create_prediction_market()`: Deprecated in v1.0.0, removal planned for v2.0.0 + +### 📅 Release Schedule + +**Planned Releases:** +- **v1.1.0** (Q2 2025): Enhanced analytics, batch operations +- **v1.2.0** (Q3 2025): Multi-token support, advanced oracles +- **v2.0.0** (Q4 2025): Complete API redesign, performance improvements + +### 🔗 Version-Specific Resources + +**Documentation:** +- [v1.0.x API Reference](./docs/api/v1.0/) +- [v0.9.x Legacy Docs](./docs/api/v0.9/) +- [Migration Guide v0.9 → v1.0](./docs/migration/v0.9-to-v1.0.md) + +**Contract Addresses:** +- **v1.0.x Mainnet**: `CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQAHHAGK3HGU` +- **v0.9.x Mainnet**: `CBLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQAHHAGK3ABC` + +**Support Channels:** +- [GitHub Issues](https://github.com/predictify/contracts/issues) - Bug reports and feature requests +- [Discord #api-support](https://discord.gg/predictify) - Community support +- [Developer Forum](https://forum.predictify.io) - Technical discussions + +--- + +## 🔧 Core API Reference + +### Market Management Functions + +#### `create_market()` +Creates a new prediction market with specified parameters. + +**Signature:** +```rust +pub fn create_market( + env: Env, + admin: Address, + question: String, + outcomes: Vec, + duration_days: u32, + oracle_config: OracleConfig, +) -> Result +``` + +**Parameters:** +- `admin`: Market administrator address +- `question`: Market question (max 200 characters) +- `outcomes`: Possible outcomes (2-10 options) +- `duration_days`: Market duration (1-365 days) +- `oracle_config`: Oracle configuration for resolution + +**Returns:** Market ID (Symbol) + +**Example:** +```typescript +const marketId = await contract.create_market( + adminAddress, + "Will Bitcoin reach $100,000 by end of 2025?", + ["Yes", "No"], + 90, // 90 days + oracleConfig +); +``` + +#### `vote()` +Submit a vote on a market outcome with stake. + +**Signature:** +```rust +pub fn vote( + env: Env, + voter: Address, + market_id: Symbol, + outcome: String, + stake: i128, +) -> Result<(), Error> +``` + +**Parameters:** +- `voter`: Voter's address +- `market_id`: Target market ID +- `outcome`: Chosen outcome +- `stake`: Stake amount (minimum 0.1 XLM) + +**Example:** +```typescript +await contract.vote( + voterAddress, + "BTC_100K", + "Yes", + 5000000 // 0.5 XLM in stroops +); +``` + +#### `claim_winnings()` +Claim winnings from resolved markets. + +**Signature:** +```rust +pub fn claim_winnings( + env: Env, + user: Address, + market_id: Symbol, +) -> Result +``` + +**Returns:** Amount claimed in stroops + +--- + +## 📊 Data Structures + +### Market +Core market data structure containing all market information. + +```rust +pub struct Market { + pub id: Symbol, + pub question: String, + pub outcomes: Vec, + pub creator: Address, + pub created_at: u64, + pub deadline: u64, + pub resolved: bool, + pub winning_outcome: Option, + pub total_stake: i128, + pub oracle_config: OracleConfig, +} +``` + +### Vote +Represents a user's vote on a market. + +```rust +pub struct Vote { + pub voter: Address, + pub market_id: Symbol, + pub outcome: String, + pub stake: i128, + pub timestamp: u64, + pub claimed: bool, +} +``` + +### OracleConfig +Configuration for oracle integration. + +```rust +pub struct OracleConfig { + pub provider: OracleProvider, + pub feed_id: String, + pub threshold: i128, + pub timeout_seconds: u64, +} +``` + +--- + +## ⚠️ Error Codes + +### User Operation Errors (100-199) +- **100**: `UserNotAuthorized` - User lacks required permissions +- **101**: `MarketNotFound` - Specified market doesn't exist +- **102**: `MarketClosed` - Market is closed for voting +- **103**: `InvalidOutcome` - Outcome not available for market +- **104**: `AlreadyVoted` - User has already voted on this market +- **105**: `NothingToClaim` - No winnings available to claim +- **106**: `MarketNotResolved` - Market resolution pending +- **107**: `InsufficientStake` - Stake below minimum requirement + +### Oracle Errors (200-299) +- **200**: `OracleUnavailable` - Oracle service unavailable +- **201**: `InvalidOracleConfig` - Oracle configuration invalid +- **202**: `OracleTimeout` - Oracle response timeout +- **203**: `OracleDataInvalid` - Oracle data format invalid + +### Validation Errors (300-399) +- **300**: `InvalidInput` - General input validation failure +- **301**: `InvalidMarket` - Market parameters invalid +- **302**: `InvalidVote` - Vote parameters invalid +- **303**: `InvalidDispute` - Dispute parameters invalid + +### System Errors (400-499) +- **400**: `ContractNotInitialized` - Contract requires initialization +- **401**: `AdminRequired` - Admin privileges required +- **402**: `ContractPaused` - Contract is paused +- **403**: `InsufficientBalance` - Account balance too low + +--- + +## 💡 Integration Examples + +### Basic Market Creation and Voting + +```typescript +import { Contract, Keypair, Networks } from '@stellar/stellar-sdk'; + +// Initialize contract +const contract = new Contract(contractId); + +// Create market +const marketId = await contract.create_market( + adminKeypair.publicKey(), + "Will Ethereum reach $5,000 by Q2 2025?", + ["Yes", "No"], + 120, // 120 days + { + provider: "Reflector", + feed_id: "ETH/USD", + threshold: 5000000000, // $5,000 in stroops + timeout_seconds: 3600 + } +); + +// Vote on market +await contract.vote( + userKeypair.publicKey(), + marketId, + "Yes", + 10000000 // 1 XLM stake +); + +// Check market status +const market = await contract.get_market(marketId); +console.log(`Market: ${market.question}`); +console.log(`Total stake: ${market.total_stake} stroops`); + +// Claim winnings (after resolution) +const winnings = await contract.claim_winnings( + userKeypair.publicKey(), + marketId +); +console.log(`Claimed: ${winnings} stroops`); +``` + +### Batch Operations + +```typescript +// Create multiple markets +const markets = await Promise.all([ + contract.create_market(admin, "BTC > $100K?", ["Yes", "No"], 90, btcConfig), + contract.create_market(admin, "ETH > $5K?", ["Yes", "No"], 90, ethConfig), + contract.create_market(admin, "SOL > $200?", ["Yes", "No"], 90, solConfig) +]); + +// Vote on multiple markets +await Promise.all( + markets.map(marketId => + contract.vote(user, marketId, "Yes", 5000000) + ) +); +``` + +--- + +## 🆘 Troubleshooting Guide + +### Common Issues and Solutions + +#### 🔧 Deployment Issues + +**Problem: Contract deployment fails with "Insufficient Balance"** +```bash +Error: Account has insufficient balance for transaction +``` +**Solution:** +```bash +# Check account balance +soroban config identity address +soroban balance --id --network mainnet + +# Fund account if needed (minimum 100 XLM recommended) +# Use Stellar Laboratory or send from funded account +``` + +**Problem: WASM file not found during deployment** +```bash +Error: No such file or directory: target/wasm32-unknown-unknown/release/predictify_hybrid.wasm +``` +**Solution:** +```bash +# Ensure contract is built first +cd contracts/predictify-hybrid +make build + +# Verify WASM file exists +ls -la target/wasm32-unknown-unknown/release/ +``` + +#### 🔮 Oracle Integration Issues + +**Problem: Oracle results not being accepted** +```rust +Error: InvalidOracleConfig (201) +``` +**Solution:** +```bash +# Verify oracle configuration +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_oracle_config \ + --network mainnet + +# Update oracle configuration if needed +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn update_oracle_config \ + --arg provider=Reflector \ + --arg feed_id="BTC/USD" \ + --network mainnet +``` + +**Problem: Oracle price feeds timing out** +```rust +Error: OracleUnavailable (200) +``` +**Solution:** +1. Check oracle service status +2. Verify network connectivity +3. Implement fallback oracle providers +4. Add retry logic with exponential backoff + +#### 🗳️ Voting and Market Issues + +**Problem: User unable to vote** +```rust +Error: MarketClosed (102) +``` +**Solution:** +```bash +# Check market status and deadline +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_market \ + --arg market_id="BTC_100K" \ + --network mainnet + +# Extend market if authorized and appropriate +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn extend_market \ + --arg market_id="BTC_100K" \ + --arg additional_days=7 \ + --network mainnet +``` + +**Problem: Insufficient stake error** +```rust +Error: InsufficientStake (107) +``` +**Solution:** +```bash +# Check minimum stake requirements +echo "Minimum vote stake: 1,000,000 stroops (0.1 XLM)" +echo "Minimum dispute stake: 100,000,000 stroops (10 XLM)" + +# Verify user balance +soroban balance --id --network mainnet +``` + +#### 🏛️ Dispute Resolution Issues + +**Problem: Dispute submission rejected** +```rust +Error: DisputeVotingNotAllowed (406) +``` +**Solution:** +1. Verify market is in resolved state +2. Check dispute window timing (24-48 hours after resolution) +3. Ensure sufficient dispute stake +4. Verify user hasn't already disputed + +**Problem: Dispute threshold too high** +```rust +Error: ThresholdExceedsMaximum (412) +``` +**Solution:** +```bash +# Check current dispute threshold +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_dispute_threshold \ + --arg market_id="BTC_100K" \ + --network mainnet + +# Admin can adjust if necessary +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn update_dispute_threshold \ + --arg market_id="BTC_100K" \ + --arg new_threshold=50000000 \ + --network mainnet +``` + +#### 💰 Fee and Payout Issues + +**Problem: Fee collection fails** +```rust +Error: NoFeesToCollect (415) +``` +**Solution:** +```bash +# Check if fees are available +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_collectable_fees \ + --arg market_id="BTC_100K" \ + --network mainnet + +# Ensure market is resolved and fees haven't been collected +``` + +**Problem: User cannot claim winnings** +```rust +Error: NothingToClaim (105) +``` +**Solution:** +1. Verify user voted on winning outcome +2. Check market resolution status +3. Ensure user hasn't already claimed +4. Verify market dispute period has ended + +### 🔍 Debugging Tools + +#### Contract State Inspection +```bash +# Get complete market information +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_market_analytics \ + --arg market_id="BTC_100K" \ + --network mainnet + +# Check user voting history +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_user_votes \ + --arg user=
\ + --network mainnet + +# Inspect contract configuration +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn get_config \ + --network mainnet +``` + +#### Transaction Analysis +```bash +# View transaction details +soroban events --id $CONTRACT_ID --network mainnet + +# Check specific transaction +soroban transaction --hash --network mainnet +``` + +#### Log Analysis +```bash +# Enable verbose logging +export RUST_LOG=debug + +# Run with detailed output +soroban contract invoke \ + --id $CONTRACT_ID \ + --fn vote \ + --arg market_id="BTC_100K" \ + --arg outcome="yes" \ + --arg stake=5000000 \ + --network mainnet \ + --verbose +``` + +--- + +## 📞 Support and Resources + +### Error Code Reference +- **100-199**: User operation errors - Check user permissions and market state +- **200-299**: Oracle errors - Verify oracle configuration and connectivity +- **300-399**: Validation errors - Check input parameters and formats +- **400-499**: System errors - Contact support for system-level issues + +### Support Channels +1. **GitHub Issues**: [Report bugs and request features](https://github.com/predictify/contracts/issues) +2. **Discord Support**: [#technical-support channel](https://discord.gg/predictify) +3. **Developer Forum**: [Technical discussions](https://forum.predictify.io) +4. **Email Support**: technical-support@predictify.io + +### Before Contacting Support +1. Check this troubleshooting guide +2. Search existing GitHub issues +3. Verify your environment and configuration +4. Collect relevant error messages and transaction hashes +5. Note your contract version and network + +### Additional Resources +- [Stellar Soroban Documentation](https://soroban.stellar.org/) +- [Stellar SDK Documentation](https://stellar.github.io/js-stellar-sdk/) +- [Predictify GitHub Repository](https://github.com/predictify/contracts) +- [Community Examples](https://github.com/predictify/examples) + +--- + +**Last Updated:** 2025-01-15 +**API Version:** v1.0.0 +**Documentation Version:** 1.0 diff --git a/README.md b/README.md index 81502710..6527c17b 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,16 @@ ## 📋 Table of Contents 1. [Project Summary](#project-summary) -2. [Prerequisites](#prerequisites) -3. [Configuration for Mainnet](#configuration-for-mainnet) -4. [Deployment Instructions](#deployment-instructions) -5. [Oracle Setup](#oracle-setup) -6. [Testing Deployment](#testing-deployment) -7. [Monitoring and Alerts](#monitoring-and-alerts) -8. [Security Checklist](#security-checklist) -9. [Rollback Procedures](#rollback-procedures) -10. [Maintenance Procedures](#maintenance-procedures) +2. [API Documentation](#api-documentation) +3. [Prerequisites](#prerequisites) +4. [Configuration for Mainnet](#configuration-for-mainnet) +5. [Deployment Instructions](#deployment-instructions) +6. [Oracle Setup](#oracle-setup) +7. [Testing Deployment](#testing-deployment) +8. [Monitoring and Alerts](#monitoring-and-alerts) +9. [Security Checklist](#security-checklist) +10. [Rollback Procedures](#rollback-procedures) +11. [Maintenance Procedures](#maintenance-procedures) --- @@ -27,6 +28,23 @@ This repository contains smart contracts for Stellar's Soroban platform, organiz --- +## 📚 API Documentation + +For comprehensive API documentation, including versioning information, integration examples, and troubleshooting guides, please refer to: + +**📖 [API_DOCUMENTATION.md](./API_DOCUMENTATION.md)** + +This dedicated documentation file contains: +- **API Versioning**: Semantic versioning, compatibility matrix, upgrade strategies +- **Core API Reference**: Function signatures, parameters, and examples +- **Data Structures**: Complete type definitions and usage +- **Error Codes**: Comprehensive error reference with solutions +- **Integration Examples**: Real-world usage patterns and best practices +- **Troubleshooting Guide**: Common issues and debugging tools +- **Support Resources**: Community channels and getting help + +--- + ## 🛠️ Prerequisites - [Rust](https://www.rust-lang.org/tools/install) - [Soroban CLI](https://github.com/stellar/soroban-tools) @@ -193,7 +211,7 @@ soroban contract deploy ... - Publish deployed contract IDs in README - Oracle dashboard or visual monitor tool (Grafana, etc.) ---- + For deployment support or technical questions, please open an issue or contact the Predictify core team. diff --git a/contracts/hello-world/src/lib.rs b/contracts/hello-world/src/lib.rs index f8120043..07874a4e 100644 --- a/contracts/hello-world/src/lib.rs +++ b/contracts/hello-world/src/lib.rs @@ -1,6 +1,63 @@ #![no_std] use soroban_sdk::{contract, contractimpl, vec, Env, String, Vec}; +/// Hello World example contract demonstrating basic Soroban smart contract functionality. +/// +/// This contract serves as a simple introduction to Soroban smart contract development +/// and demonstrates fundamental concepts such as contract structure, function implementation, +/// and basic data handling. It provides a minimal but complete example that developers +/// can use as a starting point for building more complex smart contracts. +/// +/// # Purpose +/// +/// The Hello World contract is designed to: +/// - Demonstrate basic Soroban contract structure and syntax +/// - Show how to implement public contract functions +/// - Illustrate parameter handling and return value construction +/// - Provide a foundation for learning Soroban development +/// - Serve as a template for new contract projects +/// +/// # Contract Functions +/// +/// - `hello()` - Returns a greeting message with the provided name +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String, Vec}; +/// # use hello_world::Contract; +/// # let env = Env::default(); +/// # let contract_id = env.register(Contract, ()); +/// # let client = hello_world::ContractClient::new(&env, &contract_id); +/// +/// // Call the hello function +/// let name = String::from_str(&env, "World"); +/// let greeting = client.hello(&name); +/// +/// // greeting will be ["Hello", "World"] +/// assert_eq!(greeting.len(), 2); +/// ``` +/// +/// # Development Notes +/// +/// This contract is intentionally simple and serves as: +/// - A learning resource for new Soroban developers +/// - A template for creating new contracts +/// - A reference implementation for basic contract patterns +/// - A testing ground for development tools and workflows +/// +/// For more complex examples and advanced patterns, refer to: +/// - [Soroban Examples Repository](https://github.com/stellar/soroban-examples) +/// - [Stellar Developer Documentation](https://developers.stellar.org/docs/build/smart-contracts/overview) +/// +/// # Integration with Predictify Hybrid +/// +/// While this contract is independent, it demonstrates the same foundational +/// patterns used in the Predictify Hybrid prediction market system: +/// - Contract structure and organization +/// - Function implementation and parameter handling +/// - Testing patterns and best practices +/// - Documentation standards and conventions #[contract] pub struct Contract; @@ -15,6 +72,82 @@ pub struct Contract; // . #[contractimpl] impl Contract { + /// Generate a friendly greeting message. + /// + /// This function demonstrates basic Soroban contract functionality by accepting + /// a name parameter and returning a greeting message as a vector of strings. + /// It showcases fundamental concepts including parameter handling, string + /// manipulation, and vector construction within the Soroban environment. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment providing access to blockchain context + /// * `to` - The name or identifier to include in the greeting message + /// + /// # Returns + /// + /// A `Vec` containing the greeting message components: + /// - First element: "Hello" (static greeting) + /// - Second element: The provided `to` parameter + /// + /// # Example Usage + /// + /// ```rust + /// # use soroban_sdk::{Env, String, vec}; + /// # use hello_world::Contract; + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # let client = hello_world::ContractClient::new(&env, &contract_id); + /// + /// // Basic greeting + /// let name = String::from_str(&env, "Alice"); + /// let result = client.hello(&name); + /// + /// // Verify the result + /// assert_eq!(result, vec![ + /// &env, + /// String::from_str(&env, "Hello"), + /// String::from_str(&env, "Alice") + /// ]); + /// + /// // Different names produce different greetings + /// let dev_greeting = client.hello(&String::from_str(&env, "Developer")); + /// let world_greeting = client.hello(&String::from_str(&env, "World")); + /// + /// // Both contain "Hello" as the first element + /// assert_eq!(dev_greeting.get(0).unwrap(), String::from_str(&env, "Hello")); + /// assert_eq!(world_greeting.get(0).unwrap(), String::from_str(&env, "Hello")); + /// ``` + /// + /// # Implementation Details + /// + /// The function uses the `vec!` macro to construct a vector containing: + /// 1. A static "Hello" string created using `String::from_str()` + /// 2. The input `to` parameter passed directly + /// + /// This demonstrates: + /// - **Environment Usage**: Accessing the Soroban environment for string creation + /// - **Vector Construction**: Building return values using Soroban's vector type + /// - **String Handling**: Working with Soroban's String type + /// - **Parameter Processing**: Accepting and using function parameters + /// + /// # Learning Objectives + /// + /// This function teaches: + /// - Basic Soroban function signature patterns + /// - Environment parameter usage and importance + /// - String and vector manipulation in Soroban + /// - Return value construction and formatting + /// - Testing patterns for contract functions + /// + /// # Extension Ideas + /// + /// Developers can extend this function to: + /// - Add input validation for the `to` parameter + /// - Support multiple languages or greeting formats + /// - Include timestamps or additional metadata + /// - Implement more complex string processing + /// - Add logging or event emission pub fn hello(env: Env, to: String) -> Vec { vec![&env, String::from_str(&env, "Hello"), to] } diff --git a/contracts/predictify-hybrid/src/admin.rs b/contracts/predictify-hybrid/src/admin.rs index 05af1195..55367d6e 100644 --- a/contracts/predictify-hybrid/src/admin.rs +++ b/contracts/predictify-hybrid/src/admin.rs @@ -113,7 +113,71 @@ pub struct AdminAnalytics { pub struct AdminInitializer; impl AdminInitializer { - /// Initialize contract with admin + /// Initializes the Predictify Hybrid contract with a primary administrator. + /// + /// This function sets up the foundational admin structure for the contract, + /// establishing the primary admin with SuperAdmin privileges and initializing + /// the admin management system. It must be called once after contract deployment. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The address to be granted SuperAdmin privileges + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Admin initialization completed successfully + /// - `Err(Error)` - Specific error if initialization fails + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::InvalidAddress` - Admin address is invalid or zero + /// - `Error::AlreadyInitialized` - Contract has already been initialized + /// - `Error::StorageError` - Failed to store admin data + /// - Role assignment errors from AdminRoleManager + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminInitializer; + /// # let env = Env::default(); + /// # let admin_address = Address::generate(&env); + /// + /// match AdminInitializer::initialize(&env, &admin_address) { + /// Ok(()) => { + /// println!("Contract initialized successfully"); + /// }, + /// Err(e) => { + /// println!("Initialization failed: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Initialization Process + /// + /// The initialization performs these steps: + /// 1. **Address Validation**: Ensures admin address is valid + /// 2. **Storage Setup**: Stores admin address in persistent storage + /// 3. **Role Assignment**: Grants SuperAdmin role to the admin + /// 4. **Event Emission**: Emits admin initialization event + /// 5. **Action Logging**: Records the initialization action + /// + /// # Post-Initialization State + /// + /// After successful initialization: + /// - Admin has full SuperAdmin privileges + /// - All admin permissions are available to the admin + /// - Admin management system is fully operational + /// - Contract is ready for market creation and management + /// + /// # Security + /// + /// The admin address should be carefully chosen as it will have complete + /// control over the contract. Consider using a multi-signature wallet + /// or governance contract for production deployments. pub fn initialize(env: &Env, admin: &Address) -> Result<(), Error> { // Validate admin address AdminValidator::validate_admin_address(env, admin)?; @@ -148,7 +212,77 @@ impl AdminInitializer { Ok(()) } - /// Initialize contract with configuration + /// Initializes the contract with admin and environment-specific configuration. + /// + /// This advanced initialization function sets up both admin privileges and + /// applies environment-specific configurations (development, testnet, mainnet). + /// It's ideal for deployment scenarios where specific configurations are needed. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The address to be granted SuperAdmin privileges + /// * `environment` - The target environment configuration to apply + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Admin and configuration initialization completed successfully + /// - `Err(Error)` - Specific error if initialization fails + /// + /// # Errors + /// + /// This function returns errors from: + /// - `AdminInitializer::initialize()` - Basic admin initialization errors + /// - `ConfigManager::store_config()` - Configuration storage errors + /// - Event emission errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminInitializer; + /// # use predictify_hybrid::config::Environment; + /// # let env = Env::default(); + /// # let admin_address = Address::generate(&env); + /// + /// // Initialize for mainnet deployment + /// match AdminInitializer::initialize_with_config( + /// &env, + /// &admin_address, + /// &Environment::Mainnet + /// ) { + /// Ok(()) => { + /// println!("Contract initialized with mainnet config"); + /// }, + /// Err(e) => { + /// println!("Initialization failed: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Environment Configurations + /// + /// - **Development**: Relaxed validation, debug features enabled + /// - **Testnet**: Production-like settings with test-friendly parameters + /// - **Mainnet**: Full production settings with strict validation + /// - **Custom**: Defaults to development configuration + /// + /// # Configuration Applied + /// + /// Environment-specific settings include: + /// - Fee structures and percentages + /// - Market duration limits + /// - Validation thresholds + /// - Oracle timeout settings + /// - Dispute resolution parameters + /// + /// # Use Cases + /// + /// - **Production Deployment**: Use with `Environment::Mainnet` + /// - **Testing**: Use with `Environment::Testnet` or `Environment::Development` + /// - **CI/CD Pipelines**: Automated deployment with appropriate environment + /// - **Multi-Environment Contracts**: Same contract code, different configs pub fn initialize_with_config( env: &Env, admin: &Address, @@ -171,7 +305,71 @@ impl AdminInitializer { Ok(()) } - /// Validate initialization parameters + /// Validates parameters before contract initialization. + /// + /// This function performs pre-initialization validation to ensure the contract + /// can be safely initialized with the provided parameters. It's useful for + /// checking initialization requirements before committing to the initialization. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The proposed admin address to validate + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - All parameters are valid for initialization + /// - `Err(Error)` - Specific validation error + /// + /// # Errors + /// + /// This function returns specific validation errors: + /// - `Error::InvalidAddress` - Admin address is invalid, zero, or malformed + /// - `Error::AlreadyInitialized` - Contract has already been initialized + /// - Address format validation errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminInitializer; + /// # let env = Env::default(); + /// # let proposed_admin = Address::generate(&env); + /// + /// // Validate before initialization + /// match AdminInitializer::validate_initialization_params(&env, &proposed_admin) { + /// Ok(()) => { + /// // Parameters are valid, proceed with initialization + /// AdminInitializer::initialize(&env, &proposed_admin).unwrap(); + /// }, + /// Err(e) => { + /// println!("Invalid parameters: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Validation Checks + /// + /// The function performs these validations: + /// 1. **Admin Address**: Ensures address is valid and not zero + /// 2. **Contract State**: Verifies contract hasn't been initialized + /// 3. **Address Format**: Validates Stellar address format + /// 4. **Storage Access**: Ensures storage operations will succeed + /// + /// # Use Cases + /// + /// - **Pre-flight Checks**: Validate before expensive initialization + /// - **UI Validation**: Check parameters in user interfaces + /// - **Deployment Scripts**: Ensure deployment will succeed + /// - **Testing**: Validate test parameters before test execution + /// - **Error Prevention**: Catch issues before state changes + /// + /// # Best Practices + /// + /// Always call this function before `initialize()` or `initialize_with_config()` + /// to prevent failed initialization attempts that could leave the contract + /// in an inconsistent state. pub fn validate_initialization_params( env: &Env, admin: &Address, @@ -188,7 +386,71 @@ impl AdminInitializer { pub struct AdminAccessControl; impl AdminAccessControl { - /// Validate admin permissions for an action + /// Validates that an admin has the required permission for a specific action. + /// + /// This function checks if the given admin address has the necessary permission + /// to perform a specific action based on their assigned role. It's the core + /// authorization mechanism for all admin operations in the contract. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address to validate permissions for + /// * `permission` - The specific permission required for the action + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Admin has the required permission + /// - `Err(Error)` - Admin lacks permission or validation failed + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Admin doesn't have the required permission + /// - `Error::Unauthorized` - Admin role not found or inactive + /// - Role retrieval errors from AdminRoleManager + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::{AdminAccessControl, AdminPermission}; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Check if admin can create markets + /// match AdminAccessControl::validate_permission( + /// &env, + /// &admin, + /// &AdminPermission::CreateMarket + /// ) { + /// Ok(()) => { + /// // Admin has permission, proceed with market creation + /// println!("Admin authorized for market creation"); + /// }, + /// Err(e) => { + /// println!("Permission denied: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Permission Hierarchy + /// + /// Different admin roles have different permission sets: + /// - **SuperAdmin**: All permissions + /// - **MarketAdmin**: Market-related permissions + /// - **ConfigAdmin**: Configuration permissions + /// - **FeeAdmin**: Fee management permissions + /// - **ReadOnlyAdmin**: View-only permissions + /// + /// # Use Cases + /// + /// - **Function Guards**: Validate permissions before executing admin functions + /// - **UI Authorization**: Show/hide UI elements based on permissions + /// - **API Endpoints**: Authorize admin API calls + /// - **Batch Operations**: Validate permissions for multiple operations + /// - **Audit Trails**: Log permission checks for security auditing pub fn validate_permission( env: &Env, admin: &Address, @@ -205,7 +467,72 @@ impl AdminAccessControl { Ok(()) } - /// Require admin authentication + /// Requires admin authentication and validates admin status. + /// + /// This function performs comprehensive admin authentication by verifying + /// the caller's signature and confirming they are a registered admin. + /// It's the fundamental authentication check for all admin operations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address to authenticate + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Admin is authenticated and authorized + /// - `Err(Error)` - Authentication or authorization failed + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::AdminNotSet` - No admin has been configured for the contract + /// - `Error::Unauthorized` - Caller is not the registered admin + /// - Authentication errors from Soroban's `require_auth()` + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminAccessControl; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Authenticate admin before sensitive operation + /// match AdminAccessControl::require_admin_auth(&env, &admin) { + /// Ok(()) => { + /// // Admin is authenticated, proceed with operation + /// println!("Admin authenticated successfully"); + /// }, + /// Err(e) => { + /// println!("Authentication failed: {:?}", e); + /// return; + /// } + /// } + /// ``` + /// + /// # Authentication Process + /// + /// The authentication performs these checks: + /// 1. **Signature Verification**: Validates the caller's cryptographic signature + /// 2. **Admin Lookup**: Retrieves the stored admin address from contract storage + /// 3. **Address Comparison**: Ensures the caller matches the stored admin + /// 4. **Status Validation**: Confirms admin status is active + /// + /// # Security Considerations + /// + /// - Uses Soroban's built-in signature verification + /// - Prevents unauthorized access to admin functions + /// - Should be called before any admin-only operations + /// - Protects against address spoofing attacks + /// + /// # Use Cases + /// + /// - **Function Entry Points**: First check in admin functions + /// - **Batch Operations**: Authenticate once for multiple operations + /// - **API Gateways**: Validate admin API requests + /// - **Emergency Functions**: Ensure only authorized emergency actions pub fn require_admin_auth(env: &Env, admin: &Address) -> Result<(), Error> { // Verify admin authentication admin.require_auth(); @@ -224,7 +551,82 @@ impl AdminAccessControl { Ok(()) } - /// Validate admin for specific action + /// Validates admin authentication and permissions for a specific action. + /// + /// This comprehensive validation function combines authentication and + /// permission checking for a specific action. It's a convenience function + /// that performs complete admin validation in a single call. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address to validate + /// * `action` - String identifier of the action to validate (e.g., "create_market") + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Admin is authenticated and authorized for the action + /// - `Err(Error)` - Authentication, permission, or action mapping failed + /// + /// # Errors + /// + /// This function returns errors from: + /// - `require_admin_auth()` - Authentication failures + /// - `map_action_to_permission()` - Invalid action string + /// - `validate_permission()` - Permission validation failures + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminAccessControl; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Validate admin for market creation + /// match AdminAccessControl::validate_admin_for_action( + /// &env, + /// &admin, + /// "create_market" + /// ) { + /// Ok(()) => { + /// // Admin is fully authorized, proceed with market creation + /// println!("Admin authorized for market creation"); + /// }, + /// Err(e) => { + /// println!("Authorization failed: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Supported Actions + /// + /// Valid action strings include: + /// - `"initialize"` - Contract initialization + /// - `"create_market"` - Market creation + /// - `"close_market"` - Market closure + /// - `"finalize_market"` - Market finalization + /// - `"extend_market"` - Market duration extension + /// - `"update_fees"` - Fee configuration updates + /// - `"update_config"` - Contract configuration updates + /// - `"collect_fees"` - Fee collection + /// - `"manage_disputes"` - Dispute management + /// - `"emergency_actions"` - Emergency operations + /// + /// # Validation Process + /// + /// The function performs validation in this order: + /// 1. **Authentication**: Verifies admin signature and status + /// 2. **Action Mapping**: Maps action string to permission enum + /// 3. **Permission Check**: Validates admin has required permission + /// + /// # Use Cases + /// + /// - **Single-Call Validation**: Complete validation in one function call + /// - **Dynamic Actions**: Validate actions determined at runtime + /// - **API Endpoints**: Validate admin API calls with action strings + /// - **Middleware**: Use in middleware for automatic admin validation pub fn validate_admin_for_action( env: &Env, admin: &Address, @@ -242,7 +644,82 @@ impl AdminAccessControl { Ok(()) } - /// Map action string to permission enum + /// Maps action string identifiers to their corresponding permission enums. + /// + /// This utility function converts human-readable action strings into + /// the corresponding AdminPermission enum values. It's used to bridge + /// string-based action identifiers with the type-safe permission system. + /// + /// # Parameters + /// + /// * `action` - String identifier of the action to map + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(AdminPermission)` - Successfully mapped action to permission + /// - `Err(Error::InvalidInput)` - Action string is not recognized + /// + /// # Errors + /// + /// This function returns: + /// - `Error::InvalidInput` - Action string doesn't match any known actions + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::admin::{AdminAccessControl, AdminPermission}; + /// + /// // Map action string to permission + /// match AdminAccessControl::map_action_to_permission("create_market") { + /// Ok(permission) => { + /// assert_eq!(permission, AdminPermission::CreateMarket); + /// println!("Mapped to CreateMarket permission"); + /// }, + /// Err(e) => { + /// println!("Invalid action: {:?}", e); + /// } + /// } + /// + /// // Handle invalid action + /// match AdminAccessControl::map_action_to_permission("invalid_action") { + /// Ok(_) => unreachable!(), + /// Err(e) => { + /// println!("Expected error for invalid action: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Action Mapping Table + /// + /// | Action String | Permission Enum | + /// |---------------|----------------| + /// | `"initialize"` | `AdminPermission::Initialize` | + /// | `"create_market"` | `AdminPermission::CreateMarket` | + /// | `"close_market"` | `AdminPermission::CloseMarket` | + /// | `"finalize_market"` | `AdminPermission::FinalizeMarket` | + /// | `"extend_market"` | `AdminPermission::ExtendMarket` | + /// | `"update_fees"` | `AdminPermission::UpdateFees` | + /// | `"update_config"` | `AdminPermission::UpdateConfig` | + /// | `"reset_config"` | `AdminPermission::ResetConfig` | + /// | `"collect_fees"` | `AdminPermission::CollectFees` | + /// | `"manage_disputes"` | `AdminPermission::ManageDisputes` | + /// | `"view_analytics"` | `AdminPermission::ViewAnalytics` | + /// | `"emergency_actions"` | `AdminPermission::EmergencyActions` | + /// + /// # Use Cases + /// + /// - **API Integration**: Convert API action parameters to permissions + /// - **Dynamic Validation**: Handle actions determined at runtime + /// - **Configuration**: Map configuration-driven actions to permissions + /// - **Testing**: Validate action-permission mappings in tests + /// - **Debugging**: Convert action strings for logging and debugging + /// + /// # Design Notes + /// + /// Action strings use snake_case convention to match Rust naming standards. + /// The mapping is case-sensitive and must match exactly. Consider adding + /// case-insensitive mapping if needed for API flexibility. pub fn map_action_to_permission(action: &str) -> Result { match action { "initialize" => Ok(AdminPermission::Initialize), @@ -268,7 +745,80 @@ impl AdminAccessControl { pub struct AdminRoleManager; impl AdminRoleManager { - /// Assign role to admin + /// Assigns a specific admin role to an address with associated permissions. + /// + /// This function creates or updates admin role assignments, establishing the + /// permission hierarchy for admin operations. It supports bootstrapping the + /// first admin and subsequent role assignments by authorized admins. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The address to receive the admin role + /// * `role` - The admin role to assign (SuperAdmin, MarketAdmin, etc.) + /// * `assigned_by` - The address performing the role assignment + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Role assigned successfully + /// - `Err(Error)` - Assignment failed due to permissions or validation + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Assigner lacks EmergencyActions permission + /// - Permission validation errors from AdminAccessControl + /// - Storage operation errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::{AdminRoleManager, AdminRole}; + /// # let env = Env::default(); + /// # let super_admin = Address::generate(&env); + /// # let new_admin = Address::generate(&env); + /// + /// // Assign MarketAdmin role to a new admin + /// match AdminRoleManager::assign_role( + /// &env, + /// &new_admin, + /// AdminRole::MarketAdmin, + /// &super_admin + /// ) { + /// Ok(()) => { + /// println!("MarketAdmin role assigned successfully"); + /// }, + /// Err(e) => { + /// println!("Role assignment failed: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Role Hierarchy + /// + /// Available admin roles with their permission levels: + /// - **SuperAdmin**: All permissions, can assign other roles + /// - **MarketAdmin**: Market creation, closure, finalization, extension + /// - **ConfigAdmin**: Configuration updates and resets + /// - **FeeAdmin**: Fee configuration and collection + /// - **ReadOnlyAdmin**: View-only access to analytics + /// + /// # Assignment Process + /// + /// The assignment process: + /// 1. **Bootstrap Check**: First assignment bypasses permission validation + /// 2. **Permission Validation**: Subsequent assignments require EmergencyActions permission + /// 3. **Role Creation**: Creates AdminRoleAssignment with timestamp and permissions + /// 4. **Storage Update**: Stores assignment in persistent storage + /// 5. **Event Emission**: Emits role assignment event for monitoring + /// + /// # Security + /// + /// Only admins with EmergencyActions permission can assign roles to others. + /// The first admin assignment (bootstrapping) bypasses this check to enable + /// initial contract setup. pub fn assign_role( env: &Env, admin: &Address, @@ -316,7 +866,75 @@ impl AdminRoleManager { Ok(()) } - /// Get admin role + /// Retrieves the admin role assigned to a specific address. + /// + /// This function looks up the admin role for a given address, validating + /// that the admin is active and returning their assigned role. It's used + /// for permission checking and role-based access control. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The address to look up the admin role for + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(AdminRole)` - The admin role assigned to the address + /// - `Err(Error)` - Admin not found, inactive, or unauthorized + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - No admin role assignment found + /// - `Error::Unauthorized` - Admin role assignment is inactive + /// - `Error::Unauthorized` - Address doesn't match the assigned admin + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::{AdminRoleManager, AdminRole}; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Get admin role for permission checking + /// match AdminRoleManager::get_admin_role(&env, &admin) { + /// Ok(AdminRole::SuperAdmin) => { + /// println!("User has SuperAdmin privileges"); + /// }, + /// Ok(AdminRole::MarketAdmin) => { + /// println!("User has MarketAdmin privileges"); + /// }, + /// Ok(role) => { + /// println!("User has {:?} privileges", role); + /// }, + /// Err(e) => { + /// println!("No admin role found: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Role Validation + /// + /// The function performs these validations: + /// 1. **Assignment Lookup**: Retrieves role assignment from storage + /// 2. **Active Check**: Ensures the role assignment is active + /// 3. **Address Match**: Confirms the address matches the assignment + /// 4. **Role Return**: Returns the validated admin role + /// + /// # Use Cases + /// + /// - **Permission Checking**: Determine what actions an admin can perform + /// - **UI Authorization**: Show/hide features based on admin role + /// - **Audit Logging**: Record admin roles in action logs + /// - **Role-Based Logic**: Execute different logic based on admin role + /// - **Access Control**: Gate access to role-specific functionality + /// + /// # Performance + /// + /// This function performs a single storage lookup and is optimized for + /// frequent use in permission validation scenarios. pub fn get_admin_role(env: &Env, admin: &Address) -> Result { // Use a simple fixed key for admin role storage let key = Symbol::new(env, "admin_role"); @@ -339,7 +957,80 @@ impl AdminRoleManager { Ok(assignment.role) } - /// Check if admin has permission + /// Checks if a specific admin role has a particular permission. + /// + /// This function determines whether an admin role includes a specific + /// permission by checking the role's permission set. It's a core component + /// of the permission validation system. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment (unused but kept for consistency) + /// * `role` - The admin role to check permissions for + /// * `permission` - The specific permission to check + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(true)` - Role has the specified permission + /// - `Ok(false)` - Role does not have the specified permission + /// - `Err(Error)` - Error retrieving role permissions + /// + /// # Errors + /// + /// This function typically doesn't error but may return errors from + /// permission retrieval operations in future implementations. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::admin::{AdminRoleManager, AdminRole, AdminPermission}; + /// # let env = Env::default(); + /// + /// // Check if MarketAdmin can create markets + /// let can_create = AdminRoleManager::has_permission( + /// &env, + /// &AdminRole::MarketAdmin, + /// &AdminPermission::CreateMarket + /// ).unwrap(); + /// + /// if can_create { + /// println!("MarketAdmin can create markets"); + /// } + /// + /// // Check if ReadOnlyAdmin can update fees + /// let can_update_fees = AdminRoleManager::has_permission( + /// &env, + /// &AdminRole::ReadOnlyAdmin, + /// &AdminPermission::UpdateFees + /// ).unwrap(); + /// + /// assert!(!can_update_fees); // ReadOnlyAdmin cannot update fees + /// ``` + /// + /// # Permission Matrix + /// + /// | Role | Initialize | CreateMarket | UpdateFees | UpdateConfig | Emergency | + /// |------|------------|--------------|------------|--------------|----------| + /// | SuperAdmin | ✓ | ✓ | ✓ | ✓ | ✓ | + /// | MarketAdmin | ✗ | ✓ | ✗ | ✗ | ✗ | + /// | ConfigAdmin | ✗ | ✗ | ✗ | ✓ | ✗ | + /// | FeeAdmin | ✗ | ✗ | ✓ | ✗ | ✗ | + /// | ReadOnlyAdmin | ✗ | ✗ | ✗ | ✗ | ✗ | + /// + /// # Use Cases + /// + /// - **Permission Validation**: Core permission checking logic + /// - **Role Comparison**: Compare capabilities of different roles + /// - **UI Authorization**: Determine what UI elements to show + /// - **API Gating**: Control access to API endpoints + /// - **Audit Systems**: Log permission checks for security auditing + /// + /// # Performance + /// + /// This function is highly optimized for frequent use, performing only + /// in-memory operations on the role's permission vector. pub fn has_permission( _env: &Env, role: &AdminRole, @@ -349,7 +1040,84 @@ impl AdminRoleManager { Ok(permissions.contains(permission)) } - /// Get permissions for role + /// Retrieves the complete set of permissions for a specific admin role. + /// + /// This function returns all permissions associated with an admin role, + /// providing the definitive permission set for role-based access control. + /// It's used internally by permission checking functions and externally + /// for role analysis and UI generation. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for creating the permission vector + /// * `role` - The admin role to get permissions for + /// + /// # Returns + /// + /// Returns `Vec` containing all permissions for the role. + /// The vector is never empty - even ReadOnlyAdmin has ViewAnalytics permission. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::admin::{AdminRoleManager, AdminRole, AdminPermission}; + /// # let env = Env::default(); + /// + /// // Get all permissions for SuperAdmin + /// let super_permissions = AdminRoleManager::get_permissions_for_role( + /// &env, + /// &AdminRole::SuperAdmin + /// ); + /// + /// println!("SuperAdmin has {} permissions", super_permissions.len()); + /// assert!(super_permissions.contains(&AdminPermission::Initialize)); + /// assert!(super_permissions.contains(&AdminPermission::EmergencyActions)); + /// + /// // Get permissions for MarketAdmin + /// let market_permissions = AdminRoleManager::get_permissions_for_role( + /// &env, + /// &AdminRole::MarketAdmin + /// ); + /// + /// assert!(market_permissions.contains(&AdminPermission::CreateMarket)); + /// assert!(!market_permissions.contains(&AdminPermission::UpdateFees)); + /// ``` + /// + /// # Permission Sets by Role + /// + /// **SuperAdmin** (12 permissions): + /// - Initialize, CreateMarket, CloseMarket, FinalizeMarket + /// - ExtendMarket, UpdateFees, UpdateConfig, ResetConfig + /// - CollectFees, ManageDisputes, ViewAnalytics, EmergencyActions + /// + /// **MarketAdmin** (5 permissions): + /// - CreateMarket, CloseMarket, FinalizeMarket, ExtendMarket, ViewAnalytics + /// + /// **ConfigAdmin** (3 permissions): + /// - UpdateConfig, ResetConfig, ViewAnalytics + /// + /// **FeeAdmin** (3 permissions): + /// - UpdateFees, CollectFees, ViewAnalytics + /// + /// **ReadOnlyAdmin** (1 permission): + /// - ViewAnalytics + /// + /// # Use Cases + /// + /// - **Role Analysis**: Understand what each role can do + /// - **UI Generation**: Create role-specific interfaces + /// - **Permission Auditing**: Review and audit role permissions + /// - **Role Comparison**: Compare capabilities between roles + /// - **Documentation**: Generate permission documentation + /// - **Testing**: Validate role permission assignments + /// + /// # Design Principles + /// + /// - **Least Privilege**: Each role has only necessary permissions + /// - **Clear Hierarchy**: SuperAdmin > Specialized Admins > ReadOnly + /// - **Separation of Concerns**: Different roles for different responsibilities + /// - **Extensibility**: Easy to add new roles and permissions pub fn get_permissions_for_role(env: &Env, role: &AdminRole) -> Vec { match role { AdminRole::SuperAdmin => soroban_sdk::vec![ @@ -427,12 +1195,84 @@ impl AdminRoleManager { } // ===== ADMIN FUNCTIONS ===== - -/// Admin function management pub struct AdminFunctions; impl AdminFunctions { - /// Close market (admin only) + /// Closes a market before its natural end time (admin only). + /// + /// This function allows authorized admins to forcibly close a market, + /// preventing further voting and triggering the market closure process. + /// It's used for emergency situations or when markets need early termination. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address performing the closure (must have CloseMarket permission) + /// * `market_id` - Unique identifier of the market to close + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Market closed successfully + /// - `Err(Error)` - Closure failed due to permissions or validation + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Admin lacks CloseMarket permission + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - Authentication errors from AdminAccessControl + /// - Storage operation errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol}; + /// # use predictify_hybrid::admin::AdminFunctions; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "problematic_market"); + /// + /// // Close a problematic market + /// match AdminFunctions::close_market(&env, &admin, &market_id) { + /// Ok(()) => { + /// println!("Market closed successfully"); + /// }, + /// Err(e) => { + /// println!("Failed to close market: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Closure Process + /// + /// The closure process performs these steps: + /// 1. **Permission Validation**: Ensures admin has CloseMarket permission + /// 2. **Market Validation**: Confirms market exists and can be closed + /// 3. **Market Removal**: Removes market from active storage + /// 4. **Event Emission**: Emits market closure event for monitoring + /// 5. **Action Logging**: Records the admin action for audit trails + /// + /// # Use Cases + /// + /// - **Emergency Closure**: Close markets with problematic questions or outcomes + /// - **Policy Violations**: Close markets that violate platform policies + /// - **Technical Issues**: Close markets experiencing technical problems + /// - **Legal Compliance**: Close markets for regulatory compliance + /// - **Community Requests**: Close markets based on community feedback + /// + /// # Post-Closure State + /// + /// After closure: + /// - Market is removed from active storage + /// - No further voting is possible + /// - Existing stakes may need manual resolution + /// - Market appears as closed in historical records + /// + /// # Security + /// + /// This is a powerful admin function that should be used carefully. + /// Only admins with CloseMarket permission can execute this function. pub fn close_market( env: &Env, admin: &Address, @@ -458,7 +1298,85 @@ impl AdminFunctions { Ok(()) } - /// Finalize market with admin override + /// Finalizes a market with admin override of the resolution process. + /// + /// This function allows authorized admins to directly set the final outcome + /// of a market, bypassing the normal resolution process. It's used when + /// manual intervention is required for market resolution. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address performing the finalization (must have FinalizeMarket permission) + /// * `market_id` - Unique identifier of the market to finalize + /// * `outcome` - The final outcome to set for the market + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Market finalized successfully + /// - `Err(Error)` - Finalization failed due to permissions or validation + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Admin lacks FinalizeMarket permission + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - `Error::InvalidOutcome` - Outcome doesn't match market's possible outcomes + /// - `Error::MarketAlreadyResolved` - Market has already been finalized + /// - Resolution errors from MarketResolutionManager + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol, String}; + /// # use predictify_hybrid::admin::AdminFunctions; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "disputed_market"); + /// # let outcome = String::from_str(&env, "Yes"); + /// + /// // Finalize a disputed market with admin decision + /// match AdminFunctions::finalize_market(&env, &admin, &market_id, &outcome) { + /// Ok(()) => { + /// println!("Market finalized with outcome: {}", outcome); + /// }, + /// Err(e) => { + /// println!("Failed to finalize market: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Finalization Process + /// + /// The finalization process: + /// 1. **Permission Validation**: Ensures admin has FinalizeMarket permission + /// 2. **Market Resolution**: Uses MarketResolutionManager to set final outcome + /// 3. **Event Emission**: Emits market finalization event + /// 4. **Action Logging**: Records admin action with outcome details + /// + /// # Use Cases + /// + /// - **Dispute Resolution**: Resolve disputed markets with admin decision + /// - **Oracle Failures**: Finalize markets when oracles fail or are unavailable + /// - **Subjective Markets**: Resolve markets requiring human judgment + /// - **Emergency Resolution**: Quick resolution in time-sensitive situations + /// - **Correction**: Correct automated resolutions that were incorrect + /// + /// # Post-Finalization State + /// + /// After finalization: + /// - Market state changes to Resolved + /// - Winning outcome is permanently set + /// - Users can claim winnings based on the outcome + /// - Market statistics are finalized + /// - No further changes to the market are possible + /// + /// # Governance + /// + /// Admin finalization should follow established governance procedures + /// and be transparent to the community. Consider implementing multi-signature + /// requirements for high-value market finalizations. pub fn finalize_market( env: &Env, admin: &Address, @@ -483,7 +1401,98 @@ impl AdminFunctions { Ok(()) } - /// Extend market duration + /// Extends the duration of an active market (admin only). + /// + /// This function allows authorized admins to extend the voting period + /// of an active market by adding additional days to its end time. + /// Extensions require a reason for transparency and audit purposes. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address performing the extension (must have ExtendMarket permission) + /// * `market_id` - Unique identifier of the market to extend + /// * `additional_days` - Number of additional days to add to the market duration + /// * `reason` - Explanation for why the extension is needed + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Market duration extended successfully + /// - `Err(Error)` - Extension failed due to permissions or validation + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Admin lacks ExtendMarket permission + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - `Error::MarketClosed` - Market has already ended or been closed + /// - `Error::InvalidDuration` - Extension would exceed maximum allowed duration + /// - Extension errors from ExtensionManager + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol, String}; + /// # use predictify_hybrid::admin::AdminFunctions; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "active_market"); + /// # let reason = String::from_str(&env, "Low participation, extending for more votes"); + /// + /// // Extend market by 7 days due to low participation + /// match AdminFunctions::extend_market_duration( + /// &env, + /// &admin, + /// &market_id, + /// 7, + /// &reason + /// ) { + /// Ok(()) => { + /// println!("Market extended by 7 days"); + /// }, + /// Err(e) => { + /// println!("Failed to extend market: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Extension Process + /// + /// The extension process: + /// 1. **Permission Validation**: Ensures admin has ExtendMarket permission + /// 2. **Market Validation**: Confirms market exists and is extendable + /// 3. **Duration Extension**: Uses ExtensionManager to add additional time + /// 4. **Action Logging**: Records extension with reason for audit trail + /// + /// # Extension Limits + /// + /// Extensions are subject to limits: + /// - Maximum total extension days per market + /// - Maximum single extension duration + /// - Market must be in Active state + /// - Extensions cannot exceed platform limits + /// + /// # Use Cases + /// + /// - **Low Participation**: Extend markets with insufficient voting + /// - **Technical Issues**: Extend markets affected by technical problems + /// - **Community Requests**: Extend based on legitimate community requests + /// - **External Events**: Extend when external events affect market relevance + /// - **Oracle Delays**: Extend when oracle data will be delayed + /// + /// # Transparency + /// + /// All extensions are logged with reasons and are publicly visible. + /// The extension history is maintained for each market, providing + /// full transparency of admin interventions. + /// + /// # Best Practices + /// + /// - Provide clear, specific reasons for extensions + /// - Limit extensions to necessary cases + /// - Consider community feedback before extending + /// - Document extension policies and criteria pub fn extend_market_duration( env: &Env, admin: &Address, @@ -507,7 +1516,89 @@ impl AdminFunctions { Ok(()) } - /// Update fee configuration + /// Updates the platform fee configuration (admin only). + /// + /// This function allows authorized admins to modify the fee structure + /// used throughout the platform, including platform fees, creation fees, + /// and other fee-related parameters. Changes take effect immediately. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address performing the update (must have UpdateFees permission) + /// * `new_config` - The new fee configuration to apply + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(FeeConfig)` - Updated fee configuration + /// - `Err(Error)` - Update failed due to permissions or validation + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Admin lacks UpdateFees permission + /// - `Error::InvalidInput` - Fee configuration contains invalid values + /// - Fee validation errors from FeeManager + /// - Storage operation errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminFunctions; + /// # use predictify_hybrid::fees::FeeConfig; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let new_config = FeeConfig { + /// # platform_fee_percentage: 250, // 2.5% + /// # creation_fee: 1000000, // 1 XLM + /// # min_stake: 100000, // 0.1 XLM + /// # }; + /// + /// // Update platform fees + /// match AdminFunctions::update_fee_config(&env, &admin, &new_config) { + /// Ok(updated_config) => { + /// println!("Fees updated successfully"); + /// println!("New platform fee: {}%", updated_config.platform_fee_percentage / 100); + /// }, + /// Err(e) => { + /// println!("Failed to update fees: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Fee Configuration Parameters + /// + /// The FeeConfig struct typically includes: + /// - **Platform Fee Percentage**: Fee taken from winning payouts (basis points) + /// - **Creation Fee**: Fee required to create new markets + /// - **Minimum Stake**: Minimum amount required for voting + /// - **Maximum Fee Cap**: Upper limit on total fees + /// + /// # Update Process + /// + /// The update process: + /// 1. **Permission Validation**: Ensures admin has UpdateFees permission + /// 2. **Configuration Validation**: Validates new fee parameters + /// 3. **Fee Update**: Uses FeeManager to apply new configuration + /// 4. **Action Logging**: Records fee update for audit trail + /// + /// # Impact and Considerations + /// + /// Fee updates have immediate platform-wide effects: + /// - New markets use updated creation fees + /// - Existing market resolutions use updated platform fees + /// - User interfaces should reflect new fee structure + /// - Consider gradual rollout for major fee changes + /// + /// # Best Practices + /// + /// - Announce fee changes to the community in advance + /// - Test fee changes on testnet before mainnet deployment + /// - Monitor platform activity after fee changes + /// - Keep fees competitive with similar platforms + /// - Document rationale for fee changes pub fn update_fee_config( env: &Env, admin: &Address, @@ -528,7 +1619,100 @@ impl AdminFunctions { Ok(updated_config) } - /// Update contract configuration + /// Updates the core contract configuration (admin only). + /// + /// This function allows authorized admins to modify fundamental contract + /// settings including market limits, validation thresholds, oracle timeouts, + /// and other operational parameters. Changes affect all contract operations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address performing the update (must have UpdateConfig permission) + /// * `new_config` - The new contract configuration to apply + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Configuration updated successfully + /// - `Err(Error)` - Update failed due to permissions or validation + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Admin lacks UpdateConfig permission + /// - `Error::InvalidInput` - Configuration contains invalid values + /// - Configuration validation errors from ConfigManager + /// - Storage operation errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminFunctions; + /// # use predictify_hybrid::config::{ContractConfig, Environment}; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let new_config = ContractConfig { + /// # environment: Environment::Mainnet, + /// # max_market_duration_days: 365, + /// # min_market_duration_days: 1, + /// # max_outcomes_per_market: 10, + /// # oracle_timeout_seconds: 3600, + /// # }; + /// + /// // Update contract configuration for mainnet + /// match AdminFunctions::update_contract_config(&env, &admin, &new_config) { + /// Ok(()) => { + /// println!("Contract configuration updated successfully"); + /// }, + /// Err(e) => { + /// println!("Failed to update configuration: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Configuration Parameters + /// + /// The ContractConfig typically includes: + /// - **Environment**: Target deployment environment (Development/Testnet/Mainnet) + /// - **Market Limits**: Duration limits, outcome limits, participation limits + /// - **Validation Thresholds**: Minimum stakes, consensus requirements + /// - **Oracle Settings**: Timeout values, retry limits, fallback options + /// - **Extension Limits**: Maximum extensions per market, total extension days + /// + /// # Update Process + /// + /// The configuration update process: + /// 1. **Permission Validation**: Ensures admin has UpdateConfig permission + /// 2. **Configuration Validation**: Validates all configuration parameters + /// 3. **Config Update**: Uses ConfigManager to store new configuration + /// 4. **Environment Detection**: Determines and logs environment type + /// 5. **Action Logging**: Records configuration change for audit trail + /// + /// # Impact Assessment + /// + /// Configuration changes can have significant impacts: + /// - **Market Creation**: New limits apply to future markets + /// - **Existing Markets**: Some changes may affect active markets + /// - **Oracle Integration**: Timeout changes affect oracle reliability + /// - **User Experience**: Limits affect what users can do + /// + /// # Environment-Specific Considerations + /// + /// Different environments have different optimal settings: + /// - **Development**: Relaxed limits for testing + /// - **Testnet**: Production-like but with test-friendly parameters + /// - **Mainnet**: Strict, secure, production-optimized settings + /// + /// # Change Management + /// + /// For production deployments: + /// - Test configuration changes thoroughly + /// - Consider gradual rollout strategies + /// - Monitor system behavior after changes + /// - Have rollback procedures ready + /// - Document all configuration changes pub fn update_contract_config( env: &Env, admin: &Address, @@ -547,7 +1731,100 @@ impl AdminFunctions { Ok(()) } - /// Reset configuration to defaults + /// Resets the contract configuration to default values (admin only). + /// + /// This function allows authorized admins to restore the contract configuration + /// to its default state, effectively undoing all previous configuration changes. + /// This is useful for recovery scenarios or returning to known-good settings. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The admin address performing the reset (must have ResetConfig permission) + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(ContractConfig)` - The default configuration that was applied + /// - `Err(Error)` - Reset failed due to permissions or system errors + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::Unauthorized` - Admin lacks ResetConfig permission + /// - Configuration reset errors from ConfigManager + /// - Storage operation errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminFunctions; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Reset configuration to defaults after problematic changes + /// match AdminFunctions::reset_config_to_defaults(&env, &admin) { + /// Ok(default_config) => { + /// println!("Configuration reset to defaults successfully"); + /// println!("Environment: {:?}", default_config.environment); + /// }, + /// Err(e) => { + /// println!("Failed to reset configuration: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Default Configuration + /// + /// The default configuration typically includes: + /// - **Environment**: Development (safest default) + /// - **Market Duration**: 1-30 days (conservative range) + /// - **Outcomes Limit**: 2-5 outcomes per market + /// - **Oracle Timeout**: 1 hour (reasonable default) + /// - **Extension Limits**: 7 days maximum extension + /// + /// # Reset Process + /// + /// The reset process: + /// 1. **Permission Validation**: Ensures admin has ResetConfig permission + /// 2. **Default Retrieval**: Gets default configuration from ConfigManager + /// 3. **Configuration Reset**: Applies default configuration + /// 4. **Action Logging**: Records reset action for audit trail + /// 5. **Return Defaults**: Returns the applied default configuration + /// + /// # Use Cases + /// + /// Configuration reset is useful for: + /// - **Recovery**: Recovering from problematic configuration changes + /// - **Debugging**: Isolating issues by returning to known-good state + /// - **Maintenance**: Periodic reset to clean configuration state + /// - **Environment Migration**: Resetting before environment-specific setup + /// - **Emergency Response**: Quick restoration during incidents + /// + /// # Impact and Considerations + /// + /// Resetting configuration affects: + /// - **Active Markets**: May change behavior of ongoing markets + /// - **User Limits**: Changes what users can do immediately + /// - **Oracle Integration**: May affect oracle timeout behavior + /// - **Platform Behavior**: Returns all settings to baseline + /// + /// # Best Practices + /// + /// - Use reset as a last resort after other fixes fail + /// - Announce configuration resets to users + /// - Monitor system behavior after reset + /// - Document why reset was necessary + /// - Consider partial configuration fixes before full reset + /// + /// # Recovery Procedures + /// + /// After reset, you may need to: + /// - Reconfigure environment-specific settings + /// - Update fee structures if needed + /// - Verify oracle integrations work correctly + /// - Test market creation and resolution pub fn reset_config_to_defaults( env: &Env, admin: &Address, @@ -567,18 +1844,167 @@ impl AdminFunctions { // ===== ADMIN VALIDATION ===== -/// Admin validation utilities +/// Administrative validation utilities for contract operations. +/// +/// The `AdminValidator` provides validation functions to ensure admin operations +/// are performed correctly and safely. These utilities validate admin addresses, +/// contract initialization state, and action parameters before execution. +/// +/// # Purpose +/// +/// This struct centralizes validation logic for: +/// - Admin address format and validity +/// - Contract initialization state checks +/// - Admin action parameter validation +/// - Input sanitization and security checks +/// +/// # Usage Pattern +/// +/// AdminValidator functions are typically called before performing admin operations +/// to ensure all preconditions are met and inputs are valid. pub struct AdminValidator; impl AdminValidator { - /// Validate admin address + /// Validates the format and basic properties of an admin address. + /// + /// This function performs basic validation on admin addresses to ensure they + /// meet the requirements for administrative operations. Currently implements + /// a placeholder validation due to Soroban SDK limitations. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment (currently unused) + /// * `_admin` - The admin address to validate + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Address validation passed + /// - `Err(Error)` - Address validation failed + /// + /// # Current Implementation + /// + /// The current implementation always returns `Ok(())` due to limitations + /// in the Soroban SDK that make it difficult to perform comprehensive + /// address validation. Future versions may include: + /// - Address format validation + /// - Address existence checks + /// - Blacklist validation + /// - Multi-signature validation + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminValidator; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Validate admin address before operations + /// match AdminValidator::validate_admin_address(&env, &admin) { + /// Ok(()) => { + /// println!("Admin address is valid"); + /// // Proceed with admin operation + /// }, + /// Err(e) => { + /// println!("Invalid admin address: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Future Enhancements + /// + /// When SDK capabilities improve, this function may validate: + /// - Address format compliance with Stellar standards + /// - Address existence on the network + /// - Address not in blacklist/blocklist + /// - Multi-signature threshold requirements + /// - Address activity and reputation metrics + /// + /// # Security Considerations + /// + /// While this function currently provides minimal validation, + /// it serves as a placeholder for future security enhancements. + /// Always combine with proper authentication using `require_auth()`. pub fn validate_admin_address(_env: &Env, _admin: &Address) -> Result<(), Error> { // For now, skip validation since we can't easily convert Address to string // This is a limitation of the current Soroban SDK Ok(()) } - /// Validate contract not already initialized + /// Validates that the contract has not been previously initialized. + /// + /// This function checks the contract's persistent storage to ensure that + /// initialization has not already occurred. This prevents double-initialization + /// which could lead to security vulnerabilities or data corruption. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for storage access + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Contract is not initialized (safe to initialize) + /// - `Err(Error::InvalidState)` - Contract is already initialized + /// + /// # Validation Logic + /// + /// The function checks for the existence of the "Admin" key in persistent + /// storage. If this key exists, it indicates the contract has been initialized + /// with an admin, making further initialization invalid. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::admin::AdminValidator; + /// # let env = Env::default(); + /// + /// // Check if contract can be initialized + /// match AdminValidator::validate_contract_not_initialized(&env) { + /// Ok(()) => { + /// println!("Contract is ready for initialization"); + /// // Proceed with initialization + /// }, + /// Err(e) => { + /// println!("Contract already initialized: {:?}", e); + /// // Handle already-initialized state + /// } + /// } + /// ``` + /// + /// # Security Importance + /// + /// This validation is critical for security because: + /// - **Prevents Admin Takeover**: Stops malicious re-initialization attempts + /// - **Maintains State Integrity**: Preserves existing configuration and data + /// - **Enforces Single Initialization**: Ensures contract follows proper lifecycle + /// - **Protects Existing Users**: Prevents disruption of active markets and users + /// + /// # Integration with Initialization + /// + /// This function should be called at the beginning of any initialization + /// function before making any state changes: + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::{AdminValidator, AdminInitializer}; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Safe initialization pattern + /// AdminValidator::validate_contract_not_initialized(&env)?; + /// AdminInitializer::initialize_contract(&env, &admin)?; + /// ``` + /// + /// # Error Handling + /// + /// When this validation fails, the calling function should: + /// - Return the error immediately (don't proceed) + /// - Log the attempted double-initialization + /// - Consider it a potential security incident + /// - Provide clear error messages to legitimate callers pub fn validate_contract_not_initialized(env: &Env) -> Result<(), Error> { let admin_exists = env .storage() @@ -592,7 +2018,119 @@ impl AdminValidator { Ok(()) } - /// Validate admin action parameters + /// Validates parameters for specific admin actions. + /// + /// This function performs action-specific parameter validation to ensure + /// that admin operations receive valid inputs. Each action type has its + /// own validation rules and required parameters. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for string operations + /// * `action` - The admin action being performed (e.g., "close_market") + /// * `parameters` - Map of parameter names to values for the action + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - All parameters are valid for the specified action + /// - `Err(Error::InvalidInput)` - One or more parameters are invalid + /// + /// # Supported Actions + /// + /// ## close_market + /// - **Required**: `market_id` - Non-empty market identifier + /// + /// ## finalize_market + /// - **Required**: `market_id` - Non-empty market identifier + /// - **Required**: `outcome` - Non-empty winning outcome + /// + /// ## extend_market + /// - **Required**: `market_id` - Non-empty market identifier + /// - **Required**: `additional_days` - Non-empty extension duration + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Map, String}; + /// # use predictify_hybrid::admin::AdminValidator; + /// # let env = Env::default(); + /// # let mut params = Map::new(&env); + /// # params.set( + /// # String::from_str(&env, "market_id"), + /// # String::from_str(&env, "market_123") + /// # ); + /// # params.set( + /// # String::from_str(&env, "outcome"), + /// # String::from_str(&env, "Yes") + /// # ); + /// + /// // Validate parameters for market finalization + /// match AdminValidator::validate_action_parameters( + /// &env, + /// "finalize_market", + /// ¶ms + /// ) { + /// Ok(()) => { + /// println!("Parameters are valid for market finalization"); + /// // Proceed with finalization + /// }, + /// Err(e) => { + /// println!("Invalid parameters: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Validation Rules + /// + /// ### Market ID Validation + /// - Must be present in parameters + /// - Must not be empty string + /// - Should correspond to existing market (checked elsewhere) + /// + /// ### Outcome Validation (for finalize_market) + /// - Must be present in parameters + /// - Must not be empty string + /// - Should be valid outcome for the market (checked elsewhere) + /// + /// ### Additional Days Validation (for extend_market) + /// - Must be present in parameters + /// - Must not be empty string + /// - Should be valid positive number (parsed elsewhere) + /// + /// # Error Conditions + /// + /// This function returns `Error::InvalidInput` when: + /// - Required parameters are missing from the map + /// - Required parameters have empty string values + /// - Parameter format is invalid (future enhancement) + /// + /// # Integration with Action Logging + /// + /// This validation is typically called before logging admin actions + /// to ensure only valid actions are recorded: + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Map}; + /// # use predictify_hybrid::admin::{AdminValidator, AdminActionLogger}; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let action = "close_market"; + /// # let params = Map::new(&env); + /// + /// // Validate before logging + /// AdminValidator::validate_action_parameters(&env, action, ¶ms)?; + /// AdminActionLogger::log_action(&env, &admin, action, None, params, true, None)?; + /// ``` + /// + /// # Future Enhancements + /// + /// Future versions may include: + /// - Type-specific validation (numbers, dates, etc.) + /// - Cross-parameter validation rules + /// - Custom validation for new action types + /// - Parameter sanitization and normalization + /// - Advanced security checks (injection prevention) pub fn validate_action_parameters( env: &Env, action: &str, @@ -633,11 +2171,146 @@ impl AdminValidator { // ===== ADMIN ACTION LOGGING ===== -/// Admin action logging +/// Administrative action logging and audit trail management. +/// +/// The `AdminActionLogger` provides comprehensive logging capabilities for all +/// administrative actions performed on the contract. This creates an immutable +/// audit trail for governance, compliance, and security monitoring. +/// +/// # Purpose +/// +/// This struct handles: +/// - Recording all admin actions with full context +/// - Creating audit trails for compliance +/// - Emitting events for external monitoring +/// - Providing action history retrieval +/// - Supporting forensic analysis and debugging +/// +/// # Audit Trail Components +/// +/// Each logged action includes: +/// - **Admin Identity**: Who performed the action +/// - **Action Type**: What operation was performed +/// - **Target**: What was affected (market ID, config, etc.) +/// - **Parameters**: Detailed action parameters +/// - **Timestamp**: When the action occurred +/// - **Success Status**: Whether the action succeeded +/// - **Error Details**: Failure reasons if applicable +/// +/// # Security and Compliance +/// +/// The logging system supports: +/// - Regulatory compliance requirements +/// - Security incident investigation +/// - Governance transparency +/// - Operational monitoring and alerting pub struct AdminActionLogger; impl AdminActionLogger { - /// Log admin action + /// Records an administrative action in the audit trail. + /// + /// This function creates a comprehensive record of admin actions including + /// all relevant context, parameters, and outcomes. The record is stored + /// persistently and an event is emitted for external monitoring. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for storage and events + /// * `admin` - The admin address that performed the action + /// * `action` - The type of action performed (e.g., "close_market") + /// * `target` - Optional target identifier (e.g., market ID) + /// * `parameters` - Map of action parameters and their values + /// * `success` - Whether the action completed successfully + /// * `error_message` - Optional error description if action failed + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Action logged successfully + /// - `Err(Error)` - Logging failed due to storage or event errors + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Map, String}; + /// # use predictify_hybrid::admin::AdminActionLogger; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let mut params = Map::new(&env); + /// # params.set( + /// # String::from_str(&env, "market_id"), + /// # String::from_str(&env, "market_123") + /// # ); + /// # params.set( + /// # String::from_str(&env, "outcome"), + /// # String::from_str(&env, "Yes") + /// # ); + /// + /// // Log successful market finalization + /// match AdminActionLogger::log_action( + /// &env, + /// &admin, + /// "finalize_market", + /// Some(String::from_str(&env, "market_123")), + /// params, + /// true, + /// None + /// ) { + /// Ok(()) => { + /// println!("Action logged successfully"); + /// }, + /// Err(e) => { + /// println!("Failed to log action: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Action Types + /// + /// Common action types include: + /// - **Market Operations**: "close_market", "finalize_market", "extend_market" + /// - **Configuration**: "update_config", "update_fees", "reset_config" + /// - **Role Management**: "assign_role", "revoke_role", "update_permissions" + /// - **System Operations**: "initialize_contract", "emergency_pause" + /// + /// # Storage Strategy + /// + /// The current implementation stores actions using a simple key-value approach. + /// In production, consider: + /// - Time-based partitioning for scalability + /// - Indexed storage for efficient queries + /// - Archival strategies for long-term retention + /// - Compression for storage efficiency + /// + /// # Event Emission + /// + /// Each logged action emits an event containing: + /// - Admin address + /// - Action type + /// - Success status + /// - Timestamp (from ledger) + /// + /// External systems can subscribe to these events for: + /// - Real-time monitoring + /// - Automated alerting + /// - Integration with external audit systems + /// - Dashboard updates + /// + /// # Error Handling + /// + /// Logging failures should be handled carefully: + /// - Don't fail the main operation if logging fails + /// - Consider alternative logging mechanisms + /// - Alert on persistent logging failures + /// - Maintain operation continuity + /// + /// # Best Practices + /// + /// - Log all significant admin actions + /// - Include sufficient context for investigation + /// - Use consistent action naming conventions + /// - Sanitize sensitive parameters before logging + /// - Monitor log storage usage and implement rotation pub fn log_action( env: &Env, admin: &Address, @@ -667,14 +2340,198 @@ impl AdminActionLogger { Ok(()) } - /// Get admin actions + /// Retrieves a list of all administrative actions from the audit trail. + /// + /// This function provides access to the complete history of administrative + /// actions for audit, compliance, and analysis purposes. Currently returns + /// an empty vector due to storage iteration limitations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for storage access + /// * `_limit` - Maximum number of actions to retrieve (currently unused) + /// + /// # Returns + /// + /// Returns `Result, Error>` where: + /// - `Ok(Vec)` - List of admin actions (currently empty) + /// - `Err(Error)` - Retrieval failed due to storage errors + /// + /// # Current Limitations + /// + /// The current implementation returns an empty vector because: + /// - Soroban SDK lacks efficient storage iteration capabilities + /// - Actions are stored individually without indexing + /// - No built-in pagination or filtering mechanisms + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::admin::AdminActionLogger; + /// # let env = Env::default(); + /// + /// // Retrieve recent admin actions for audit + /// match AdminActionLogger::get_admin_actions(&env, 50) { + /// Ok(actions) => { + /// println!("Found {} admin actions", actions.len()); + /// for action in actions { + /// println!("Action: {} by {:?} at {}", + /// action.action, action.admin, action.timestamp); + /// } + /// }, + /// Err(e) => { + /// println!("Failed to retrieve actions: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Future Implementation + /// + /// A production implementation would include: + /// - **Indexed Storage**: Actions indexed by timestamp, admin, type + /// - **Pagination**: Efficient pagination with cursor-based navigation + /// - **Filtering**: Filter by date range, admin, action type, success status + /// - **Sorting**: Sort by timestamp, admin, or action type + /// - **Aggregation**: Summary statistics and trend analysis + /// + /// # Proposed Storage Schema + /// + /// ```rust + /// // Time-based partitioning + /// let partition_key = format!("actions_{}", timestamp / PARTITION_SIZE); + /// + /// // Admin-based indexing + /// let admin_index = format!("admin_actions_{}", admin); + /// + /// // Action type indexing + /// let type_index = format!("action_type_{}", action_type); + /// ``` + /// + /// # Use Cases + /// + /// This function supports: + /// - **Compliance Audits**: Providing complete action history + /// - **Security Analysis**: Investigating suspicious patterns + /// - **Operational Review**: Understanding admin activity patterns + /// - **Debugging**: Tracing the sequence of admin operations + /// - **Reporting**: Generating admin activity reports + /// + /// # Performance Considerations + /// + /// When implementing full functionality: + /// - Implement pagination to avoid large result sets + /// - Use appropriate caching for frequently accessed data + /// - Consider read replicas for heavy audit workloads + /// - Implement query optimization for common access patterns pub fn get_admin_actions(env: &Env, _limit: u32) -> Result, Error> { // For now, return empty vector since we don't have a way to iterate over storage // In a real implementation, you would store actions in a more sophisticated way Ok(Vec::new(env)) } - /// Get admin actions for specific admin + /// Retrieves administrative actions performed by a specific admin. + /// + /// This function provides filtered access to the audit trail, showing only + /// actions performed by a particular admin address. Useful for individual + /// admin accountability and performance analysis. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for storage access + /// * `_admin` - The admin address to filter actions for + /// * `_limit` - Maximum number of actions to retrieve (currently unused) + /// + /// # Returns + /// + /// Returns `Result, Error>` where: + /// - `Ok(Vec)` - List of actions by the specified admin (currently empty) + /// - `Err(Error)` - Retrieval failed due to storage errors + /// + /// # Current Limitations + /// + /// Similar to `get_admin_actions`, this function currently returns an empty + /// vector due to Soroban SDK storage iteration limitations. A full implementation + /// would require indexed storage and efficient filtering capabilities. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::admin::AdminActionLogger; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// // Get actions performed by a specific admin + /// match AdminActionLogger::get_admin_actions_for_admin(&env, &admin, 25) { + /// Ok(actions) => { + /// println!("Admin performed {} actions", actions.len()); + /// for action in actions { + /// println!("{}: {} ({})", + /// action.timestamp, + /// action.action, + /// if action.success { "Success" } else { "Failed" } + /// ); + /// } + /// }, + /// Err(e) => { + /// println!("Failed to retrieve admin actions: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Use Cases + /// + /// This function is valuable for: + /// - **Individual Accountability**: Tracking specific admin's actions + /// - **Performance Review**: Analyzing admin activity and success rates + /// - **Security Investigation**: Investigating suspicious admin behavior + /// - **Training**: Reviewing new admin's learning progress + /// - **Compliance**: Demonstrating individual admin compliance + /// + /// # Future Implementation Strategy + /// + /// A production implementation would include: + /// + /// ## Indexed Storage + /// ```rust + /// // Store actions with admin-based indexing + /// let admin_key = format!("admin_{}_{}", admin, timestamp); + /// env.storage().persistent().set(&admin_key, &action); + /// + /// // Maintain admin action count + /// let count_key = format!("admin_count_{}", admin); + /// let current_count: u32 = env.storage().persistent().get(&count_key).unwrap_or(0); + /// env.storage().persistent().set(&count_key, &(current_count + 1)); + /// ``` + /// + /// ## Efficient Querying + /// - Range queries by timestamp + /// - Pagination with cursor-based navigation + /// - Filtering by action type and success status + /// - Sorting options (newest first, oldest first) + /// + /// ## Analytics Integration + /// - Success rate calculation + /// - Action frequency analysis + /// - Time-based activity patterns + /// - Comparison with other admins + /// + /// # Security Considerations + /// + /// When implementing full functionality: + /// - Ensure proper access control (admins can only see their own actions unless super admin) + /// - Sanitize sensitive information in returned data + /// - Implement rate limiting to prevent abuse + /// - Log access to audit logs for meta-auditing + /// + /// # Performance Optimization + /// + /// For high-volume environments: + /// - Implement caching for frequently accessed admin histories + /// - Use background processes for heavy analytics + /// - Consider read replicas for audit queries + /// - Implement data archival for old actions pub fn get_admin_actions_for_admin( env: &Env, _admin: &Address, diff --git a/contracts/predictify-hybrid/src/config.rs b/contracts/predictify-hybrid/src/config.rs index 33b20308..fb2015f6 100644 --- a/contracts/predictify-hybrid/src/config.rs +++ b/contracts/predictify-hybrid/src/config.rs @@ -141,161 +141,1007 @@ pub const ORACLE_STATS_STORAGE_KEY: &str = "OracleStats"; // ===== CONFIGURATION STRUCTS ===== -/// Environment type enumeration +/// Deployment environment specification for the Predictify Hybrid contract. +/// +/// This enum defines the different environments where the contract can be deployed, +/// each with its own configuration parameters, security settings, and operational +/// characteristics. The environment determines fee structures, validation rules, +/// and network-specific behaviors. +/// +/// # Environment Characteristics +/// +/// Each environment is optimized for different use cases: +/// - **Development**: Relaxed rules for testing and development +/// - **Testnet**: Production-like environment for integration testing +/// - **Mainnet**: Full production environment with strict security +/// - **Custom**: Flexible environment for specialized deployments +/// +/// # Usage in Configuration +/// +/// The environment setting affects: +/// - Fee structures and minimum stakes +/// - Validation thresholds and limits +/// - Oracle timeout and retry settings +/// - Market duration and extension rules +/// - Security and permission requirements +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::config::Environment; +/// +/// // Environment comparison and selection +/// let current_env = Environment::Mainnet; +/// +/// match current_env { +/// Environment::Development => { +/// println!("Using development settings with relaxed rules"); +/// }, +/// Environment::Testnet => { +/// println!("Using testnet settings for integration testing"); +/// }, +/// Environment::Mainnet => { +/// println!("Using production settings with full security"); +/// }, +/// Environment::Custom => { +/// println!("Using custom environment configuration"); +/// } +/// } +/// ``` #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[contracttype] pub enum Environment { - /// Development environment + /// Development environment with relaxed validation and low fees. + /// + /// Characteristics: + /// - Minimal fees for easy testing + /// - Relaxed validation rules + /// - Short timeouts for faster iteration + /// - Permissive market creation limits + /// - Debug-friendly error messages Development, - /// Testnet environment + + /// Testnet environment that mirrors production settings. + /// + /// Characteristics: + /// - Production-like fee structures + /// - Full validation enabled + /// - Realistic timeouts and limits + /// - Comprehensive testing capabilities + /// - Integration testing support Testnet, - /// Mainnet environment + + /// Production mainnet environment with full security. + /// + /// Characteristics: + /// - Optimized fee structures + /// - Strict validation and security + /// - Production timeouts and limits + /// - Maximum security features + /// - Audit-ready configuration Mainnet, - /// Custom environment + + /// Custom environment for specialized deployments. + /// + /// Characteristics: + /// - Configurable parameters + /// - Flexible validation rules + /// - Custom fee structures + /// - Specialized use case support + /// - Enterprise deployment ready Custom, } -/// Network configuration +/// Network-specific configuration for Stellar blockchain connectivity. +/// +/// This struct contains all the network-related parameters required for the +/// contract to operate correctly on different Stellar networks. It includes +/// environment settings, connection details, and network identifiers. +/// +/// # Purpose +/// +/// NetworkConfig enables: +/// - Multi-network deployment support +/// - Environment-specific network settings +/// - RPC endpoint configuration +/// - Network identity verification +/// - Contract address management +/// +/// # Usage Scenarios +/// +/// - **Development**: Local Stellar network or Futurenet +/// - **Testing**: Stellar Testnet with test tokens +/// - **Production**: Stellar Mainnet with real assets +/// - **Custom**: Private or consortium networks +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::config::{NetworkConfig, Environment}; +/// # let env = Env::default(); +/// # let contract_addr = Address::generate(&env); +/// +/// // Create mainnet network configuration +/// let mainnet_config = NetworkConfig { +/// environment: Environment::Mainnet, +/// passphrase: String::from_str(&env, "Public Global Stellar Network ; September 2015"), +/// rpc_url: String::from_str(&env, "https://horizon.stellar.org"), +/// network_id: String::from_str(&env, "mainnet"), +/// contract_address: contract_addr, +/// }; +/// +/// println!("Configured for {} environment", +/// match mainnet_config.environment { +/// Environment::Mainnet => "production", +/// Environment::Testnet => "testing", +/// Environment::Development => "development", +/// Environment::Custom => "custom", +/// } +/// ); +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct NetworkConfig { - /// Network environment + /// The deployment environment (Development, Testnet, Mainnet, Custom). + /// + /// This determines which network-specific settings and validation + /// rules are applied throughout the contract. pub environment: Environment, - /// Network passphrase + + /// Stellar network passphrase for transaction signing. + /// + /// Standard passphrases: + /// - Mainnet: "Public Global Stellar Network ; September 2015" + /// - Testnet: "Test SDF Network ; September 2015" + /// - Development: Custom passphrase for local networks pub passphrase: String, - /// RPC URL + + /// RPC endpoint URL for blockchain interactions. + /// + /// Examples: + /// - Mainnet: "https://horizon.stellar.org" + /// - Testnet: "https://horizon-testnet.stellar.org" + /// - Development: "http://localhost:8000" pub rpc_url: String, - /// Network ID + + /// Network identifier for configuration management. + /// + /// Used for: + /// - Configuration file organization + /// - Network-specific caching + /// - Deployment tracking + /// - Environment validation pub network_id: String, - /// Contract deployment address + + /// The deployed contract's address on this network. + /// + /// This address is used for: + /// - Contract invocation + /// - Event filtering + /// - Cross-contract communication + /// - Network verification pub contract_address: Address, } -/// Fee configuration +/// Comprehensive fee structure configuration for the prediction platform. +/// +/// This struct defines all fee-related parameters that govern the economic +/// model of the prediction market platform. It includes platform fees, +/// creation costs, limits, and collection thresholds. +/// +/// # Fee Types +/// +/// The platform implements several fee mechanisms: +/// - **Platform Fees**: Percentage taken from winning payouts +/// - **Creation Fees**: Fixed cost to create new markets +/// - **Minimum/Maximum Limits**: Bounds on fee amounts +/// - **Collection Thresholds**: When fees are automatically collected +/// +/// # Economic Model +/// +/// Fees serve multiple purposes: +/// - Platform sustainability and development funding +/// - Spam prevention through creation costs +/// - Market quality incentives +/// - Oracle and infrastructure costs +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::config::FeeConfig; +/// +/// // Create a balanced fee configuration +/// let fee_config = FeeConfig { +/// platform_fee_percentage: 250, // 2.5% of winnings +/// creation_fee: 10_000_000, // 1 XLM to create market +/// min_fee_amount: 1_000_000, // 0.1 XLM minimum +/// max_fee_amount: 100_000_000, // 10 XLM maximum +/// collection_threshold: 50_000_000, // Collect at 5 XLM +/// fees_enabled: true, // Fees are active +/// }; +/// +/// // Calculate platform fee for a 100 XLM payout +/// let payout = 1_000_000_000; // 100 XLM +/// let platform_fee = (payout * fee_config.platform_fee_percentage) / 10000; +/// println!("Platform fee: {} stroops", platform_fee); // 25 XLM +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct FeeConfig { - /// Platform fee percentage + /// Platform fee percentage in basis points (1/100th of a percent). + /// + /// This fee is taken from winning payouts and represents the platform's + /// revenue. Examples: + /// - 250 = 2.5% fee + /// - 500 = 5.0% fee + /// - 1000 = 10.0% fee + /// + /// Range: 0-1000 (0% to 10%) pub platform_fee_percentage: i128, - /// Market creation fee + + /// Fixed fee required to create a new prediction market (in stroops). + /// + /// This fee prevents spam market creation and covers: + /// - Oracle setup costs + /// - Storage and computational resources + /// - Market validation and moderation + /// + /// Typical values: + /// - Development: 1_000_000 (0.1 XLM) + /// - Testnet: 10_000_000 (1 XLM) + /// - Mainnet: 50_000_000 (5 XLM) pub creation_fee: i128, - /// Minimum fee amount + + /// Minimum fee amount that can be charged (in stroops). + /// + /// Ensures fees are meaningful and cover basic operational costs. + /// Prevents dust fees that could clog the system. pub min_fee_amount: i128, - /// Maximum fee amount + + /// Maximum fee amount that can be charged (in stroops). + /// + /// Protects users from excessive fees on large markets. + /// Provides predictable cost ceiling for high-value markets. pub max_fee_amount: i128, - /// Fee collection threshold + + /// Threshold amount for automatic fee collection (in stroops). + /// + /// When accumulated fees reach this threshold, they are automatically + /// collected to reduce gas costs and improve efficiency. pub collection_threshold: i128, - /// Whether fees are enabled + + /// Global flag to enable or disable all fee collection. + /// + /// When false: + /// - No platform fees are charged + /// - Creation fees may still apply (depends on implementation) + /// - Useful for promotional periods or testing pub fees_enabled: bool, } -/// Voting configuration +/// Voting and dispute mechanism configuration for prediction markets. +/// +/// This struct defines the parameters that govern how users can vote on market +/// outcomes and dispute resolutions. It includes stake requirements, thresholds +/// for different market sizes, and dispute handling parameters. +/// +/// # Voting Mechanics +/// +/// The voting system supports: +/// - **Stake-weighted voting**: Higher stakes have more influence +/// - **Dispute mechanisms**: Challenge incorrect resolutions +/// - **Dynamic thresholds**: Adjust based on market size and activity +/// - **Time extensions**: Allow additional time for disputes +/// +/// # Economic Incentives +/// +/// Voting configuration balances: +/// - Participation incentives through reasonable minimum stakes +/// - Spam prevention through dispute costs +/// - Proportional influence based on market size +/// - Fair dispute resolution processes +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::config::VotingConfig; +/// +/// // Create balanced voting configuration +/// let voting_config = VotingConfig { +/// min_vote_stake: 1_000_000, // 0.1 XLM minimum vote +/// min_dispute_stake: 10_000_000, // 1 XLM minimum dispute +/// max_dispute_threshold: 100_000_000, // 10 XLM max dispute cost +/// base_dispute_threshold: 10_000_000, // 1 XLM base dispute cost +/// large_market_threshold: 1_000_000_000, // 100 XLM = large market +/// high_activity_threshold: 100, // 100+ votes = high activity +/// dispute_extension_hours: 24, // 24 hour dispute window +/// }; +/// +/// // Check if market qualifies as large +/// let market_volume = 500_000_000; // 50 XLM +/// let is_large_market = market_volume >= voting_config.large_market_threshold; +/// println!("Large market: {}", is_large_market); // false +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct VotingConfig { - /// Minimum vote stake + /// Minimum stake required to vote on a market outcome (in stroops). + /// + /// This prevents spam voting while keeping participation accessible. + /// Typical values: + /// - Development: 100_000 (0.01 XLM) + /// - Testnet: 1_000_000 (0.1 XLM) + /// - Mainnet: 5_000_000 (0.5 XLM) pub min_vote_stake: i128, - /// Minimum dispute stake + + /// Minimum stake required to initiate a dispute (in stroops). + /// + /// Higher than voting stake to prevent frivolous disputes. + /// Should be meaningful but not prohibitive for legitimate disputes. pub min_dispute_stake: i128, - /// Maximum dispute threshold + + /// Maximum dispute threshold that can be required (in stroops). + /// + /// Caps dispute costs to ensure accessibility while maintaining + /// serious commitment from disputers. pub max_dispute_threshold: i128, - /// Base dispute threshold + + /// Base dispute threshold for standard markets (in stroops). + /// + /// Starting point for dispute cost calculations. + /// May be adjusted based on market size and activity. pub base_dispute_threshold: i128, - /// Large market threshold + + /// Total stake threshold that defines a "large" market (in stroops). + /// + /// Large markets may have: + /// - Higher dispute thresholds + /// - Extended resolution periods + /// - Additional validation requirements pub large_market_threshold: i128, - /// High activity threshold + + /// Vote count threshold that defines "high activity" markets. + /// + /// High activity markets may receive: + /// - Priority in resolution queues + /// - Enhanced dispute mechanisms + /// - Additional monitoring pub high_activity_threshold: u32, - /// Dispute extension hours + + /// Additional hours added to resolution period when disputed. + /// + /// Provides time for: + /// - Community review of disputes + /// - Additional evidence gathering + /// - Oracle re-evaluation + /// - Consensus building pub dispute_extension_hours: u32, } -/// Market configuration +/// Market creation and structure configuration parameters. +/// +/// This struct defines the constraints and limits for creating prediction markets, +/// including duration limits, outcome constraints, and content length restrictions. +/// These parameters ensure market quality and system performance. +/// +/// # Market Quality Control +/// +/// Configuration parameters serve to: +/// - **Ensure Clarity**: Reasonable question and outcome lengths +/// - **Maintain Performance**: Limit complexity for efficient processing +/// - **Prevent Abuse**: Reasonable duration and outcome limits +/// - **Support Usability**: Balanced constraints for good user experience +/// +/// # Duration Considerations +/// +/// Market duration affects: +/// - Oracle availability and reliability +/// - User engagement and participation +/// - Resolution complexity and accuracy +/// - Platform resource utilization +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::config::MarketConfig; +/// +/// // Create production market configuration +/// let market_config = MarketConfig { +/// max_duration_days: 365, // Up to 1 year markets +/// min_duration_days: 1, // At least 1 day +/// max_outcomes: 10, // Up to 10 possible outcomes +/// min_outcomes: 2, // At least binary choice +/// max_question_length: 500, // 500 character questions +/// max_outcome_length: 100, // 100 character outcomes +/// }; +/// +/// // Validate a market proposal +/// let question = "Will Bitcoin reach $100,000 by end of 2024?"; +/// let outcomes = vec!["Yes", "No"]; +/// let duration = 90; // 3 months +/// +/// let valid_question = question.len() <= market_config.max_question_length as usize; +/// let valid_outcomes = outcomes.len() >= market_config.min_outcomes as usize && +/// outcomes.len() <= market_config.max_outcomes as usize; +/// let valid_duration = duration >= market_config.min_duration_days && +/// duration <= market_config.max_duration_days; +/// +/// println!("Market valid: {}", valid_question && valid_outcomes && valid_duration); +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct MarketConfig { - /// Maximum market duration in days + /// Maximum allowed market duration in days. + /// + /// Limits how far into the future markets can extend. + /// Considerations: + /// - Oracle data availability decreases over time + /// - User interest may wane for very long markets + /// - Platform evolution may make old markets obsolete + /// + /// Typical values: 30-365 days pub max_duration_days: u32, - /// Minimum market duration in days + + /// Minimum required market duration in days. + /// + /// Ensures markets have sufficient time for: + /// - User discovery and participation + /// - Meaningful price discovery + /// - Event outcome determination + /// + /// Typical values: 1-7 days pub min_duration_days: u32, - /// Maximum number of outcomes + + /// Maximum number of possible outcomes per market. + /// + /// Limits complexity while supporting diverse market types: + /// - Binary markets: 2 outcomes + /// - Multiple choice: 3-10 outcomes + /// - Complex scenarios: Up to maximum + /// + /// Higher limits increase: + /// - Storage requirements + /// - UI complexity + /// - Resolution difficulty pub max_outcomes: u32, - /// Minimum number of outcomes + + /// Minimum number of required outcomes per market. + /// + /// Typically 2 to ensure meaningful prediction markets. + /// Single-outcome markets don't provide prediction value. pub min_outcomes: u32, - /// Maximum question length + + /// Maximum length for market questions in characters. + /// + /// Balances between: + /// - Detailed, clear questions + /// - Storage efficiency + /// - UI display constraints + /// - Processing performance + /// + /// Typical range: 200-1000 characters pub max_question_length: u32, - /// Maximum outcome length + + /// Maximum length for outcome descriptions in characters. + /// + /// Keeps outcome descriptions: + /// - Clear and concise + /// - Displayable in UI components + /// - Storage efficient + /// - Easy to process + /// + /// Typical range: 50-200 characters pub max_outcome_length: u32, } -/// Extension configuration +/// Market duration extension configuration and fee structure. +/// +/// This struct defines the parameters for extending market durations beyond +/// their original end dates. Extensions allow markets to accommodate delayed +/// events or provide additional time for resolution when needed. +/// +/// # Extension Use Cases +/// +/// Market extensions are useful for: +/// - **Delayed Events**: When predicted events are postponed +/// - **Resolution Complexity**: Additional time needed for accurate resolution +/// - **High Stakes Markets**: Extra caution for significant markets +/// - **Community Requests**: Popular markets that warrant extension +/// +/// # Economic Model +/// +/// Extension fees serve to: +/// - Cover additional oracle and infrastructure costs +/// - Prevent abuse of extension mechanisms +/// - Compensate for extended resource usage +/// - Maintain platform sustainability +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::config::ExtensionConfig; +/// +/// // Create extension configuration +/// let extension_config = ExtensionConfig { +/// max_extension_days: 30, // Up to 30 days per extension +/// min_extension_days: 1, // At least 1 day extension +/// fee_per_day: 1_000_000, // 0.1 XLM per day +/// max_total_extensions: 3, // Maximum 3 extensions per market +/// }; +/// +/// // Calculate extension cost +/// let extension_days = 7; +/// let total_cost = extension_days as i128 * extension_config.fee_per_day; +/// println!("7-day extension costs: {} stroops", total_cost); // 7,000,000 stroops +/// +/// // Check if extension is valid +/// let current_extensions = 2; +/// let can_extend = current_extensions < extension_config.max_total_extensions && +/// extension_days >= extension_config.min_extension_days && +/// extension_days <= extension_config.max_extension_days; +/// println!("Can extend: {}", can_extend); // true +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct ExtensionConfig { - /// Maximum extension days + /// Maximum number of days that can be added in a single extension. + /// + /// Prevents excessively long extensions while allowing meaningful + /// time additions. Typical values: + /// - Development: 7-14 days + /// - Production: 14-30 days pub max_extension_days: u32, - /// Minimum extension days + + /// Minimum number of days required for an extension. + /// + /// Ensures extensions are meaningful and worth the administrative + /// overhead. Typically 1-3 days minimum. pub min_extension_days: u32, - /// Extension fee per day + + /// Fee charged per day of extension (in stroops). + /// + /// This fee: + /// - Covers additional oracle and infrastructure costs + /// - Prevents frivolous extension requests + /// - Scales with the duration of extension + /// + /// Typical values: + /// - Development: 100_000 (0.01 XLM/day) + /// - Testnet: 1_000_000 (0.1 XLM/day) + /// - Mainnet: 5_000_000 (0.5 XLM/day) pub fee_per_day: i128, - /// Maximum total extensions + + /// Maximum number of extensions allowed per market. + /// + /// Prevents indefinite market extensions while allowing + /// reasonable flexibility for legitimate needs. + /// Typical range: 2-5 extensions pub max_total_extensions: u32, } -/// Resolution configuration +/// Market resolution mechanism and confidence scoring configuration. +/// +/// This struct defines how markets are resolved by combining oracle data +/// with community voting. It includes confidence scoring, weighting mechanisms, +/// and consensus requirements for accurate market resolution. +/// +/// # Hybrid Resolution Model +/// +/// The resolution system combines: +/// - **Oracle Data**: Objective, external data sources +/// - **Community Voting**: Collective intelligence and verification +/// - **Confidence Scoring**: Reliability assessment of resolutions +/// - **Weighted Consensus**: Balanced decision making +/// +/// # Resolution Quality +/// +/// Configuration parameters ensure: +/// - High accuracy through multiple data sources +/// - Transparency in resolution processes +/// - Resistance to manipulation +/// - Scalable resolution mechanisms +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::config::ResolutionConfig; +/// +/// // Create balanced resolution configuration +/// let resolution_config = ResolutionConfig { +/// min_confidence_score: 0, // 0% minimum confidence +/// max_confidence_score: 100, // 100% maximum confidence +/// oracle_weight_percentage: 70, // Oracle has 70% influence +/// community_weight_percentage: 30, // Community has 30% influence +/// min_votes_for_consensus: 5, // Need at least 5 votes +/// }; +/// +/// // Calculate weighted resolution +/// let oracle_confidence = 85; // Oracle 85% confident +/// let community_confidence = 92; // Community 92% confident +/// +/// let weighted_confidence = +/// (oracle_confidence * resolution_config.oracle_weight_percentage + +/// community_confidence * resolution_config.community_weight_percentage) / 100; +/// +/// println!("Final confidence: {}%", weighted_confidence); // 87% +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct ResolutionConfig { - /// Minimum confidence score + /// Minimum allowed confidence score (typically 0). + /// + /// Represents the lowest confidence level that can be assigned + /// to a market resolution. Usually 0 to allow full range. pub min_confidence_score: u32, - /// Maximum confidence score + + /// Maximum allowed confidence score (typically 100). + /// + /// Represents the highest confidence level that can be assigned + /// to a market resolution. Usually 100 for percentage-based scoring. pub max_confidence_score: u32, - /// Oracle weight percentage + + /// Percentage weight given to oracle data in hybrid resolution. + /// + /// Determines how much influence oracle data has in the final + /// resolution decision. Higher values favor objective data sources. + /// + /// Typical values: + /// - High oracle trust: 70-80% + /// - Balanced approach: 50-60% + /// - Community focused: 30-40% pub oracle_weight_percentage: u32, - /// Community weight percentage + + /// Percentage weight given to community voting in hybrid resolution. + /// + /// Determines how much influence community consensus has in the + /// final resolution. Should sum with oracle_weight_percentage to 100. + /// + /// Higher community weight provides: + /// - Better handling of edge cases + /// - Resistance to oracle manipulation + /// - Democratic decision making pub community_weight_percentage: u32, - /// Minimum votes for consensus + + /// Minimum number of community votes required for valid consensus. + /// + /// Ensures community input is meaningful and representative. + /// Too low: Susceptible to manipulation + /// Too high: May prevent resolution of niche markets + /// + /// Typical values: 3-10 votes depending on platform size pub min_votes_for_consensus: u32, } -/// Oracle configuration +/// Oracle integration and reliability configuration parameters. +/// +/// This struct defines how the contract interacts with external oracle services +/// for market resolution. It includes timeout settings, retry mechanisms, +/// and data freshness requirements to ensure reliable oracle integration. +/// +/// # Oracle Reliability +/// +/// Configuration parameters address: +/// - **Data Freshness**: Ensuring oracle data is current +/// - **Network Resilience**: Handling temporary oracle failures +/// - **Timeout Management**: Preventing indefinite waits +/// - **Quality Assurance**: Maintaining data reliability standards +/// +/// # Integration Patterns +/// +/// Oracle configuration supports: +/// - Multiple oracle providers for redundancy +/// - Fallback mechanisms for oracle failures +/// - Data validation and quality checks +/// - Performance monitoring and optimization +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::config::OracleConfig; +/// +/// // Create production oracle configuration +/// let oracle_config = OracleConfig { +/// max_price_age: 3600, // 1 hour maximum data age +/// retry_attempts: 3, // Try up to 3 times +/// timeout_seconds: 30, // 30 second timeout per attempt +/// }; +/// +/// // Calculate total maximum wait time +/// let max_wait_time = oracle_config.retry_attempts as u64 * oracle_config.timeout_seconds; +/// println!("Maximum oracle wait: {} seconds", max_wait_time); // 90 seconds +/// +/// // Check if data is fresh enough +/// let data_age = 1800; // 30 minutes old +/// let is_fresh = data_age <= oracle_config.max_price_age; +/// println!("Data is fresh: {}", is_fresh); // true +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct OracleConfig { - /// Maximum oracle price age + /// Maximum age of oracle data before it's considered stale (in seconds). + /// + /// Ensures oracle data is sufficiently recent for accurate market + /// resolution. Older data may not reflect current conditions. + /// + /// Typical values: + /// - High-frequency markets: 300-900 seconds (5-15 minutes) + /// - Standard markets: 1800-3600 seconds (30-60 minutes) + /// - Long-term markets: 3600-7200 seconds (1-2 hours) pub max_price_age: u64, - /// Oracle retry attempts + + /// Number of retry attempts for failed oracle requests. + /// + /// Provides resilience against: + /// - Temporary network issues + /// - Oracle service interruptions + /// - Rate limiting responses + /// - Transient failures + /// + /// Typical values: 2-5 retries pub retry_attempts: u32, - /// Oracle timeout seconds + + /// Timeout duration for each oracle request (in seconds). + /// + /// Balances between: + /// - Allowing sufficient time for oracle response + /// - Preventing indefinite waits + /// - Maintaining responsive user experience + /// - Managing system resources + /// + /// Typical values: 10-60 seconds per request pub timeout_seconds: u64, } -/// Complete contract configuration +/// Complete contract configuration combining all subsystem configurations. +/// +/// This struct serves as the master configuration container that brings together +/// all the individual configuration components into a single, cohesive contract +/// configuration. It ensures all subsystems work together harmoniously. +/// +/// # Configuration Architecture +/// +/// The ContractConfig follows a modular design: +/// - **Network**: Blockchain connectivity and environment settings +/// - **Fees**: Economic model and fee structures +/// - **Voting**: Community participation and dispute mechanisms +/// - **Market**: Market creation rules and constraints +/// - **Extension**: Market duration extension parameters +/// - **Resolution**: Hybrid resolution and confidence scoring +/// - **Oracle**: External data integration settings +/// +/// # Environment-Specific Configurations +/// +/// Different environments require different parameter sets: +/// - **Development**: Relaxed limits, low fees, fast timeouts +/// - **Testnet**: Production-like settings with test-friendly adjustments +/// - **Mainnet**: Optimized, secure, production-ready parameters +/// - **Custom**: Flexible configuration for specialized deployments +/// +/// # Configuration Validation +/// +/// The complete configuration ensures: +/// - Internal consistency between subsystems +/// - Appropriate parameter relationships +/// - Environment-appropriate settings +/// - Security and performance optimization +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::config::{ConfigManager, Environment}; +/// # let env = Env::default(); +/// +/// // Get environment-specific configurations +/// let dev_config = ConfigManager::get_development_config(&env); +/// let mainnet_config = ConfigManager::get_mainnet_config(&env); +/// +/// // Compare environment differences +/// println!("Dev creation fee: {} stroops", dev_config.fees.creation_fee); +/// println!("Mainnet creation fee: {} stroops", mainnet_config.fees.creation_fee); +/// +/// // Access nested configuration +/// println!("Oracle timeout: {} seconds", dev_config.oracle.timeout_seconds); +/// println!("Max market duration: {} days", dev_config.market.max_duration_days); +/// +/// // Validate environment consistency +/// assert_eq!(dev_config.network.environment, Environment::Development); +/// assert_eq!(mainnet_config.network.environment, Environment::Mainnet); +/// ``` +/// +/// # Configuration Management +/// +/// ContractConfig supports: +/// - **Serialization**: Storage in contract persistent storage +/// - **Validation**: Consistency checks across all parameters +/// - **Updates**: Partial or complete configuration updates +/// - **Versioning**: Configuration evolution and migration +/// - **Testing**: Test-specific configuration generation +/// +/// # Integration Patterns +/// +/// The configuration is used throughout the contract: +/// - Market creation validates against market config +/// - Fee calculations use fee config parameters +/// - Oracle calls respect timeout and retry settings +/// - Voting mechanisms follow voting config rules +/// - Extensions are governed by extension config +/// +/// # Best Practices +/// +/// - Always validate complete configuration after changes +/// - Test configuration changes in development environment first +/// - Document rationale for production configuration values +/// - Monitor system behavior after configuration updates +/// - Maintain configuration version history for rollbacks #[derive(Clone, Debug)] #[contracttype] pub struct ContractConfig { - /// Network configuration + /// Network connectivity and environment configuration. + /// + /// Defines which Stellar network the contract operates on, + /// connection parameters, and environment-specific settings. pub network: NetworkConfig, - /// Fee configuration + + /// Economic model and fee structure configuration. + /// + /// Controls platform fees, creation costs, limits, and + /// collection thresholds for sustainable operation. pub fees: FeeConfig, - /// Voting configuration + + /// Voting and dispute mechanism configuration. + /// + /// Governs community participation, stake requirements, + /// and dispute resolution processes. pub voting: VotingConfig, - /// Market configuration + + /// Market creation and structure configuration. + /// + /// Defines constraints for market creation including + /// duration limits, outcome counts, and content restrictions. pub market: MarketConfig, - /// Extension configuration + + /// Market duration extension configuration. + /// + /// Controls how markets can be extended beyond their + /// original duration, including fees and limits. pub extension: ExtensionConfig, - /// Resolution configuration + + /// Market resolution and confidence scoring configuration. + /// + /// Defines how markets are resolved using hybrid oracle + /// and community consensus mechanisms. pub resolution: ResolutionConfig, - /// Oracle configuration + + /// Oracle integration and reliability configuration. + /// + /// Controls how the contract interacts with external + /// oracle services for market resolution data. pub oracle: OracleConfig, } // ===== CONFIGURATION MANAGER ===== -/// Configuration management utilities +/// Centralized configuration management for the Predictify Hybrid contract. +/// +/// The `ConfigManager` provides a comprehensive suite of functions for creating, +/// managing, and maintaining contract configurations across different environments. +/// It serves as the single source of truth for all configuration-related operations. +/// +/// # Core Responsibilities +/// +/// ConfigManager handles: +/// - **Environment-Specific Configs**: Development, testnet, and mainnet configurations +/// - **Component Configs**: Individual subsystem configuration generation +/// - **Storage Management**: Persistent configuration storage and retrieval +/// - **Validation**: Configuration consistency and validity checks +/// - **Updates**: Safe configuration updates and migrations +/// +/// # Configuration Philosophy +/// +/// The configuration system follows these principles: +/// - **Environment Appropriate**: Each environment has optimized settings +/// - **Modular Design**: Configurations are composed of focused components +/// - **Safety First**: Validation prevents invalid or dangerous configurations +/// - **Flexibility**: Support for custom configurations when needed +/// - **Maintainability**: Clear, documented, and testable configuration logic +/// +/// # Usage Patterns +/// +/// ConfigManager is typically used during: +/// - Contract initialization and deployment +/// - Runtime configuration retrieval +/// - Administrative configuration updates +/// - Testing and development setup +/// - Environment migrations +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::config::{ConfigManager, Environment}; +/// # let env = Env::default(); +/// +/// // Get environment-appropriate configurations +/// let dev_config = ConfigManager::get_development_config(&env); +/// let mainnet_config = ConfigManager::get_mainnet_config(&env); +/// +/// // Store configuration in contract +/// ConfigManager::store_config(&env, &mainnet_config).unwrap(); +/// +/// // Retrieve stored configuration +/// let stored_config = ConfigManager::get_config(&env).unwrap(); +/// assert_eq!(stored_config.network.environment, Environment::Mainnet); +/// ``` pub struct ConfigManager; impl ConfigManager { - /// Get default configuration for development environment + /// Creates a development environment configuration with relaxed parameters. + /// + /// This function generates a complete contract configuration optimized for + /// development and testing scenarios. It uses relaxed validation rules, + /// lower fees, and shorter timeouts to facilitate rapid development cycles. + /// + /// # Development Characteristics + /// + /// The development configuration features: + /// - **Low Fees**: Minimal creation and platform fees for easy testing + /// - **Relaxed Limits**: Permissive market creation and participation rules + /// - **Fast Timeouts**: Short oracle and extension timeouts for quick iteration + /// - **Test Network**: Uses Stellar testnet for safe development + /// - **Debug Friendly**: Settings optimized for debugging and testing + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for string and address creation + /// + /// # Returns + /// + /// Returns a `ContractConfig` with development-optimized settings across + /// all subsystems (network, fees, voting, market, extension, resolution, oracle). + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::config::{ConfigManager, Environment}; + /// # let env = Env::default(); + /// + /// // Get development configuration + /// let dev_config = ConfigManager::get_development_config(&env); + /// + /// // Verify development characteristics + /// assert_eq!(dev_config.network.environment, Environment::Development); + /// assert!(dev_config.fees.creation_fee < 10_000_000); // Less than 1 XLM + /// assert!(dev_config.oracle.timeout_seconds <= 30); // Quick timeouts + /// + /// println!("Development config ready with {} second oracle timeout", + /// dev_config.oracle.timeout_seconds); + /// ``` + /// + /// # Development vs Production + /// + /// Key differences from production: + /// - Creation fees: ~0.1 XLM vs ~5 XLM + /// - Platform fees: ~1% vs ~2.5% + /// - Oracle timeouts: ~10s vs ~30s + /// - Market limits: More permissive vs strict + /// - Validation: Relaxed vs comprehensive + /// + /// # Use Cases + /// + /// Development configuration is ideal for: + /// - Local development and testing + /// - Unit and integration test suites + /// - Feature development and experimentation + /// - Debugging and troubleshooting + /// - Rapid prototyping + /// + /// # Network Configuration + /// + /// The development config uses Stellar testnet by default but can be + /// easily modified for local networks or Futurenet as needed. pub fn get_development_config(env: &Env) -> ContractConfig { ContractConfig { network: NetworkConfig { @@ -317,7 +1163,78 @@ impl ConfigManager { } } - /// Get default configuration for testnet environment + /// Creates a testnet environment configuration with production-like settings. + /// + /// This function generates a complete contract configuration that closely + /// mirrors production settings while remaining suitable for testing and + /// integration scenarios. It provides a realistic testing environment. + /// + /// # Testnet Characteristics + /// + /// The testnet configuration features: + /// - **Production-Like Fees**: Realistic fee structures for testing + /// - **Full Validation**: Complete validation rules enabled + /// - **Realistic Timeouts**: Production-appropriate timeout values + /// - **Test Network**: Uses Stellar testnet with test tokens + /// - **Integration Ready**: Optimized for integration testing + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for string and address creation + /// + /// # Returns + /// + /// Returns a `ContractConfig` with testnet-optimized settings that closely + /// mirror production while remaining test-friendly. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::config::{ConfigManager, Environment}; + /// # let env = Env::default(); + /// + /// // Get testnet configuration + /// let testnet_config = ConfigManager::get_testnet_config(&env); + /// + /// // Verify testnet characteristics + /// assert_eq!(testnet_config.network.environment, Environment::Testnet); + /// assert_eq!(testnet_config.network.passphrase.to_string(), + /// "Test SDF Network ; September 2015"); + /// + /// // Compare with development settings + /// let dev_config = ConfigManager::get_development_config(&env); + /// assert!(testnet_config.fees.creation_fee >= dev_config.fees.creation_fee); + /// + /// println!("Testnet config with {} XLM creation fee", + /// testnet_config.fees.creation_fee / 10_000_000); + /// ``` + /// + /// # Testing Scenarios + /// + /// Testnet configuration is perfect for: + /// - **Integration Testing**: End-to-end testing with realistic settings + /// - **User Acceptance Testing**: Testing with production-like behavior + /// - **Performance Testing**: Load testing with realistic parameters + /// - **Oracle Integration**: Testing oracle connectivity and reliability + /// - **Fee Testing**: Validating economic model with realistic fees + /// + /// # Network Details + /// + /// The testnet configuration: + /// - Uses Stellar testnet (Test SDF Network) + /// - Connects to Stellar testnet RPC endpoints + /// - Employs test tokens (not real value) + /// - Provides reset capabilities for testing + /// + /// # Production Preparation + /// + /// Testnet serves as the final validation before mainnet: + /// - Validates all contract functionality + /// - Tests oracle integrations + /// - Verifies fee calculations + /// - Confirms user experience flows + /// - Validates security measures pub fn get_testnet_config(env: &Env) -> ContractConfig { ContractConfig { network: NetworkConfig { @@ -339,7 +1256,89 @@ impl ConfigManager { } } - /// Get default configuration for mainnet environment + /// Creates a mainnet environment configuration with production-optimized settings. + /// + /// This function generates a complete contract configuration optimized for + /// production deployment on Stellar mainnet. It emphasizes security, efficiency, + /// and economic sustainability while maintaining excellent user experience. + /// + /// # Mainnet Characteristics + /// + /// The mainnet configuration features: + /// - **Optimized Fees**: Balanced fee structure for sustainability and accessibility + /// - **Strict Security**: Comprehensive validation and security measures + /// - **Production Timeouts**: Reliable timeout values for production use + /// - **Mainnet Network**: Uses Stellar mainnet with real XLM + /// - **Audit Ready**: Configuration suitable for security audits + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for string and address creation + /// + /// # Returns + /// + /// Returns a `ContractConfig` with production-optimized settings designed + /// for real-world usage with actual economic value. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::config::{ConfigManager, Environment}; + /// # let env = Env::default(); + /// + /// // Get mainnet configuration + /// let mainnet_config = ConfigManager::get_mainnet_config(&env); + /// + /// // Verify mainnet characteristics + /// assert_eq!(mainnet_config.network.environment, Environment::Mainnet); + /// assert_eq!(mainnet_config.network.passphrase.to_string(), + /// "Public Global Stellar Network ; September 2015"); + /// + /// // Check production-grade settings + /// assert!(mainnet_config.fees.creation_fee >= 10_000_000); // At least 1 XLM + /// assert!(mainnet_config.fees.platform_fee_percentage >= 200); // At least 2% + /// + /// println!("Mainnet config with {}% platform fee", + /// mainnet_config.fees.platform_fee_percentage / 100); + /// ``` + /// + /// # Production Considerations + /// + /// Mainnet configuration addresses: + /// - **Economic Sustainability**: Fees that support platform operations + /// - **Security**: Robust validation and anti-abuse measures + /// - **Scalability**: Settings that support high transaction volumes + /// - **User Experience**: Balanced between security and usability + /// - **Regulatory Compliance**: Settings that support compliance requirements + /// + /// # Fee Structure + /// + /// Mainnet fees are designed to: + /// - Cover operational costs (oracles, infrastructure) + /// - Prevent spam and abuse + /// - Generate sustainable revenue + /// - Remain competitive with alternatives + /// - Support platform development + /// + /// # Security Features + /// + /// Production security includes: + /// - Comprehensive input validation + /// - Anti-manipulation measures + /// - Robust dispute mechanisms + /// - Oracle reliability safeguards + /// - Economic incentive alignment + /// + /// # Deployment Readiness + /// + /// Before mainnet deployment, ensure: + /// - Thorough testing on testnet + /// - Security audit completion + /// - Oracle integration validation + /// - Fee model validation + /// - User experience testing + /// - Monitoring and alerting setup pub fn get_mainnet_config(env: &Env) -> ContractConfig { ContractConfig { network: NetworkConfig { @@ -361,7 +1360,55 @@ impl ConfigManager { } } - /// Get default fee configuration + /// Creates a default fee configuration suitable for development and testing. + /// + /// This function generates a balanced fee configuration that provides reasonable + /// defaults for most environments while remaining accessible for development + /// and testing scenarios. + /// + /// # Default Fee Structure + /// + /// The default configuration includes: + /// - **Platform Fee**: 2% of winning payouts + /// - **Creation Fee**: 1 XLM to create markets + /// - **Minimum Fee**: 0.1 XLM floor + /// - **Maximum Fee**: 100 XLM ceiling + /// - **Collection Threshold**: 10 XLM auto-collection + /// - **Fees Enabled**: Active by default + /// + /// # Returns + /// + /// Returns a `FeeConfig` with balanced default values suitable for + /// development, testing, and initial production deployments. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get default fee configuration + /// let fee_config = ConfigManager::get_default_fee_config(); + /// + /// // Verify default values + /// assert_eq!(fee_config.platform_fee_percentage, 2); // 2% + /// assert_eq!(fee_config.creation_fee, 10_000_000); // 1 XLM + /// assert!(fee_config.fees_enabled); + /// + /// println!("Default platform fee: {}%", fee_config.platform_fee_percentage); + /// ``` + /// + /// # Usage Context + /// + /// Default fees are appropriate for: + /// - Development and testing environments + /// - Initial testnet deployments + /// - Conservative production starts + /// - Baseline configuration reference + /// + /// # Customization + /// + /// For production mainnet, consider using `get_mainnet_fee_config()` + /// which provides higher, more sustainable fee structures. pub fn get_default_fee_config() -> FeeConfig { FeeConfig { platform_fee_percentage: DEFAULT_PLATFORM_FEE_PERCENTAGE, @@ -373,7 +1420,58 @@ impl ConfigManager { } } - /// Get mainnet fee configuration (higher fees) + /// Creates a mainnet-optimized fee configuration with higher, sustainable fees. + /// + /// This function generates a fee configuration specifically designed for + /// production mainnet deployment, with higher fees that support platform + /// sustainability while remaining competitive and accessible. + /// + /// # Mainnet Fee Structure + /// + /// The mainnet configuration includes: + /// - **Platform Fee**: 3% of winning payouts (vs 2% default) + /// - **Creation Fee**: 1.5 XLM to create markets (vs 1 XLM default) + /// - **Minimum Fee**: 0.2 XLM floor (vs 0.1 XLM default) + /// - **Maximum Fee**: 200 XLM ceiling (vs 100 XLM default) + /// - **Collection Threshold**: 20 XLM auto-collection (vs 10 XLM default) + /// - **Fees Enabled**: Active for revenue generation + /// + /// # Returns + /// + /// Returns a `FeeConfig` with mainnet-optimized values designed for + /// production deployment with real economic value. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get mainnet fee configuration + /// let mainnet_fees = ConfigManager::get_mainnet_fee_config(); + /// let default_fees = ConfigManager::get_default_fee_config(); + /// + /// // Compare mainnet vs default + /// assert!(mainnet_fees.platform_fee_percentage > default_fees.platform_fee_percentage); + /// assert!(mainnet_fees.creation_fee > default_fees.creation_fee); + /// + /// println!("Mainnet creation fee: {} XLM", mainnet_fees.creation_fee / 10_000_000); + /// ``` + /// + /// # Economic Rationale + /// + /// Higher mainnet fees serve to: + /// - **Cover Operational Costs**: Oracle fees, infrastructure, development + /// - **Prevent Spam**: Higher creation fees deter low-quality markets + /// - **Ensure Sustainability**: Revenue supports long-term platform viability + /// - **Maintain Quality**: Economic barriers encourage thoughtful market creation + /// + /// # Market Competitiveness + /// + /// Mainnet fees are designed to be: + /// - Competitive with similar prediction platforms + /// - Reasonable for serious market creators + /// - Sustainable for platform operations + /// - Transparent and predictable pub fn get_mainnet_fee_config() -> FeeConfig { FeeConfig { platform_fee_percentage: 3, // 3% for mainnet @@ -385,7 +1483,60 @@ impl ConfigManager { } } - /// Get default voting configuration + /// Creates a default voting configuration with balanced participation thresholds. + /// + /// This function generates a voting configuration that balances accessibility + /// with security, providing reasonable defaults for community participation + /// and dispute resolution mechanisms. + /// + /// # Default Voting Parameters + /// + /// The default configuration includes: + /// - **Minimum Vote Stake**: 0.1 XLM (accessible participation) + /// - **Minimum Dispute Stake**: 1 XLM (serious commitment required) + /// - **Maximum Dispute Threshold**: 10 XLM (reasonable cap) + /// - **Base Dispute Threshold**: 1 XLM (starting point) + /// - **Large Market Threshold**: 100 XLM (high-value market definition) + /// - **High Activity Threshold**: 100 votes (active market definition) + /// - **Dispute Extension**: 24 hours (reasonable review time) + /// + /// # Returns + /// + /// Returns a `VotingConfig` with balanced default values suitable for + /// most environments and use cases. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get default voting configuration + /// let voting_config = ConfigManager::get_default_voting_config(); + /// + /// // Check accessibility + /// assert_eq!(voting_config.min_vote_stake, 1_000_000); // 0.1 XLM + /// assert_eq!(voting_config.dispute_extension_hours, 24); + /// + /// // Calculate dispute cost for standard market + /// let dispute_cost = voting_config.base_dispute_threshold; + /// println!("Base dispute cost: {} XLM", dispute_cost / 10_000_000); + /// ``` + /// + /// # Participation Balance + /// + /// Default settings balance: + /// - **Accessibility**: Low minimum stakes encourage participation + /// - **Security**: Higher dispute stakes prevent frivolous challenges + /// - **Scalability**: Thresholds adjust based on market size and activity + /// - **Fairness**: Reasonable timeframes for dispute resolution + /// + /// # Environment Suitability + /// + /// Default voting config works well for: + /// - Development and testing environments + /// - Initial testnet deployments + /// - Conservative production launches + /// - General-purpose prediction markets pub fn get_default_voting_config() -> VotingConfig { VotingConfig { min_vote_stake: MIN_VOTE_STAKE, @@ -398,7 +1549,61 @@ impl ConfigManager { } } - /// Get mainnet voting configuration (higher stakes) + /// Creates a mainnet-optimized voting configuration with higher stakes and security. + /// + /// This function generates a voting configuration specifically designed for + /// production mainnet deployment, with higher stakes that improve security + /// and reduce spam while maintaining reasonable accessibility. + /// + /// # Mainnet Voting Parameters + /// + /// The mainnet configuration includes: + /// - **Minimum Vote Stake**: 0.2 XLM (vs 0.1 XLM default) + /// - **Minimum Dispute Stake**: 2 XLM (vs 1 XLM default) + /// - **Maximum Dispute Threshold**: 20 XLM (vs 10 XLM default) + /// - **Base Dispute Threshold**: 2 XLM (vs 1 XLM default) + /// - **Large Market Threshold**: 200 XLM (vs 100 XLM default) + /// - **High Activity Threshold**: 200 votes (vs 100 votes default) + /// - **Dispute Extension**: 48 hours (vs 24 hours default) + /// + /// # Returns + /// + /// Returns a `VotingConfig` with mainnet-optimized values designed for + /// production deployment with enhanced security and quality. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get mainnet voting configuration + /// let mainnet_voting = ConfigManager::get_mainnet_voting_config(); + /// let default_voting = ConfigManager::get_default_voting_config(); + /// + /// // Compare mainnet vs default security + /// assert!(mainnet_voting.min_dispute_stake > default_voting.min_dispute_stake); + /// assert!(mainnet_voting.dispute_extension_hours > default_voting.dispute_extension_hours); + /// + /// println!("Mainnet dispute stake: {} XLM", + /// mainnet_voting.min_dispute_stake / 10_000_000); + /// ``` + /// + /// # Enhanced Security Features + /// + /// Higher mainnet stakes provide: + /// - **Spam Resistance**: Higher costs deter low-quality participation + /// - **Serious Commitment**: Meaningful stakes ensure thoughtful voting + /// - **Extended Review**: Longer dispute periods for thorough evaluation + /// - **Quality Markets**: Higher thresholds for large/active market classification + /// + /// # Production Considerations + /// + /// Mainnet voting config addresses: + /// - Real economic value at stake + /// - Higher potential for manipulation attempts + /// - Need for robust dispute resolution + /// - Community quality and engagement + /// - Platform reputation and trust pub fn get_mainnet_voting_config() -> VotingConfig { VotingConfig { min_vote_stake: 2_000_000, // 0.2 XLM for mainnet @@ -411,7 +1616,63 @@ impl ConfigManager { } } - /// Get default market configuration + /// Creates a default market configuration with balanced creation constraints. + /// + /// This function generates a market configuration that provides reasonable + /// defaults for market creation, balancing flexibility with quality control + /// and system performance considerations. + /// + /// # Default Market Parameters + /// + /// The default configuration includes: + /// - **Maximum Duration**: 365 days (up to 1 year markets) + /// - **Minimum Duration**: 1 day (at least 24 hours) + /// - **Maximum Outcomes**: 10 possible outcomes per market + /// - **Minimum Outcomes**: 2 outcomes (binary minimum) + /// - **Maximum Question Length**: 500 characters + /// - **Maximum Outcome Length**: 100 characters + /// + /// # Returns + /// + /// Returns a `MarketConfig` with balanced default values suitable for + /// diverse market types and use cases. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get default market configuration + /// let market_config = ConfigManager::get_default_market_config(); + /// + /// // Validate a market proposal + /// let question = "Will Bitcoin reach $100,000 by end of 2024?"; + /// let outcomes = vec!["Yes", "No"]; + /// let duration_days = 90; + /// + /// let valid_question = question.len() <= market_config.max_question_length as usize; + /// let valid_outcomes = outcomes.len() >= market_config.min_outcomes as usize; + /// let valid_duration = duration_days <= market_config.max_duration_days; + /// + /// assert!(valid_question && valid_outcomes && valid_duration); + /// ``` + /// + /// # Quality Control Balance + /// + /// Default settings balance: + /// - **Flexibility**: Wide duration range supports diverse market types + /// - **Quality**: Reasonable length limits ensure clarity + /// - **Performance**: Outcome limits maintain system efficiency + /// - **Usability**: Constraints are permissive but meaningful + /// + /// # Market Type Support + /// + /// Default config supports: + /// - Binary prediction markets (2 outcomes) + /// - Multiple choice markets (3-10 outcomes) + /// - Short-term events (1+ days) + /// - Long-term predictions (up to 1 year) + /// - Detailed questions (up to 500 characters) pub fn get_default_market_config() -> MarketConfig { MarketConfig { max_duration_days: MAX_MARKET_DURATION_DAYS, @@ -423,7 +1684,62 @@ impl ConfigManager { } } - /// Get default extension configuration + /// Creates a default extension configuration with reasonable limits and fees. + /// + /// This function generates an extension configuration that allows market + /// duration extensions while preventing abuse through reasonable limits + /// and proportional fees. + /// + /// # Default Extension Parameters + /// + /// The default configuration includes: + /// - **Maximum Extension Days**: 30 days per extension + /// - **Minimum Extension Days**: 1 day minimum extension + /// - **Fee Per Day**: 10 XLM per day of extension + /// - **Maximum Total Extensions**: 3 extensions per market + /// + /// # Returns + /// + /// Returns an `ExtensionConfig` with balanced default values that allow + /// reasonable market extensions while preventing abuse. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get default extension configuration + /// let ext_config = ConfigManager::get_default_extension_config(); + /// + /// // Calculate extension cost + /// let extension_days = 7; + /// let total_cost = extension_days as i128 * ext_config.fee_per_day; + /// + /// // Check if extension is allowed + /// let current_extensions = 2; + /// let can_extend = current_extensions < ext_config.max_total_extensions && + /// extension_days <= ext_config.max_extension_days; + /// + /// println!("7-day extension costs: {} XLM", total_cost / 10_000_000); + /// assert!(can_extend); + /// ``` + /// + /// # Extension Economics + /// + /// Default fees are designed to: + /// - **Cover Costs**: Additional oracle and infrastructure expenses + /// - **Prevent Abuse**: Meaningful cost discourages frivolous extensions + /// - **Scale Appropriately**: Cost proportional to extension duration + /// - **Remain Accessible**: Not prohibitively expensive for legitimate needs + /// + /// # Use Case Support + /// + /// Default config accommodates: + /// - Event delays and postponements + /// - Complex resolution scenarios + /// - High-stakes markets needing extra time + /// - Community-requested extensions + /// - Oracle data availability issues pub fn get_default_extension_config() -> ExtensionConfig { ExtensionConfig { max_extension_days: MAX_EXTENSION_DAYS, @@ -433,7 +1749,69 @@ impl ConfigManager { } } - /// Get default resolution configuration + /// Creates a default resolution configuration for hybrid oracle-community resolution. + /// + /// This function generates a resolution configuration that balances oracle + /// reliability with community wisdom, providing a hybrid approach to market + /// resolution that leverages both automated and human intelligence. + /// + /// # Default Resolution Parameters + /// + /// The default configuration includes: + /// - **Minimum Confidence Score**: 70% (reliable threshold) + /// - **Maximum Confidence Score**: 100% (perfect confidence) + /// - **Oracle Weight**: 60% of resolution decision + /// - **Community Weight**: 40% of resolution decision + /// - **Minimum Votes for Consensus**: 10 community votes required + /// + /// # Returns + /// + /// Returns a `ResolutionConfig` with balanced default values that combine + /// oracle reliability with community validation. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get default resolution configuration + /// let resolution_config = ConfigManager::get_default_resolution_config(); + /// + /// // Check hybrid weighting + /// assert_eq!(resolution_config.oracle_weight_percentage, 60); + /// assert_eq!(resolution_config.community_weight_percentage, 40); + /// assert_eq!(resolution_config.oracle_weight_percentage + + /// resolution_config.community_weight_percentage, 100); + /// + /// // Verify confidence thresholds + /// assert!(resolution_config.min_confidence_score >= 70); + /// println!("Minimum confidence required: {}%", resolution_config.min_confidence_score); + /// ``` + /// + /// # Hybrid Resolution Model + /// + /// The default configuration implements a hybrid model where: + /// - **Oracle Primary**: Oracle data carries more weight (60%) + /// - **Community Validation**: Community provides validation and backup (40%) + /// - **Confidence Gating**: Low confidence triggers community involvement + /// - **Consensus Requirements**: Minimum vote thresholds ensure quality + /// + /// # Resolution Flow + /// + /// Default config supports this resolution process: + /// 1. Oracle provides initial resolution with confidence score + /// 2. If confidence ≥ minimum, oracle resolution weighted at 60% + /// 3. Community voting weighted at 40% for final decision + /// 4. Minimum vote threshold ensures adequate participation + /// 5. Combined weighted result determines final outcome + /// + /// # Quality Assurance + /// + /// Default settings ensure: + /// - High-confidence oracle data is respected + /// - Community input prevents oracle manipulation + /// - Sufficient participation for legitimate consensus + /// - Balanced approach reduces single points of failure pub fn get_default_resolution_config() -> ResolutionConfig { ResolutionConfig { min_confidence_score: MIN_CONFIDENCE_SCORE, @@ -444,7 +1822,75 @@ impl ConfigManager { } } - /// Get default oracle configuration + /// Creates a default oracle configuration with balanced reliability and performance. + /// + /// This function generates an oracle configuration that balances data freshness, + /// reliability, and system performance, providing reasonable defaults for + /// oracle integration across various market types and conditions. + /// + /// # Default Oracle Parameters + /// + /// The default configuration includes: + /// - **Maximum Price Age**: 3600 seconds (1 hour data freshness) + /// - **Retry Attempts**: 3 attempts for failed oracle calls + /// - **Timeout Seconds**: 30 seconds per oracle request + /// + /// # Returns + /// + /// Returns an `OracleConfig` with balanced default values suitable for + /// reliable oracle integration with reasonable performance characteristics. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get default oracle configuration + /// let oracle_config = ConfigManager::get_default_oracle_config(); + /// + /// // Check data freshness requirements + /// assert_eq!(oracle_config.max_price_age, 3600); // 1 hour + /// + /// // Verify reliability settings + /// assert_eq!(oracle_config.retry_attempts, 3); + /// assert_eq!(oracle_config.timeout_seconds, 30); + /// + /// // Calculate maximum total time for oracle resolution + /// let max_resolution_time = oracle_config.retry_attempts * oracle_config.timeout_seconds; + /// println!("Maximum oracle resolution time: {} seconds", max_resolution_time); + /// ``` + /// + /// # Data Freshness Balance + /// + /// The 1-hour maximum age balances: + /// - **Accuracy**: Recent data reflects current market conditions + /// - **Availability**: Reasonable window prevents excessive failures + /// - **Performance**: Allows for oracle caching and optimization + /// - **Cost**: Reduces unnecessary oracle calls + /// + /// # Reliability Features + /// + /// Default retry and timeout settings provide: + /// - **Fault Tolerance**: Multiple attempts handle transient failures + /// - **Reasonable Timeouts**: 30 seconds allows for network latency + /// - **Bounded Delays**: Maximum 90 seconds total resolution time + /// - **Predictable Behavior**: Consistent timing for user experience + /// + /// # Oracle Integration + /// + /// Default config supports integration with: + /// - Price feed oracles (Chainlink, Band Protocol, etc.) + /// - Event outcome oracles (sports, elections, etc.) + /// - Custom data providers + /// - Hybrid oracle networks + /// + /// # Performance Considerations + /// + /// Default settings balance: + /// - User experience (reasonable wait times) + /// - System reliability (adequate retries) + /// - Resource usage (bounded timeouts) + /// - Data quality (freshness requirements) pub fn get_default_oracle_config() -> OracleConfig { OracleConfig { max_price_age: MAX_ORACLE_PRICE_AGE, @@ -453,7 +1899,58 @@ impl ConfigManager { } } - /// Get mainnet oracle configuration (stricter requirements) + /// Creates a mainnet-optimized oracle configuration with stricter reliability requirements. + /// + /// This function generates an oracle configuration specifically designed for + /// production mainnet deployment, with stricter data freshness requirements + /// and enhanced reliability measures to ensure high-quality oracle data. + /// + /// # Mainnet Oracle Parameters + /// + /// The mainnet configuration includes: + /// - **Maximum Price Age**: 1800 seconds (30 minutes vs 1 hour default) + /// - **Retry Attempts**: 5 attempts (vs 3 attempts default) + /// - **Timeout Seconds**: 60 seconds (vs 30 seconds default) + /// + /// # Returns + /// + /// Returns an `OracleConfig` with mainnet-optimized values designed for + /// production deployment with enhanced data quality and reliability. + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::config::ConfigManager; + /// + /// // Get mainnet oracle configuration + /// let mainnet_oracle = ConfigManager::get_mainnet_oracle_config(); + /// let default_oracle = ConfigManager::get_default_oracle_config(); + /// + /// // Compare mainnet vs default strictness + /// assert!(mainnet_oracle.max_price_age < default_oracle.max_price_age); + /// assert!(mainnet_oracle.retry_attempts > default_oracle.retry_attempts); + /// assert!(mainnet_oracle.timeout_seconds > default_oracle.timeout_seconds); + /// + /// println!("Mainnet data freshness: {} minutes", + /// mainnet_oracle.max_price_age / 60); + /// ``` + /// + /// # Enhanced Reliability Features + /// + /// Mainnet oracle config provides: + /// - **Fresher Data**: 30-minute maximum age ensures current market conditions + /// - **More Retries**: 5 attempts handle network issues and temporary failures + /// - **Longer Timeouts**: 60 seconds accommodates complex oracle operations + /// - **Higher Quality**: Stricter requirements improve resolution accuracy + /// + /// # Production Considerations + /// + /// Mainnet settings address: + /// - Real economic value requiring accurate data + /// - Higher stakes demanding reliable oracle responses + /// - Network congestion and latency issues + /// - Oracle provider diversity and failover + /// - Regulatory compliance and audit requirements pub fn get_mainnet_oracle_config() -> OracleConfig { OracleConfig { max_price_age: 1800, // 30 minutes for mainnet @@ -462,14 +1959,112 @@ impl ConfigManager { } } - /// Store configuration in contract storage + /// Stores a complete contract configuration in persistent contract storage. + /// + /// This function saves the provided configuration to the contract's persistent + /// storage, making it available for future contract calls and ensuring + /// configuration persistence across contract invocations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for storage operations + /// * `config` - The complete contract configuration to store + /// + /// # Returns + /// + /// Returns `Ok(())` on successful storage, or an `Error` if storage fails. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::config::ConfigManager; + /// # let env = Env::default(); + /// + /// // Create and store development configuration + /// let dev_config = ConfigManager::get_development_config(&env); + /// let result = ConfigManager::store_config(&env, &dev_config); + /// + /// assert!(result.is_ok()); + /// + /// // Verify storage by retrieving + /// let retrieved_config = ConfigManager::get_config(&env).unwrap(); + /// assert_eq!(retrieved_config.network.environment, dev_config.network.environment); + /// ``` + /// + /// # Storage Details + /// + /// Configuration storage: + /// - Uses persistent storage for durability across contract calls + /// - Stores under the "ContractConfig" key for consistent retrieval + /// - Overwrites any existing configuration + /// - Atomic operation ensuring consistency + /// + /// # Usage Context + /// + /// This function is typically called during: + /// - Contract initialization and setup + /// - Configuration updates by admin functions + /// - Environment-specific deployments + /// - Configuration resets and migrations pub fn store_config(env: &Env, config: &ContractConfig) -> Result<(), Error> { let key = Symbol::new(env, "ContractConfig"); env.storage().persistent().set(&key, config); Ok(()) } - /// Retrieve configuration from contract storage + /// Retrieves the current contract configuration from persistent storage. + /// + /// This function loads the previously stored contract configuration from + /// persistent storage, providing access to all current contract settings + /// and parameters for use in contract operations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for storage operations + /// + /// # Returns + /// + /// Returns the stored `ContractConfig` on success, or `Error::ConfigurationNotFound` + /// if no configuration has been stored. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::config::{ConfigManager, Environment}; + /// # let env = Env::default(); + /// + /// // Store a configuration first + /// let testnet_config = ConfigManager::get_testnet_config(&env); + /// ConfigManager::store_config(&env, &testnet_config).unwrap(); + /// + /// // Retrieve the stored configuration + /// let current_config = ConfigManager::get_config(&env).unwrap(); + /// + /// // Verify it matches what was stored + /// assert_eq!(current_config.network.environment, Environment::Testnet); + /// assert_eq!(current_config.fees.platform_fee_percentage, + /// testnet_config.fees.platform_fee_percentage); + /// + /// println!("Current environment: {:?}", current_config.network.environment); + /// ``` + /// + /// # Error Handling + /// + /// This function returns `Error::ConfigurationNotFound` when: + /// - No configuration has been previously stored + /// - Configuration was stored but corrupted + /// - Storage key doesn't exist or is inaccessible + /// + /// # Usage Context + /// + /// Configuration retrieval is used in: + /// - Contract function calls requiring current settings + /// - Fee calculations and validation + /// - Market creation and management + /// - Oracle integration and resolution + /// - Admin operations and updates pub fn get_config(env: &Env) -> Result { let key = Symbol::new(env, "ContractConfig"); env.storage() @@ -478,12 +2073,126 @@ impl ConfigManager { .ok_or(Error::ConfigurationNotFound) } - /// Update configuration in contract storage + /// Updates the contract configuration in persistent storage. + /// + /// This function provides a convenient wrapper for updating the stored + /// contract configuration, ensuring consistency with the storage mechanism + /// and maintaining the same storage key and behavior. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for storage operations + /// * `config` - The updated contract configuration to store + /// + /// # Returns + /// + /// Returns `Ok(())` on successful update, or an `Error` if storage fails. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::config::ConfigManager; + /// # let env = Env::default(); + /// + /// // Get current configuration + /// let mut current_config = ConfigManager::get_development_config(&env); + /// ConfigManager::store_config(&env, ¤t_config).unwrap(); + /// + /// // Modify fee settings + /// current_config.fees.platform_fee_percentage = 3; // Increase to 3% + /// current_config.fees.creation_fee = 15_000_000; // Increase to 1.5 XLM + /// + /// // Update stored configuration + /// let result = ConfigManager::update_config(&env, ¤t_config); + /// assert!(result.is_ok()); + /// + /// // Verify update + /// let updated_config = ConfigManager::get_config(&env).unwrap(); + /// assert_eq!(updated_config.fees.platform_fee_percentage, 3); + /// ``` + /// + /// # Update Semantics + /// + /// Configuration updates: + /// - Completely replace the existing configuration + /// - Are atomic operations ensuring consistency + /// - Take effect immediately for subsequent contract calls + /// - Should be validated before updating + /// + /// # Administrative Context + /// + /// Configuration updates are typically performed by: + /// - Contract administrators during governance actions + /// - Automated systems responding to market conditions + /// - Migration scripts during contract upgrades + /// - Emergency response procedures pub fn update_config(env: &Env, config: &ContractConfig) -> Result<(), Error> { Self::store_config(env, config) } - /// Reset configuration to defaults + /// Resets the contract configuration to development defaults and stores it. + /// + /// This function provides a convenient way to reset the contract configuration + /// to safe development defaults, useful for testing, recovery scenarios, + /// or initial contract setup. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for configuration generation and storage + /// + /// # Returns + /// + /// Returns the newly stored development `ContractConfig` on success, + /// or an `Error` if storage fails. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::config::{ConfigManager, Environment}; + /// # let env = Env::default(); + /// + /// // Store a custom configuration first + /// let mainnet_config = ConfigManager::get_mainnet_config(&env); + /// ConfigManager::store_config(&env, &mainnet_config).unwrap(); + /// + /// // Reset to development defaults + /// let reset_config = ConfigManager::reset_to_defaults(&env).unwrap(); + /// + /// // Verify reset to development environment + /// assert_eq!(reset_config.network.environment, Environment::Development); + /// assert_eq!(reset_config.fees.platform_fee_percentage, 2); // Default 2% + /// + /// // Confirm it's stored + /// let stored_config = ConfigManager::get_config(&env).unwrap(); + /// assert_eq!(stored_config.network.environment, Environment::Development); + /// ``` + /// + /// # Reset Behavior + /// + /// Configuration reset: + /// - Uses development configuration as the default baseline + /// - Overwrites any existing stored configuration + /// - Provides safe, conservative settings suitable for testing + /// - Returns the newly stored configuration for immediate use + /// + /// # Use Cases + /// + /// Configuration reset is useful for: + /// - **Testing**: Clean slate for test scenarios + /// - **Recovery**: Restore known-good configuration after issues + /// - **Development**: Quick setup for development environments + /// - **Debugging**: Eliminate configuration as a variable + /// - **Migration**: Safe fallback during configuration updates + /// + /// # Safety Considerations + /// + /// Development defaults provide: + /// - Conservative fee structures + /// - Accessible participation thresholds + /// - Reasonable timeout and retry settings + /// - Safe oracle and resolution parameters pub fn reset_to_defaults(env: &Env) -> Result { let config = Self::get_development_config(env); Self::store_config(env, &config)?; diff --git a/contracts/predictify-hybrid/src/disputes.rs b/contracts/predictify-hybrid/src/disputes.rs index 4a011cc8..f1e9a9ae 100644 --- a/contracts/predictify-hybrid/src/disputes.rs +++ b/contracts/predictify-hybrid/src/disputes.rs @@ -10,7 +10,56 @@ use soroban_sdk::{contracttype, symbol_short, Address, Env, Map, String, Symbol, // ===== DISPUTE STRUCTURES ===== -/// Represents a dispute on a market +/// Represents a formal dispute against a market's oracle resolution. +/// +/// A dispute is created when a community member challenges the oracle's +/// resolution of a market, believing the outcome is incorrect. Disputes +/// require a stake to prevent spam and ensure serious commitment. +/// +/// # Fields +/// +/// * `user` - Address of the user who initiated the dispute +/// * `market_id` - Unique identifier of the disputed market +/// * `stake` - Amount staked by the disputer (must meet minimum requirements) +/// * `timestamp` - When the dispute was created (ledger timestamp) +/// * `reason` - Optional explanation for why the dispute was raised +/// * `status` - Current status of the dispute (Active, Resolved, etc.) +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String}; +/// # use predictify_hybrid::disputes::{Dispute, DisputeStatus}; +/// # let env = Env::default(); +/// # let user = Address::generate(&env); +/// # let market_id = Symbol::new(&env, "market_123"); +/// +/// let dispute = Dispute { +/// user: user.clone(), +/// market_id: market_id.clone(), +/// stake: 10_000_000, // 1 XLM +/// timestamp: env.ledger().timestamp(), +/// reason: Some(String::from_str(&env, "Oracle data appears incorrect")), +/// status: DisputeStatus::Active, +/// }; +/// +/// // Dispute is now active and awaiting community voting +/// assert_eq!(dispute.status, DisputeStatus::Active); +/// ``` +/// +/// # Dispute Lifecycle +/// +/// 1. **Creation**: User stakes tokens and provides reasoning +/// 2. **Community Voting**: Other users vote on dispute validity +/// 3. **Resolution**: Dispute is resolved based on community consensus +/// 4. **Fee Distribution**: Stakes are distributed to winning side +/// +/// # Staking Requirements +/// +/// - Minimum stake amount enforced to prevent spam +/// - Stake is locked during dispute resolution +/// - Winners receive their stake back plus rewards +/// - Losers forfeit their stake to the winning side #[contracttype] pub struct Dispute { pub user: Address, @@ -21,7 +70,52 @@ pub struct Dispute { pub status: DisputeStatus, } -/// Represents the status of a dispute +/// Represents the current lifecycle status of a dispute. +/// +/// Disputes progress through various states from creation to final resolution. +/// Each status indicates what actions are available and the dispute's current phase. +/// +/// # Variants +/// +/// * `Active` - Dispute is open and accepting community votes +/// * `Resolved` - Dispute has been resolved with a final outcome +/// * `Rejected` - Dispute was rejected by community consensus +/// * `Expired` - Dispute voting period ended without sufficient participation +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::disputes::DisputeStatus; +/// +/// // Check if dispute can still receive votes +/// let status = DisputeStatus::Active; +/// let can_vote = matches!(status, DisputeStatus::Active); +/// assert!(can_vote); +/// +/// // Check if dispute is finalized +/// let final_status = DisputeStatus::Resolved; +/// let is_final = matches!(final_status, +/// DisputeStatus::Resolved | DisputeStatus::Rejected | DisputeStatus::Expired +/// ); +/// assert!(is_final); +/// ``` +/// +/// # Status Transitions +/// +/// Valid transitions: +/// - `Active` → `Resolved` (community upholds dispute) +/// - `Active` → `Rejected` (community rejects dispute) +/// - `Active` → `Expired` (insufficient voting participation) +/// +/// Invalid transitions: +/// - Any final status → Any other status (disputes are immutable once resolved) +/// +/// # Business Logic +/// +/// - **Active**: Dispute accepts votes, market resolution is pending +/// - **Resolved**: Oracle result overturned, new outcome established +/// - **Rejected**: Oracle result upheld, original outcome stands +/// - **Expired**: Insufficient community engagement, original outcome stands #[contracttype] pub enum DisputeStatus { Active, @@ -30,7 +124,56 @@ pub enum DisputeStatus { Expired, } -/// Represents dispute statistics for a market +/// Comprehensive statistics about disputes for a specific market. +/// +/// This structure aggregates dispute activity data to provide insights into +/// community engagement, dispute patterns, and market controversy levels. +/// Used for analytics, governance decisions, and market quality assessment. +/// +/// # Fields +/// +/// * `total_disputes` - Total number of disputes ever raised for this market +/// * `total_dispute_stakes` - Sum of all stakes committed to disputes (in stroops) +/// * `active_disputes` - Number of disputes currently accepting votes +/// * `resolved_disputes` - Number of disputes that have been finalized +/// * `unique_disputers` - Count of unique addresses that have disputed this market +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::disputes::DisputeStats; +/// +/// let stats = DisputeStats { +/// total_disputes: 3, +/// total_dispute_stakes: 50_000_000, // 5 XLM total +/// active_disputes: 1, +/// resolved_disputes: 2, +/// unique_disputers: 3, +/// }; +/// +/// // Calculate average stake per dispute +/// let avg_stake = stats.total_dispute_stakes / stats.total_disputes as i128; +/// assert_eq!(avg_stake, 16_666_666); // ~1.67 XLM average +/// +/// // Check market controversy level +/// let controversy_ratio = stats.total_disputes as f64 / 10.0; // Assume 10 total participants +/// println!("Market controversy: {:.1}%", controversy_ratio * 100.0); +/// ``` +/// +/// # Analytics Use Cases +/// +/// - **Market Quality**: High dispute rates may indicate poor oracle data +/// - **Community Engagement**: Dispute participation shows market interest +/// - **Economic Impact**: Total stakes show financial commitment to accuracy +/// - **Resolution Efficiency**: Active vs resolved ratio shows processing speed +/// +/// # Governance Insights +/// +/// Statistics help identify: +/// - Markets requiring oracle provider review +/// - Patterns of systematic disputes +/// - Community confidence in specific market types +/// - Economic incentive effectiveness #[contracttype] pub struct DisputeStats { pub total_disputes: u32, @@ -40,7 +183,66 @@ pub struct DisputeStats { pub unique_disputers: u32, } -/// Represents dispute resolution data +/// Contains the final resolution data for a completed dispute process. +/// +/// This structure captures the outcome of the hybrid resolution system, +/// combining oracle data with community voting to determine the final +/// market result. Used for transparency and audit trails. +/// +/// # Fields +/// +/// * `market_id` - Unique identifier of the resolved market +/// * `final_outcome` - The definitive outcome after dispute resolution +/// * `oracle_weight` - Influence of oracle data in final decision (scaled integer) +/// * `community_weight` - Influence of community votes in final decision (scaled integer) +/// * `dispute_impact` - How much disputes affected the final outcome (scaled integer) +/// * `resolution_timestamp` - When the final resolution was determined +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, String}; +/// # use predictify_hybrid::disputes::DisputeResolution; +/// # let env = Env::default(); +/// +/// let resolution = DisputeResolution { +/// market_id: Symbol::new(&env, "btc_100k"), +/// final_outcome: String::from_str(&env, "No"), +/// oracle_weight: 60, // 60% oracle influence +/// community_weight: 40, // 40% community influence +/// dispute_impact: 25, // 25% change from original oracle result +/// resolution_timestamp: env.ledger().timestamp(), +/// }; +/// +/// // Verify hybrid resolution weights sum to 100% +/// assert_eq!(resolution.oracle_weight + resolution.community_weight, 100); +/// +/// // Check if community significantly influenced outcome +/// let community_influenced = resolution.dispute_impact > 20; +/// assert!(community_influenced); +/// ``` +/// +/// # Hybrid Resolution Model +/// +/// The resolution combines: +/// 1. **Oracle Data**: Automated, objective data source +/// 2. **Community Voting**: Human judgment and local knowledge +/// 3. **Dispute Impact**: Measure of how much community changed oracle result +/// +/// # Weight Calculation +/// +/// - Weights are scaled integers (0-100) representing percentages +/// - Oracle weight typically higher for objective markets +/// - Community weight increases with dispute strength +/// - Final outcome balances both sources proportionally +/// +/// # Transparency Features +/// +/// Resolution data provides: +/// - Clear audit trail of decision factors +/// - Quantified influence of each resolution source +/// - Timestamp for regulatory compliance +/// - Outcome justification for participants #[contracttype] pub struct DisputeResolution { pub market_id: Symbol, @@ -51,7 +253,65 @@ pub struct DisputeResolution { pub resolution_timestamp: u64, } -/// Represents a dispute vote +/// Represents an individual vote cast on a dispute by a community member. +/// +/// Community members can vote on active disputes to express their opinion +/// on whether the dispute is valid. Votes are weighted by stake to ensure +/// economic alignment and prevent manipulation. +/// +/// # Fields +/// +/// * `user` - Address of the voter +/// * `dispute_id` - Unique identifier of the dispute being voted on +/// * `vote` - Boolean vote (true = support dispute, false = reject dispute) +/// * `stake` - Amount staked with this vote (determines voting power) +/// * `timestamp` - When the vote was cast +/// * `reason` - Optional explanation for the vote decision +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String}; +/// # use predictify_hybrid::disputes::DisputeVote; +/// # let env = Env::default(); +/// # let voter = Address::generate(&env); +/// # let dispute_id = Symbol::new(&env, "dispute_123"); +/// +/// let vote = DisputeVote { +/// user: voter.clone(), +/// dispute_id: dispute_id.clone(), +/// vote: true, // Supporting the dispute +/// stake: 5_000_000, // 0.5 XLM voting power +/// timestamp: env.ledger().timestamp(), +/// reason: Some(String::from_str(&env, "Oracle data contradicts reliable sources")), +/// }; +/// +/// // Vote supports the dispute with economic backing +/// assert!(vote.vote); +/// assert!(vote.stake > 0); +/// ``` +/// +/// # Voting Mechanics +/// +/// - **Stake-Weighted**: Higher stakes carry more voting power +/// - **Binary Choice**: Support (true) or reject (false) the dispute +/// - **Economic Commitment**: Voters risk their stake on the outcome +/// - **Transparent Reasoning**: Optional explanations for accountability +/// +/// # Vote Outcomes +/// +/// - **Support (true)**: Voter believes dispute is valid, oracle was wrong +/// - **Reject (false)**: Voter believes dispute is invalid, oracle was correct +/// - **Winning Side**: Receives their stake back plus rewards from losing side +/// - **Losing Side**: Forfeits stake to winners as penalty for incorrect vote +/// +/// # Governance Features +/// +/// Dispute voting enables: +/// - Democratic resolution of oracle disagreements +/// - Economic incentives for accurate voting +/// - Community oversight of oracle quality +/// - Transparent decision-making process #[contracttype] #[derive(Clone)] pub struct DisputeVote { @@ -63,7 +323,73 @@ pub struct DisputeVote { pub reason: Option, } -/// Represents dispute voting data +/// Aggregated voting data and metadata for a dispute resolution process. +/// +/// This structure tracks the complete voting process for a dispute, +/// including participation metrics, stake distribution, and timing. +/// Used to determine dispute outcomes and manage the voting lifecycle. +/// +/// # Fields +/// +/// * `dispute_id` - Unique identifier of the dispute being voted on +/// * `voting_start` - Timestamp when voting period began +/// * `voting_end` - Timestamp when voting period ends +/// * `total_votes` - Total number of individual votes cast +/// * `support_votes` - Number of votes supporting the dispute +/// * `against_votes` - Number of votes rejecting the dispute +/// * `total_support_stake` - Total stake backing dispute support +/// * `total_against_stake` - Total stake backing dispute rejection +/// * `status` - Current status of the voting process +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol}; +/// # use predictify_hybrid::disputes::{DisputeVoting, DisputeVotingStatus}; +/// # let env = Env::default(); +/// +/// let voting = DisputeVoting { +/// dispute_id: Symbol::new(&env, "dispute_123"), +/// voting_start: env.ledger().timestamp(), +/// voting_end: env.ledger().timestamp() + 86400, // 24 hours +/// total_votes: 15, +/// support_votes: 8, +/// against_votes: 7, +/// total_support_stake: 25_000_000, // 2.5 XLM +/// total_against_stake: 20_000_000, // 2.0 XLM +/// status: DisputeVotingStatus::Active, +/// }; +/// +/// // Calculate voting metrics +/// let participation_rate = voting.total_votes as f64 / 100.0; // Assume 100 eligible voters +/// let stake_ratio = voting.total_support_stake as f64 / voting.total_against_stake as f64; +/// +/// println!("Participation: {:.1}%, Stake ratio: {:.2}", +/// participation_rate * 100.0, stake_ratio); +/// ``` +/// +/// # Voting Period Management +/// +/// - **Start Time**: When dispute voting opens to community +/// - **End Time**: Deadline for vote submission (typically 24-48 hours) +/// - **Status Tracking**: Monitors voting process lifecycle +/// - **Early Resolution**: May close early if outcome is decisive +/// +/// # Outcome Determination +/// +/// Resolution considers both: +/// 1. **Vote Count**: Simple majority of individual votes +/// 2. **Stake Weight**: Economic weight of supporting stakes +/// 3. **Participation Threshold**: Minimum votes required for validity +/// 4. **Stake Threshold**: Minimum total stake for legitimacy +/// +/// # Analytics and Insights +/// +/// Voting data provides: +/// - Community engagement levels +/// - Economic commitment to accuracy +/// - Dispute resolution efficiency +/// - Market controversy indicators #[contracttype] pub struct DisputeVoting { pub dispute_id: Symbol, @@ -77,7 +403,55 @@ pub struct DisputeVoting { pub status: DisputeVotingStatus, } -/// Represents dispute voting status +/// Current status of a dispute voting process. +/// +/// Tracks the lifecycle of community voting on disputes, from initiation +/// through completion or termination. Each status determines what actions +/// are available and how the voting process should be handled. +/// +/// # Variants +/// +/// * `Active` - Voting is open and accepting community votes +/// * `Completed` - Voting period ended with sufficient participation +/// * `Expired` - Voting period ended without meeting minimum requirements +/// * `Cancelled` - Voting was terminated early (e.g., by admin action) +/// +/// # Example +/// +/// ```rust +/// # use predictify_hybrid::disputes::DisputeVotingStatus; +/// +/// // Check if voting is still accepting votes +/// let status = DisputeVotingStatus::Active; +/// let can_vote = matches!(status, DisputeVotingStatus::Active); +/// assert!(can_vote); +/// +/// // Check if voting has concluded +/// let final_status = DisputeVotingStatus::Completed; +/// let is_concluded = matches!(final_status, +/// DisputeVotingStatus::Completed | +/// DisputeVotingStatus::Expired | +/// DisputeVotingStatus::Cancelled +/// ); +/// assert!(is_concluded); +/// ``` +/// +/// # Status Transitions +/// +/// Valid transitions: +/// - `Active` → `Completed` (successful voting completion) +/// - `Active` → `Expired` (insufficient participation) +/// - `Active` → `Cancelled` (administrative termination) +/// +/// Invalid transitions: +/// - Any final status → Any other status (voting outcomes are immutable) +/// +/// # Business Logic by Status +/// +/// - **Active**: Accept votes, track participation, monitor deadlines +/// - **Completed**: Process results, distribute rewards, update dispute status +/// - **Expired**: Apply default outcome, return stakes, log insufficient participation +/// - **Cancelled**: Return all stakes, invalidate dispute, log cancellation reason #[contracttype] pub enum DisputeVotingStatus { Active, @@ -86,7 +460,66 @@ pub enum DisputeVotingStatus { Cancelled, } -/// Represents dispute escalation data +/// Data structure for disputes that have been escalated to higher authority. +/// +/// When standard community voting cannot resolve a dispute (due to ties, +/// insufficient participation, or complexity), the dispute can be escalated +/// to admin review or specialized resolution mechanisms. +/// +/// # Fields +/// +/// * `dispute_id` - Unique identifier of the escalated dispute +/// * `escalated_by` - Address of the user who requested escalation +/// * `escalation_reason` - Explanation for why escalation was necessary +/// * `escalation_timestamp` - When the escalation was requested +/// * `escalation_level` - Tier of escalation (1=admin, 2=governance, etc.) +/// * `requires_admin_review` - Whether admin intervention is needed +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String}; +/// # use predictify_hybrid::disputes::DisputeEscalation; +/// # let env = Env::default(); +/// # let user = Address::generate(&env); +/// +/// let escalation = DisputeEscalation { +/// dispute_id: Symbol::new(&env, "dispute_456"), +/// escalated_by: user.clone(), +/// escalation_reason: String::from_str(&env, +/// "Voting resulted in exact tie, need admin decision"), +/// escalation_timestamp: env.ledger().timestamp(), +/// escalation_level: 1, // Admin review +/// requires_admin_review: true, +/// }; +/// +/// // Escalation requires admin intervention +/// assert!(escalation.requires_admin_review); +/// assert_eq!(escalation.escalation_level, 1); +/// ``` +/// +/// # Escalation Triggers +/// +/// Disputes may be escalated when: +/// - **Voting Ties**: Equal stakes on both sides +/// - **Low Participation**: Insufficient community engagement +/// - **Technical Issues**: Oracle data unavailable or corrupted +/// - **Complex Cases**: Subjective outcomes requiring expert judgment +/// - **Appeal Requests**: Losing party contests the result +/// +/// # Escalation Levels +/// +/// 1. **Level 1**: Admin review and decision +/// 2. **Level 2**: Governance token holder voting +/// 3. **Level 3**: External arbitration or expert panel +/// 4. **Level 4**: Legal or regulatory intervention +/// +/// # Resolution Authority +/// +/// - **Admin Review**: Fast resolution for clear-cut cases +/// - **Governance Voting**: Democratic resolution for policy matters +/// - **Expert Panel**: Specialized knowledge for technical disputes +/// - **Legal Process**: Final resort for high-stakes disagreements #[contracttype] pub struct DisputeEscalation { pub dispute_id: Symbol, @@ -97,7 +530,78 @@ pub struct DisputeEscalation { pub requires_admin_review: bool, } -/// Represents dispute fee distribution data +/// Records the distribution of fees and stakes after dispute resolution. +/// +/// When a dispute is resolved, stakes from the losing side are distributed +/// to the winning side as rewards for accurate judgment. This structure +/// tracks the distribution process and ensures transparent fee allocation. +/// +/// # Fields +/// +/// * `dispute_id` - Unique identifier of the resolved dispute +/// * `total_fees` - Total amount available for distribution (in stroops) +/// * `winner_stake` - Total stake from the winning side +/// * `loser_stake` - Total stake from the losing side (becomes rewards) +/// * `winner_addresses` - List of addresses that voted correctly +/// * `distribution_timestamp` - When fees were distributed +/// * `fees_distributed` - Whether distribution has been completed +/// +/// # Example +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, Vec, Address}; +/// # use predictify_hybrid::disputes::DisputeFeeDistribution; +/// # let env = Env::default(); +/// # let mut winners = Vec::new(&env); +/// # winners.push_back(Address::generate(&env)); +/// # winners.push_back(Address::generate(&env)); +/// +/// let distribution = DisputeFeeDistribution { +/// dispute_id: Symbol::new(&env, "dispute_789"), +/// total_fees: 30_000_000, // 3 XLM total +/// winner_stake: 20_000_000, // 2 XLM from winners +/// loser_stake: 10_000_000, // 1 XLM from losers (becomes rewards) +/// winner_addresses: winners, +/// distribution_timestamp: env.ledger().timestamp(), +/// fees_distributed: true, +/// }; +/// +/// // Calculate reward ratio +/// let reward_ratio = distribution.loser_stake as f64 / distribution.winner_stake as f64; +/// println!("Winners receive {:.1}% bonus", reward_ratio * 100.0); +/// +/// // Verify distribution completed +/// assert!(distribution.fees_distributed); +/// ``` +/// +/// # Distribution Mechanics +/// +/// 1. **Stake Recovery**: Winners get their original stakes back +/// 2. **Reward Distribution**: Loser stakes distributed proportionally to winners +/// 3. **Platform Fee**: Small percentage retained for platform operations +/// 4. **Gas Costs**: Distribution transaction costs handled appropriately +/// +/// # Proportional Rewards +/// +/// Winners receive rewards based on: +/// - **Stake Size**: Larger stakes receive proportionally larger rewards +/// - **Timing**: Early voters may receive slight bonuses +/// - **Confidence**: Stronger votes (higher stakes) earn more rewards +/// +/// # Transparency Features +/// +/// - **Public Record**: All distributions are publicly auditable +/// - **Address List**: Winners are explicitly recorded +/// - **Timestamp**: Distribution timing is permanently recorded +/// - **Status Flag**: Clear indication of completion status +/// +/// # Economic Incentives +/// +/// Fee distribution creates: +/// - **Accuracy Rewards**: Economic incentive for correct voting +/// - **Participation Incentive**: Rewards for community engagement +/// - **Quality Control**: Penalties for incorrect dispute judgments +/// - **Platform Sustainability**: Fees support ongoing operations #[contracttype] pub struct DisputeFeeDistribution { pub dispute_id: Symbol, @@ -111,11 +615,135 @@ pub struct DisputeFeeDistribution { // ===== DISPUTE MANAGER ===== -/// Main dispute manager for handling all dispute operations +/// Central manager for all dispute-related operations in the prediction market system. +/// +/// The DisputeManager handles the complete dispute lifecycle, from initial dispute +/// creation through community voting to final resolution and fee distribution. +/// It coordinates between oracle data and community consensus to ensure fair +/// and accurate market outcomes. +/// +/// # Core Responsibilities +/// +/// - **Dispute Processing**: Handle dispute creation and validation +/// - **Community Voting**: Manage voting processes and participation +/// - **Resolution Logic**: Combine oracle and community data for final outcomes +/// - **Fee Distribution**: Distribute stakes and rewards to participants +/// - **Analytics**: Track dispute patterns and market quality metrics +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String}; +/// # use predictify_hybrid::disputes::DisputeManager; +/// # let env = Env::default(); +/// # let user = Address::generate(&env); +/// # let admin = Address::generate(&env); +/// # let market_id = Symbol::new(&env, "market_123"); +/// +/// // User disputes a market result +/// let result = DisputeManager::process_dispute( +/// &env, +/// user.clone(), +/// market_id.clone(), +/// 10_000_000, // 1 XLM stake +/// Some(String::from_str(&env, "Oracle data appears incorrect")) +/// ); +/// +/// // Admin resolves the dispute after community voting +/// let resolution = DisputeManager::resolve_dispute( +/// &env, +/// market_id.clone(), +/// admin.clone() +/// ); +/// ``` +/// +/// # Dispute Workflow +/// +/// 1. **Dispute Creation**: User stakes tokens to challenge oracle result +/// 2. **Validation**: System validates dispute eligibility and parameters +/// 3. **Community Voting**: Other users vote on dispute validity +/// 4. **Resolution**: Combine oracle and community data for final outcome +/// 5. **Distribution**: Distribute stakes and rewards to winning participants +/// +/// # Security Features +/// +/// - **Stake Requirements**: Minimum stakes prevent spam disputes +/// - **Authentication**: All operations require proper user authorization +/// - **Admin Oversight**: Critical operations require admin permissions +/// - **Economic Incentives**: Rewards align with accurate dispute resolution pub struct DisputeManager; impl DisputeManager { - /// Process a user's dispute of market result + /// Processes a user's formal dispute against a market's oracle resolution. + /// + /// This function allows community members to challenge oracle results by + /// staking tokens and providing reasoning. The dispute triggers a community + /// voting process to determine if the oracle result should be overturned. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `user` - Address of the user initiating the dispute (must authenticate) + /// * `market_id` - Unique identifier of the market being disputed + /// * `stake` - Amount to stake on the dispute (must meet minimum requirements) + /// * `reason` - Optional explanation for why the dispute is being raised + /// + /// # Returns + /// + /// Returns `Ok(())` if the dispute is successfully processed, or an `Error` if: + /// - Market is not eligible for disputes (not ended, no oracle result) + /// - Stake amount is below minimum requirements + /// - User has already disputed this market + /// - Market is already in a disputed state + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol, String}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let user = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "btc_price_market"); + /// + /// // User disputes oracle result with reasoning + /// let result = DisputeManager::process_dispute( + /// &env, + /// user.clone(), + /// market_id.clone(), + /// 15_000_000, // 1.5 XLM stake + /// Some(String::from_str(&env, + /// "Oracle price differs significantly from major exchanges")) + /// ); + /// + /// match result { + /// Ok(()) => println!("Dispute successfully created"), + /// Err(e) => println!("Dispute failed: {:?}", e), + /// } + /// ``` + /// + /// # Process Flow + /// + /// 1. **Authentication**: Verify user signature and authorization + /// 2. **Market Validation**: Ensure market is eligible for disputes + /// 3. **Parameter Validation**: Check stake amount and user eligibility + /// 4. **Stake Transfer**: Lock user's stake in the dispute + /// 5. **Dispute Creation**: Create and store dispute record + /// 6. **Market Extension**: Extend market deadline for voting period + /// 7. **Storage Update**: Persist all changes to blockchain storage + /// + /// # Economic Impact + /// + /// - **Stake Lock**: User's stake is locked until dispute resolution + /// - **Market Extension**: Market deadline extended by dispute period + /// - **Voting Incentive**: Other users can earn rewards by voting correctly + /// - **Quality Control**: Economic cost discourages frivolous disputes + /// + /// # Security Considerations + /// + /// - Requires user authentication to prevent unauthorized disputes + /// - Validates market state to ensure disputes are only allowed when appropriate + /// - Enforces minimum stake requirements to prevent spam + /// - Checks for duplicate disputes from the same user pub fn process_dispute( env: &Env, user: Address, @@ -158,7 +786,85 @@ impl DisputeManager { Ok(()) } - /// Resolve a dispute by determining final outcome + /// Resolves a dispute by combining oracle data with community voting results. + /// + /// This function determines the final outcome of a disputed market by analyzing + /// community votes, calculating weights for oracle vs community input, and + /// creating a comprehensive resolution record for transparency and auditability. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to resolve + /// * `admin` - Address of the admin performing the resolution (must authenticate) + /// + /// # Returns + /// + /// Returns a `DisputeResolution` containing the final outcome and resolution + /// metadata, or an `Error` if: + /// - Admin lacks proper permissions + /// - Market is not ready for resolution (voting still active) + /// - Insufficient community participation + /// - Resolution calculation fails + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "disputed_market"); + /// + /// // Admin resolves dispute after voting period + /// let resolution = DisputeManager::resolve_dispute( + /// &env, + /// market_id.clone(), + /// admin.clone() + /// ).unwrap(); + /// + /// // Check resolution details + /// println!("Final outcome: {}", resolution.final_outcome.to_string()); + /// println!("Oracle weight: {}%", resolution.oracle_weight); + /// println!("Community weight: {}%", resolution.community_weight); + /// println!("Dispute impact: {}%", resolution.dispute_impact); + /// + /// // Verify weights sum to 100% + /// assert_eq!(resolution.oracle_weight + resolution.community_weight, 100); + /// ``` + /// + /// # Resolution Algorithm + /// + /// The hybrid resolution process: + /// 1. **Collect Votes**: Aggregate all community votes and stakes + /// 2. **Calculate Impact**: Measure how much disputes affected the outcome + /// 3. **Weight Determination**: Balance oracle reliability vs community consensus + /// 4. **Outcome Synthesis**: Combine weighted inputs for final result + /// 5. **Resolution Record**: Create transparent audit trail + /// + /// # Weighting Logic + /// + /// - **High Oracle Confidence + Low Disputes**: Oracle weight ~80% + /// - **Medium Oracle Confidence + Medium Disputes**: Balanced ~60/40% + /// - **Low Oracle Confidence + High Disputes**: Community weight ~70% + /// - **Tie Situations**: Admin discretion with documented reasoning + /// + /// # Transparency Features + /// + /// Resolution provides complete audit trail: + /// - Final outcome with clear justification + /// - Exact weights used in decision process + /// - Quantified impact of community disputes + /// - Timestamp for regulatory compliance + /// - Immutable record for future reference + /// + /// # Administrative Authority + /// + /// Only authorized admins can resolve disputes to ensure: + /// - Proper validation of voting completion + /// - Correct application of resolution algorithms + /// - Appropriate handling of edge cases + /// - Consistent resolution quality across markets pub fn resolve_dispute( env: &Env, market_id: Symbol, @@ -201,13 +907,134 @@ impl DisputeManager { Ok(resolution) } - /// Get dispute statistics for a market + /// Retrieves comprehensive dispute statistics for a specific market. + /// + /// This function calculates and returns detailed statistics about dispute + /// activity for a market, including participation metrics, stake distribution, + /// and resolution patterns. Used for analytics, governance, and market quality assessment. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to analyze + /// + /// # Returns + /// + /// Returns a `DisputeStats` structure containing comprehensive dispute metrics, + /// or an `Error` if the market is not found. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "analyzed_market"); + /// + /// // Get dispute statistics for analysis + /// let stats = DisputeManager::get_dispute_stats(&env, market_id).unwrap(); + /// + /// // Analyze dispute activity + /// println!("Total disputes: {}", stats.total_disputes); + /// println!("Total stakes: {} XLM", stats.total_dispute_stakes / 10_000_000); + /// println!("Unique disputers: {}", stats.unique_disputers); + /// + /// // Calculate engagement metrics + /// let avg_stake = if stats.total_disputes > 0 { + /// stats.total_dispute_stakes / stats.total_disputes as i128 + /// } else { 0 }; + /// println!("Average stake per dispute: {} XLM", avg_stake / 10_000_000); + /// + /// // Check market controversy level + /// let controversy_ratio = stats.total_disputes as f64 / 100.0; // Assume 100 participants + /// if controversy_ratio > 0.1 { + /// println!("High controversy market detected"); + /// } + /// ``` + /// + /// # Statistics Included + /// + /// The returned statistics provide: + /// - **Total Disputes**: Count of all disputes ever raised + /// - **Total Stakes**: Sum of all dispute stakes in stroops + /// - **Active Disputes**: Number of currently unresolved disputes + /// - **Resolved Disputes**: Number of completed dispute processes + /// - **Unique Disputers**: Count of distinct addresses that disputed + /// + /// # Use Cases + /// + /// - **Market Quality Assessment**: High dispute rates may indicate oracle issues + /// - **Community Engagement**: Participation levels show market interest + /// - **Economic Analysis**: Stake amounts reveal financial commitment + /// - **Governance Decisions**: Data supports policy and parameter adjustments + /// - **Oracle Evaluation**: Dispute patterns help assess oracle reliability pub fn get_dispute_stats(env: &Env, market_id: Symbol) -> Result { let market = MarketStateManager::get_market(env, &market_id)?; Ok(DisputeAnalytics::calculate_dispute_stats(&market)) } - /// Get all disputes for a market + /// Retrieves all dispute records associated with a specific market. + /// + /// This function returns a complete list of all disputes that have been + /// raised against a market, including both active and resolved disputes. + /// Useful for detailed analysis, audit trails, and dispute history review. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to query + /// + /// # Returns + /// + /// Returns a `Vec` containing all dispute records for the market, + /// or an `Error` if the market is not found. Empty vector if no disputes exist. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::disputes::{DisputeManager, DisputeStatus}; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "disputed_market"); + /// + /// // Get all disputes for detailed analysis + /// let disputes = DisputeManager::get_market_disputes(&env, market_id).unwrap(); + /// + /// // Analyze dispute patterns + /// for dispute in disputes.iter() { + /// println!("Dispute by: {}", dispute.user.to_string()); + /// println!("Stake: {} XLM", dispute.stake / 10_000_000); + /// println!("Status: {:?}", dispute.status); + /// + /// if let Some(reason) = &dispute.reason { + /// println!("Reason: {}", reason.to_string()); + /// } + /// } + /// + /// // Filter by status + /// let active_disputes: Vec<_> = disputes.iter() + /// .filter(|d| matches!(d.status, DisputeStatus::Active)) + /// .collect(); + /// + /// println!("Active disputes: {}", active_disputes.len()); + /// ``` + /// + /// # Dispute Information + /// + /// Each dispute record contains: + /// - **User Address**: Who initiated the dispute + /// - **Stake Amount**: Economic commitment to the dispute + /// - **Timestamp**: When the dispute was created + /// - **Reason**: Optional explanation for the dispute + /// - **Status**: Current state (Active, Resolved, Rejected, Expired) + /// + /// # Analysis Applications + /// + /// - **Audit Trails**: Complete history of market challenges + /// - **Pattern Recognition**: Identify systematic dispute trends + /// - **User Behavior**: Analyze disputer participation patterns + /// - **Timeline Analysis**: Track dispute timing and resolution speed + /// - **Quality Metrics**: Assess market and oracle performance pub fn get_market_disputes(env: &Env, market_id: Symbol) -> Result, Error> { let market = MarketStateManager::get_market(env, &market_id)?; Ok(DisputeUtils::extract_disputes_from_market( @@ -215,13 +1042,134 @@ impl DisputeManager { )) } - /// Check if user has disputed a market + /// Checks whether a specific user has already disputed a given market. + /// + /// This function prevents duplicate disputes from the same user and provides + /// a quick way to check user participation in dispute processes. Essential + /// for validation logic and user interface state management. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to check + /// * `user` - Address of the user to check for dispute participation + /// + /// # Returns + /// + /// Returns `true` if the user has disputed this market, `false` if they haven't, + /// or an `Error` if the market is not found. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol, Address}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "market_123"); + /// # let user = Address::generate(&env); + /// + /// // Check if user can dispute (hasn't disputed before) + /// let has_disputed = DisputeManager::has_user_disputed( + /// &env, + /// market_id.clone(), + /// user.clone() + /// ).unwrap(); + /// + /// if has_disputed { + /// println!("User has already disputed this market"); + /// // Show dispute status instead of dispute option + /// } else { + /// println!("User can dispute this market"); + /// // Show dispute creation interface + /// } + /// + /// // Validation before allowing dispute creation + /// if !has_disputed { + /// // Proceed with dispute creation logic + /// println!("Proceeding with dispute creation"); + /// } + /// ``` + /// + /// # Use Cases + /// + /// - **Duplicate Prevention**: Ensure users can only dispute once per market + /// - **UI State Management**: Show appropriate interface based on user status + /// - **Validation Logic**: Pre-validate dispute creation requests + /// - **User Analytics**: Track user participation across markets + /// - **Access Control**: Implement business rules for dispute eligibility + /// + /// # Business Rules + /// + /// - Users can only dispute a market once to prevent spam + /// - Check is performed before allowing dispute creation + /// - Historical disputes (resolved/rejected) still count as "disputed" + /// - Essential for maintaining dispute system integrity pub fn has_user_disputed(env: &Env, market_id: Symbol, user: Address) -> Result { let market = MarketStateManager::get_market(env, &market_id)?; Ok(DisputeUtils::has_user_disputed(&market, &user)) } - /// Get user's dispute stake for a market + /// Retrieves the total stake amount a user has committed to disputes on a market. + /// + /// This function returns the amount a user has staked when disputing a market, + /// which is locked until dispute resolution. Used for displaying user positions, + /// calculating potential rewards, and managing stake-related operations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to query + /// * `user` - Address of the user whose stake to retrieve + /// + /// # Returns + /// + /// Returns the user's dispute stake amount in stroops, or `0` if the user + /// has not disputed this market. Returns an `Error` if the market is not found. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol, Address}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "staked_market"); + /// # let user = Address::generate(&env); + /// + /// // Get user's dispute stake + /// let stake = DisputeManager::get_user_dispute_stake( + /// &env, + /// market_id.clone(), + /// user.clone() + /// ).unwrap(); + /// + /// if stake > 0 { + /// println!("User has {} XLM staked in disputes", stake / 10_000_000); + /// + /// // Calculate potential rewards (example logic) + /// let potential_reward = stake * 120 / 100; // 20% bonus if dispute wins + /// println!("Potential reward: {} XLM", potential_reward / 10_000_000); + /// + /// // Show stake status in UI + /// println!("Stake is locked until dispute resolution"); + /// } else { + /// println!("User has not disputed this market"); + /// } + /// ``` + /// + /// # Stake Management + /// + /// - **Locked Funds**: Stake is locked until dispute resolution + /// - **Reward Calculation**: Basis for calculating potential rewards + /// - **Risk Assessment**: Shows user's economic exposure + /// - **Portfolio Tracking**: Part of user's total locked assets + /// + /// # Use Cases + /// + /// - **User Dashboards**: Display locked stake amounts + /// - **Reward Calculations**: Determine potential dispute rewards + /// - **Risk Management**: Show user's economic exposure + /// - **Portfolio Analytics**: Track user's dispute participation + /// - **Liquidity Planning**: Account for locked funds in user balance pub fn get_user_dispute_stake( env: &Env, market_id: Symbol, @@ -231,7 +1179,99 @@ impl DisputeManager { Ok(DisputeUtils::get_user_dispute_stake(&market, &user)) } - /// Vote on a dispute + /// Allows community members to vote on the validity of a dispute. + /// + /// This function enables users to participate in dispute resolution by casting + /// weighted votes (backed by stakes) on whether they believe a dispute is valid. + /// Votes determine the final outcome and reward distribution. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `user` - Address of the user casting the vote (must authenticate) + /// * `market_id` - Unique identifier of the disputed market + /// * `dispute_id` - Unique identifier of the specific dispute + /// * `vote` - Boolean vote (true = support dispute, false = reject dispute) + /// * `stake` - Amount to stake with the vote (determines voting power) + /// * `reason` - Optional explanation for the vote decision + /// + /// # Returns + /// + /// Returns `Ok(())` if the vote is successfully recorded, or an `Error` if: + /// - User has already voted on this dispute + /// - Dispute voting period has ended + /// - Stake amount is below minimum requirements + /// - Dispute is not in an active voting state + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol, String}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let voter = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "disputed_market"); + /// # let dispute_id = Symbol::new(&env, "dispute_456"); + /// + /// // Vote to support the dispute + /// let result = DisputeManager::vote_on_dispute( + /// &env, + /// voter.clone(), + /// market_id.clone(), + /// dispute_id.clone(), + /// true, // Supporting the dispute + /// 5_000_000, // 0.5 XLM voting power + /// Some(String::from_str(&env, "Oracle data contradicts multiple sources")) + /// ); + /// + /// match result { + /// Ok(()) => println!("Vote successfully recorded"), + /// Err(e) => println!("Vote failed: {:?}", e), + /// } + /// + /// // Vote to reject the dispute + /// let other_voter = Address::generate(&env); + /// let reject_result = DisputeManager::vote_on_dispute( + /// &env, + /// other_voter, + /// market_id, + /// dispute_id, + /// false, // Rejecting the dispute + /// 3_000_000, // 0.3 XLM voting power + /// Some(String::from_str(&env, "Oracle data appears accurate")) + /// ); + /// ``` + /// + /// # Voting Mechanics + /// + /// - **Stake-Weighted**: Higher stakes provide more voting influence + /// - **Binary Choice**: Support (true) or reject (false) the dispute + /// - **Economic Risk**: Voters risk their stake on the outcome + /// - **Transparent Process**: All votes are recorded with optional reasoning + /// + /// # Vote Outcomes + /// + /// - **Support Vote (true)**: Believes dispute is valid, oracle was incorrect + /// - **Reject Vote (false)**: Believes dispute is invalid, oracle was correct + /// - **Winning Side**: Receives stake back plus proportional rewards + /// - **Losing Side**: Forfeits stake to winners as accuracy incentive + /// + /// # Process Flow + /// + /// 1. **Authentication**: Verify voter signature and authorization + /// 2. **Validation**: Check voting eligibility and dispute status + /// 3. **Stake Transfer**: Lock voter's stake with the vote + /// 4. **Vote Recording**: Store vote with timestamp and reasoning + /// 5. **Event Emission**: Broadcast vote event for transparency + /// 6. **Aggregation**: Update dispute voting statistics + /// + /// # Economic Incentives + /// + /// Voting creates strong incentives for accuracy: + /// - Correct votes earn rewards from incorrect votes + /// - Stake amounts reflect voter confidence + /// - Economic penalties discourage frivolous voting + /// - Proportional rewards based on stake size pub fn vote_on_dispute( env: &Env, user: Address, @@ -272,7 +1312,69 @@ impl DisputeManager { Ok(()) } - /// Calculate dispute outcome based on voting + /// Calculates the final outcome of a dispute based on community voting results. + /// + /// This function analyzes all votes cast on a dispute, applies stake weighting, + /// and determines whether the dispute should be upheld (true) or rejected (false). + /// The calculation considers both vote counts and economic stakes. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `dispute_id` - Unique identifier of the dispute to calculate outcome for + /// + /// # Returns + /// + /// Returns `true` if the dispute is upheld (oracle was wrong), `false` if rejected + /// (oracle was correct), or an `Error` if: + /// - Dispute is not found + /// - Voting period is still active + /// - Insufficient votes to determine outcome + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let dispute_id = Symbol::new(&env, "completed_dispute"); + /// + /// // Calculate outcome after voting period ends + /// let outcome = DisputeManager::calculate_dispute_outcome( + /// &env, + /// dispute_id.clone() + /// ).unwrap(); + /// + /// if outcome { + /// println!("Dispute upheld - oracle result overturned"); + /// // Community believes oracle was incorrect + /// } else { + /// println!("Dispute rejected - oracle result stands"); + /// // Community believes oracle was correct + /// } + /// ``` + /// + /// # Calculation Algorithm + /// + /// The outcome determination process: + /// 1. **Vote Aggregation**: Collect all votes with stakes + /// 2. **Stake Weighting**: Apply economic weight to each vote + /// 3. **Threshold Analysis**: Check minimum participation requirements + /// 4. **Outcome Decision**: Determine result based on weighted consensus + /// + /// # Weighting Logic + /// + /// - **Stake-Weighted Voting**: Larger stakes have more influence + /// - **Participation Threshold**: Minimum votes required for validity + /// - **Economic Consensus**: Stakes must exceed minimum threshold + /// - **Tie Breaking**: Admin intervention required for exact ties + /// + /// # Use Cases + /// + /// - **Resolution Processing**: Determine final dispute outcome + /// - **Fee Distribution**: Basis for distributing stakes to winners + /// - **Market Finalization**: Update market with final result + /// - **Analytics**: Track dispute resolution patterns pub fn calculate_dispute_outcome(env: &Env, dispute_id: Symbol) -> Result { // Get dispute voting data let voting_data = DisputeUtils::get_dispute_voting(env, &dispute_id)?; @@ -286,7 +1388,77 @@ impl DisputeManager { Ok(outcome) } - /// Distribute dispute fees to winners + /// Distributes stakes and fees to the winning side of a resolved dispute. + /// + /// This function calculates and executes the distribution of stakes from + /// losing voters to winning voters, creating economic incentives for + /// accurate dispute resolution participation. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `dispute_id` - Unique identifier of the resolved dispute + /// + /// # Returns + /// + /// Returns a `DisputeFeeDistribution` record containing distribution details, + /// or an `Error` if: + /// - Dispute is not ready for distribution + /// - Outcome calculation fails + /// - Distribution transaction fails + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let dispute_id = Symbol::new(&env, "resolved_dispute"); + /// + /// // Distribute fees after dispute resolution + /// let distribution = DisputeManager::distribute_dispute_fees( + /// &env, + /// dispute_id.clone() + /// ).unwrap(); + /// + /// // Check distribution results + /// println!("Total fees distributed: {} XLM", + /// distribution.total_fees / 10_000_000); + /// println!("Winners: {} addresses", + /// distribution.winner_addresses.len()); + /// println!("Winner stake: {} XLM", + /// distribution.winner_stake / 10_000_000); + /// println!("Loser stake (rewards): {} XLM", + /// distribution.loser_stake / 10_000_000); + /// + /// // Calculate reward ratio + /// let reward_ratio = distribution.loser_stake as f64 / + /// distribution.winner_stake as f64; + /// println!("Winners receive {:.1}% bonus", reward_ratio * 100.0); + /// ``` + /// + /// # Distribution Mechanics + /// + /// 1. **Outcome Determination**: Calculate which side won + /// 2. **Stake Aggregation**: Sum stakes from winning and losing sides + /// 3. **Proportional Distribution**: Distribute loser stakes to winners + /// 4. **Platform Fee**: Deduct small percentage for operations + /// 5. **Transaction Execution**: Transfer funds to winner addresses + /// + /// # Reward Calculation + /// + /// Winners receive: + /// - **Original Stake**: Full recovery of their staked amount + /// - **Proportional Bonus**: Share of losing side's stakes + /// - **Early Voter Bonus**: Potential bonus for early participation + /// + /// # Economic Incentives + /// + /// Fee distribution creates: + /// - **Accuracy Rewards**: Economic benefit for correct voting + /// - **Participation Incentive**: Rewards encourage community engagement + /// - **Quality Control**: Penalties for incorrect dispute judgments + /// - **Platform Sustainability**: Small fees support operations pub fn distribute_dispute_fees( env: &Env, dispute_id: Symbol, @@ -314,7 +1486,84 @@ impl DisputeManager { Ok(fee_distribution) } - /// Escalate a dispute + /// Escalates a dispute to higher authority when standard resolution fails. + /// + /// This function allows users to escalate disputes that cannot be resolved + /// through normal community voting, such as ties, low participation, or + /// complex cases requiring expert judgment. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `user` - Address of the user requesting escalation (must authenticate) + /// * `dispute_id` - Unique identifier of the dispute to escalate + /// * `reason` - Explanation for why escalation is necessary + /// + /// # Returns + /// + /// Returns a `DisputeEscalation` record containing escalation details, + /// or an `Error` if: + /// - User lacks permission to escalate + /// - Dispute is not eligible for escalation + /// - Escalation reason is insufficient + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol, String}; + /// # use predictify_hybrid::disputes::DisputeManager; + /// # let env = Env::default(); + /// # let user = Address::generate(&env); + /// # let dispute_id = Symbol::new(&env, "tied_dispute"); + /// + /// // Escalate a dispute with exact vote tie + /// let escalation = DisputeManager::escalate_dispute( + /// &env, + /// user.clone(), + /// dispute_id.clone(), + /// String::from_str(&env, + /// "Voting resulted in exact tie with equal stakes on both sides") + /// ).unwrap(); + /// + /// // Check escalation details + /// println!("Escalated by: {}", escalation.escalated_by.to_string()); + /// println!("Escalation level: {}", escalation.escalation_level); + /// println!("Requires admin review: {}", escalation.requires_admin_review); + /// println!("Reason: {}", escalation.escalation_reason.to_string()); + /// ``` + /// + /// # Escalation Triggers + /// + /// Valid reasons for escalation: + /// - **Exact Ties**: Equal stakes on both sides + /// - **Low Participation**: Insufficient community voting + /// - **Technical Issues**: Oracle data problems or system errors + /// - **Complex Cases**: Subjective outcomes requiring expert judgment + /// - **Appeal Process**: Losing party contests the result + /// + /// # Escalation Levels + /// + /// 1. **Level 1**: Admin review and decision + /// 2. **Level 2**: Governance token holder voting + /// 3. **Level 3**: External arbitration panel + /// 4. **Level 4**: Legal or regulatory intervention + /// + /// # Process Flow + /// + /// 1. **Authentication**: Verify escalation requester + /// 2. **Validation**: Check escalation eligibility + /// 3. **Record Creation**: Store escalation with reasoning + /// 4. **Admin Notification**: Alert administrators of escalation + /// 5. **Status Update**: Mark dispute as escalated + /// 6. **Event Emission**: Broadcast escalation event + /// + /// # Resolution Authority + /// + /// Escalated disputes require: + /// - **Admin Review**: Manual evaluation by authorized administrators + /// - **Expert Judgment**: Specialized knowledge for complex cases + /// - **Governance Process**: Community governance for policy matters + /// - **External Arbitration**: Independent third-party resolution pub fn escalate_dispute( env: &Env, user: Address, diff --git a/contracts/predictify-hybrid/src/errors.rs b/contracts/predictify-hybrid/src/errors.rs index 1ac329e5..55716a39 100644 --- a/contracts/predictify-hybrid/src/errors.rs +++ b/contracts/predictify-hybrid/src/errors.rs @@ -2,7 +2,81 @@ use soroban_sdk::contracterror; -/// Essential error codes for Predictify Hybrid contract +/// Comprehensive error codes for the Predictify Hybrid prediction market contract. +/// +/// This enum defines all possible error conditions that can occur within the Predictify Hybrid +/// smart contract system. Each error is assigned a unique numeric code for efficient handling +/// and clear identification. The errors are organized into logical categories for better +/// understanding and maintenance. +/// +/// # Error Categories +/// +/// **User Operation Errors (100-199):** +/// - Authentication and authorization failures +/// - Market access and state violations +/// - User action conflicts and restrictions +/// +/// **Oracle Errors (200-299):** +/// - Oracle connectivity and availability issues +/// - Oracle configuration and validation problems +/// +/// **Validation Errors (300-399):** +/// - Input validation failures +/// - Parameter format and range violations +/// - Configuration validation errors +/// +/// **System Errors (400-499):** +/// - System state and configuration issues +/// - Dispute and governance related errors +/// - Fee and extension management errors +/// +/// # Example Usage +/// +/// ```rust +/// # use predictify_hybrid::errors::Error; +/// +/// // Handle specific error types +/// fn handle_market_operation_result(result: Result<(), Error>) { +/// match result { +/// Ok(()) => println!("Operation successful"), +/// Err(Error::Unauthorized) => { +/// println!("Error {}: {}", Error::Unauthorized as u32, Error::Unauthorized.description()); +/// } +/// Err(Error::MarketNotFound) => { +/// println!("Market does not exist or has been removed"); +/// } +/// Err(Error::InsufficientStake) => { +/// println!("Stake amount is below minimum requirement"); +/// } +/// Err(e) => { +/// println!("Operation failed with error {}: {}", e as u32, e.description()); +/// } +/// } +/// } +/// +/// // Get error information +/// let error = Error::MarketClosed; +/// println!("Error Code: {}", error.code()); // "MARKET_CLOSED" +/// println!("Description: {}", error.description()); // "Market is closed" +/// println!("Numeric Code: {}", error as u32); // 102 +/// ``` +/// +/// # Error Handling Best Practices +/// +/// 1. **Specific Handling**: Match specific error types for targeted error handling +/// 2. **User Feedback**: Use `description()` method for user-friendly error messages +/// 3. **Logging**: Use `code()` method for structured logging and monitoring +/// 4. **Recovery**: Implement appropriate recovery strategies for different error types +/// 5. **Validation**: Prevent errors through proper input validation +/// +/// # Integration Points +/// +/// Error enum integrates with: +/// - **All Contract Functions**: Every public function returns Result +/// - **Validation System**: Validation functions return specific error types +/// - **Event System**: Error events are emitted with error codes +/// - **Client Applications**: Error codes enable proper error handling in dApps +/// - **Monitoring Systems**: Error codes support operational monitoring and alerting #[contracterror] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] @@ -93,7 +167,56 @@ pub enum Error { } impl Error { - /// Get a human-readable description of the error + /// Get a human-readable description of the error. + /// + /// This method returns a clear, user-friendly description of the error that can be + /// displayed to end users or included in error messages. The descriptions are written + /// in plain English and explain what went wrong in terms that users can understand. + /// + /// # Returns + /// + /// A static string slice containing a human-readable description of the error. + /// + /// # Example Usage + /// + /// ```rust + /// # use predictify_hybrid::errors::Error; + /// + /// // Display user-friendly error messages + /// let error = Error::InsufficientStake; + /// println!("Operation failed: {}", error.description()); + /// // Output: "Operation failed: Insufficient stake amount" + /// + /// // Use in error handling for user interfaces + /// fn display_error_to_user(error: Error) { + /// let message = format!("Error: {}", error.description()); + /// // Display message in UI + /// println!("{}", message); + /// } + /// + /// // Compare different error descriptions + /// let errors = vec![ + /// Error::MarketNotFound, + /// Error::MarketClosed, + /// Error::AlreadyVoted, + /// ]; + /// + /// for error in errors { + /// println!("{}: {}", error.code(), error.description()); + /// } + /// // Output: + /// // MARKET_NOT_FOUND: Market not found + /// // MARKET_CLOSED: Market is closed + /// // ALREADY_VOTED: User has already voted + /// ``` + /// + /// # Use Cases + /// + /// - **User Interface**: Display error messages to users + /// - **API Responses**: Include descriptions in API error responses + /// - **Logging**: Add context to log entries + /// - **Documentation**: Generate error documentation + /// - **Debugging**: Understand error conditions during development pub fn description(&self) -> &'static str { match self { Error::Unauthorized => "User is not authorized to perform this action", @@ -137,7 +260,69 @@ impl Error { } } - /// Get error code as string + /// Get the error code as a standardized string identifier. + /// + /// This method returns a standardized string representation of the error code that + /// follows a consistent naming convention (UPPER_SNAKE_CASE). These codes are ideal + /// for programmatic error handling, logging, monitoring, and API responses where + /// consistent string identifiers are preferred over numeric codes. + /// + /// # Returns + /// + /// A static string slice containing the standardized error code identifier. + /// + /// # Example Usage + /// + /// ```rust + /// # use predictify_hybrid::errors::Error; + /// + /// // Use for structured logging + /// let error = Error::OracleUnavailable; + /// println!("ERROR_CODE={} MESSAGE={}", error.code(), error.description()); + /// // Output: "ERROR_CODE=ORACLE_UNAVAILABLE MESSAGE=Oracle is unavailable" + /// + /// // Use for API error responses + /// fn create_api_error_response(error: Error) -> String { + /// format!( + /// r#"{{ + /// "error": "{}", + /// "message": "{}", + /// "code": {} + /// }}"", + /// error.code(), + /// error.description(), + /// error as u32 + /// ) + /// } + /// + /// // Use for error categorization + /// fn categorize_error(error: Error) -> &'static str { + /// match error.code() { + /// code if code.starts_with("MARKET_") => "Market Error", + /// code if code.starts_with("ORACLE_") => "Oracle Error", + /// code if code.starts_with("DISPUTE_") => "Dispute Error", + /// _ => "General Error", + /// } + /// } + /// + /// // Use for monitoring and alerting + /// fn should_alert(error: Error) -> bool { + /// matches!(error.code(), + /// "ORACLE_UNAVAILABLE" | + /// "DISPUTE_FEE_DISTRIBUTION_FAILED" | + /// "ADMIN_NOT_SET" + /// ) + /// } + /// ``` + /// + /// # Use Cases + /// + /// - **Structured Logging**: Consistent error identifiers for log analysis + /// - **API Responses**: Machine-readable error codes for client applications + /// - **Monitoring**: Error tracking and alerting based on error types + /// - **Error Categorization**: Group and filter errors by type + /// - **Documentation**: Generate error code reference documentation + /// - **Testing**: Verify specific error conditions in unit tests pub fn code(&self) -> &'static str { match self { Error::Unauthorized => "UNAUTHORIZED", diff --git a/contracts/predictify-hybrid/src/events.rs b/contracts/predictify-hybrid/src/events.rs index cf67dc47..cc5db4fa 100644 --- a/contracts/predictify-hybrid/src/events.rs +++ b/contracts/predictify-hybrid/src/events.rs @@ -27,7 +27,64 @@ pub enum AdminRole { // ===== EVENT TYPES ===== -/// Market creation event +/// Event emitted when a new prediction market is successfully created. +/// +/// This event provides comprehensive information about newly created markets, +/// including market parameters, outcomes, administrative details, and timing. +/// Essential for tracking market creation activity and building market indices. +/// +/// # Event Data +/// +/// Contains all critical market creation parameters: +/// - Market identification and question details +/// - Available outcomes for prediction +/// - Administrative and timing information +/// - Creation timestamp for chronological ordering +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String, Vec}; +/// # use predictify_hybrid::events::MarketCreatedEvent; +/// # let env = Env::default(); +/// # let admin = Address::generate(&env); +/// +/// // Market creation event data +/// let event = MarketCreatedEvent { +/// market_id: Symbol::new(&env, "btc_50k_2024"), +/// question: String::from_str(&env, "Will Bitcoin reach $50,000 by end of 2024?"), +/// outcomes: vec![ +/// &env, +/// String::from_str(&env, "Yes"), +/// String::from_str(&env, "No") +/// ], +/// admin: admin.clone(), +/// end_time: 1735689600, // Dec 31, 2024 +/// timestamp: env.ledger().timestamp(), +/// }; +/// +/// // Event provides complete market context +/// println!("New market: {}", event.question.to_string()); +/// println!("Market ID: {}", event.market_id.to_string()); +/// println!("Outcomes: {} options", event.outcomes.len()); +/// println!("Ends: {}", event.end_time); +/// ``` +/// +/// # Integration Points +/// +/// - **Market Indexing**: Build searchable market directories +/// - **Activity Feeds**: Display recent market creation activity +/// - **Analytics**: Track market creation patterns and trends +/// - **Notifications**: Alert users about new markets in categories of interest +/// - **Audit Trails**: Maintain complete record of market creation events +/// +/// # Event Timing +/// +/// Emitted immediately after successful market creation, providing: +/// - Real-time notification of new markets +/// - Chronological ordering via timestamp +/// - Immediate availability for user interfaces +/// - Historical record for analytics and reporting #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct MarketCreatedEvent { @@ -45,7 +102,67 @@ pub struct MarketCreatedEvent { pub timestamp: u64, } -/// Vote cast event +/// Event emitted when a user successfully casts a vote on a prediction market. +/// +/// This event captures all details of voting activity, including voter identity, +/// chosen outcome, stake amount, and timing. Critical for tracking market +/// participation, calculating outcomes, and maintaining voting transparency. +/// +/// # Vote Information +/// +/// Records complete voting context: +/// - Market and voter identification +/// - Selected outcome and confidence (stake) +/// - Precise timing for chronological analysis +/// - Economic weight for outcome calculations +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String}; +/// # use predictify_hybrid::events::VoteCastEvent; +/// # let env = Env::default(); +/// # let voter = Address::generate(&env); +/// +/// // Vote casting event data +/// let event = VoteCastEvent { +/// market_id: Symbol::new(&env, "btc_50k_2024"), +/// voter: voter.clone(), +/// outcome: String::from_str(&env, "Yes"), +/// stake: 10_000_000, // 1.0 XLM +/// timestamp: env.ledger().timestamp(), +/// }; +/// +/// // Event provides complete voting context +/// println!("Vote cast by: {}", event.voter.to_string()); +/// println!("Market: {}", event.market_id.to_string()); +/// println!("Outcome: {}", event.outcome.to_string()); +/// println!("Stake: {} XLM", event.stake / 10_000_000); +/// ``` +/// +/// # Economic Tracking +/// +/// Enables comprehensive economic analysis: +/// - **Stake Distribution**: Track economic weight across outcomes +/// - **Voter Confidence**: Analyze stake amounts as confidence indicators +/// - **Market Liquidity**: Monitor total stakes and participation levels +/// - **Outcome Probability**: Calculate implied probabilities from stakes +/// +/// # Transparency Features +/// +/// Supports market transparency through: +/// - **Public Voting Records**: All votes are publicly auditable +/// - **Stake Verification**: Economic weights are transparently recorded +/// - **Chronological Ordering**: Precise timing enables trend analysis +/// - **Voter Attribution**: Clear voter identity for accountability +/// +/// # Integration Applications +/// +/// - **Real-time Updates**: Live market activity feeds +/// - **Analytics Dashboards**: Voting pattern analysis and visualization +/// - **Outcome Calculation**: Stake-weighted probability calculations +/// - **User Portfolios**: Track individual voting history and performance +/// - **Market Sentiment**: Aggregate voting trends and momentum analysis #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct VoteCastEvent { @@ -61,7 +178,70 @@ pub struct VoteCastEvent { pub timestamp: u64, } -/// Oracle result fetched event +/// Event emitted when oracle data is successfully fetched for market resolution. +/// +/// This event captures comprehensive oracle data retrieval information, including +/// the specific data source, fetched values, comparison logic, and timing. +/// Essential for transparency, auditability, and dispute resolution processes. +/// +/// # Oracle Data Context +/// +/// Provides complete oracle resolution context: +/// - Market identification and oracle provider details +/// - Actual fetched data values and comparison parameters +/// - Resolution logic and threshold evaluation +/// - Precise timing for chronological verification +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, String}; +/// # use predictify_hybrid::events::OracleResultEvent; +/// # let env = Env::default(); +/// +/// // Oracle result event for Bitcoin price market +/// let event = OracleResultEvent { +/// market_id: Symbol::new(&env, "btc_50k_2024"), +/// result: String::from_str(&env, "Yes"), // Bitcoin reached $50k +/// provider: String::from_str(&env, "Chainlink"), +/// feed_id: String::from_str(&env, "BTC/USD"), +/// price: 52_000_00000000, // $52,000 (8 decimal precision) +/// threshold: 50_000_00000000, // $50,000 threshold +/// comparison: String::from_str(&env, "gte"), // greater than or equal +/// timestamp: env.ledger().timestamp(), +/// }; +/// +/// // Event provides complete oracle context +/// println!("Oracle result: {}", event.result.to_string()); +/// println!("Price fetched: ${}", event.price / 100000000); +/// println!("Threshold: ${}", event.threshold / 100000000); +/// println!("Provider: {}", event.provider.to_string()); +/// println!("Feed: {}", event.feed_id.to_string()); +/// ``` +/// +/// # Transparency and Auditability +/// +/// Enables complete oracle transparency: +/// - **Data Source Verification**: Clear provider and feed identification +/// - **Value Documentation**: Exact fetched values with precision +/// - **Logic Transparency**: Comparison operators and thresholds +/// - **Timing Verification**: Precise fetch timestamps +/// +/// # Dispute Resolution Support +/// +/// Critical for dispute processes: +/// - **Evidence Base**: Concrete data for dispute evaluation +/// - **Verification Path**: Complete audit trail from source to result +/// - **Alternative Validation**: Enable cross-reference with other sources +/// - **Historical Context**: Timestamp-based data verification +/// +/// # Integration Applications +/// +/// - **Oracle Monitoring**: Track oracle performance and reliability +/// - **Data Verification**: Cross-reference oracle results with external sources +/// - **Dispute Analysis**: Provide evidence for community dispute resolution +/// - **Market Analytics**: Analyze oracle accuracy and market outcomes +/// - **Compliance Reporting**: Maintain regulatory audit trails #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct OracleResultEvent { @@ -83,7 +263,73 @@ pub struct OracleResultEvent { pub timestamp: u64, } -/// Market resolved event +/// Event emitted when a prediction market is successfully resolved with final outcome. +/// +/// This event captures the complete resolution process, including the final outcome, +/// resolution methodology (oracle vs. community), confidence metrics, and timing. +/// Critical for market finalization, payout calculations, and resolution transparency. +/// +/// # Resolution Context +/// +/// Provides comprehensive resolution information: +/// - Final market outcome and supporting evidence +/// - Resolution methodology and confidence scoring +/// - Oracle and community input comparison +/// - Timing for chronological resolution tracking +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, String}; +/// # use predictify_hybrid::events::MarketResolvedEvent; +/// # let env = Env::default(); +/// +/// // Market resolution event for Bitcoin price market +/// let event = MarketResolvedEvent { +/// market_id: Symbol::new(&env, "btc_50k_2024"), +/// final_outcome: String::from_str(&env, "Yes"), +/// oracle_result: String::from_str(&env, "Yes"), +/// community_consensus: String::from_str(&env, "Yes"), +/// resolution_method: String::from_str(&env, "Oracle_Community_Consensus"), +/// confidence_score: 95, // 95% confidence +/// timestamp: env.ledger().timestamp(), +/// }; +/// +/// // Event provides complete resolution context +/// println!("Market resolved: {}", event.market_id.to_string()); +/// println!("Final outcome: {}", event.final_outcome.to_string()); +/// println!("Resolution method: {}", event.resolution_method.to_string()); +/// println!("Confidence: {}%", event.confidence_score); +/// +/// // Check consensus alignment +/// let consensus_aligned = event.oracle_result == event.community_consensus; +/// println!("Oracle-Community alignment: {}", consensus_aligned); +/// ``` +/// +/// # Resolution Methods +/// +/// Supports multiple resolution approaches: +/// - **Oracle Only**: Pure oracle-based resolution +/// - **Community Only**: Pure community voting resolution +/// - **Hybrid Consensus**: Oracle and community agreement +/// - **Dispute Resolution**: Community override of oracle result +/// - **Admin Override**: Administrative resolution for edge cases +/// +/// # Confidence Scoring +/// +/// Confidence scores indicate resolution reliability: +/// - **90-100%**: High confidence, strong consensus +/// - **70-89%**: Medium confidence, reasonable consensus +/// - **50-69%**: Low confidence, weak consensus +/// - **Below 50%**: Very low confidence, potential disputes +/// +/// # Integration Applications +/// +/// - **Payout Processing**: Trigger reward distribution to winners +/// - **Market Analytics**: Track resolution accuracy and patterns +/// - **Confidence Metrics**: Display resolution reliability to users +/// - **Dispute Prevention**: Early warning for low-confidence resolutions +/// - **Historical Analysis**: Build resolution methodology effectiveness data #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct MarketResolvedEvent { @@ -103,7 +349,72 @@ pub struct MarketResolvedEvent { pub timestamp: u64, } -/// Dispute created event +/// Event emitted when a user creates a formal dispute against a market resolution. +/// +/// This event captures dispute initiation details, including the disputing party, +/// economic stake, reasoning, and timing. Essential for tracking dispute activity, +/// managing dispute processes, and maintaining resolution transparency. +/// +/// # Dispute Information +/// +/// Records complete dispute context: +/// - Market identification and disputing party +/// - Economic stake demonstrating dispute seriousness +/// - Optional reasoning for dispute justification +/// - Precise timing for dispute process management +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String}; +/// # use predictify_hybrid::events::DisputeCreatedEvent; +/// # let env = Env::default(); +/// # let disputer = Address::generate(&env); +/// +/// // Dispute creation event +/// let event = DisputeCreatedEvent { +/// market_id: Symbol::new(&env, "btc_50k_2024"), +/// disputer: disputer.clone(), +/// stake: 50_000_000, // 5.0 XLM dispute stake +/// reason: Some(String::from_str(&env, +/// "Oracle price appears incorrect - multiple exchanges show different value")), +/// timestamp: env.ledger().timestamp(), +/// }; +/// +/// // Event provides complete dispute context +/// println!("Dispute created by: {}", event.disputer.to_string()); +/// println!("Market disputed: {}", event.market_id.to_string()); +/// println!("Stake amount: {} XLM", event.stake / 10_000_000); +/// +/// if let Some(reason) = &event.reason { +/// println!("Dispute reason: {}", reason.to_string()); +/// } +/// ``` +/// +/// # Economic Stakes +/// +/// Dispute stakes serve multiple purposes: +/// - **Seriousness Filter**: Minimum stake prevents frivolous disputes +/// - **Economic Risk**: Disputers risk stake if dispute is rejected +/// - **Incentive Alignment**: Encourages well-researched disputes +/// - **Compensation Pool**: Stakes fund dispute resolution rewards +/// +/// # Dispute Lifecycle +/// +/// Dispute creation triggers: +/// 1. **Validation**: Check dispute eligibility and stake requirements +/// 2. **Community Voting**: Open dispute for community evaluation +/// 3. **Evidence Collection**: Gather supporting data and arguments +/// 4. **Resolution Process**: Determine dispute validity +/// 5. **Stake Distribution**: Reward accurate participants +/// +/// # Integration Applications +/// +/// - **Dispute Management**: Track and manage active disputes +/// - **Community Engagement**: Notify community of new disputes +/// - **Resolution Analytics**: Analyze dispute patterns and outcomes +/// - **Transparency Reporting**: Maintain public dispute records +/// - **Economic Monitoring**: Track dispute stakes and economic activity #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct DisputeCreatedEvent { @@ -119,7 +430,79 @@ pub struct DisputeCreatedEvent { pub timestamp: u64, } -/// Dispute resolved event +/// Event emitted when a dispute is successfully resolved with final outcome and rewards. +/// +/// This event captures the complete dispute resolution process, including the final +/// outcome, winning and losing participants, fee distribution, and timing. +/// Essential for transparency, reward distribution, and dispute analytics. +/// +/// # Resolution Information +/// +/// Records complete dispute resolution context: +/// - Market identification and final dispute outcome +/// - Winner and loser participant lists +/// - Economic reward distribution amounts +/// - Precise timing for chronological tracking +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String, Vec}; +/// # use predictify_hybrid::events::DisputeResolvedEvent; +/// # let env = Env::default(); +/// # let winner1 = Address::generate(&env); +/// # let winner2 = Address::generate(&env); +/// # let loser1 = Address::generate(&env); +/// +/// // Dispute resolution event +/// let event = DisputeResolvedEvent { +/// market_id: Symbol::new(&env, "btc_50k_2024"), +/// outcome: String::from_str(&env, "Dispute_Upheld"), // Community sided with disputer +/// winners: vec![&env, winner1.clone(), winner2.clone()], // Correct voters +/// losers: vec![&env, loser1.clone()], // Incorrect voters +/// fee_distribution: 25_000_000, // 2.5 XLM distributed to winners +/// timestamp: env.ledger().timestamp(), +/// }; +/// +/// // Event provides complete resolution context +/// println!("Dispute resolved: {}", event.market_id.to_string()); +/// println!("Outcome: {}", event.outcome.to_string()); +/// println!("Winners: {} participants", event.winners.len()); +/// println!("Losers: {} participants", event.losers.len()); +/// println!("Total rewards: {} XLM", event.fee_distribution / 10_000_000); +/// ``` +/// +/// # Resolution Outcomes +/// +/// Possible dispute outcomes: +/// - **Dispute_Upheld**: Community agreed with disputer, oracle was wrong +/// - **Dispute_Rejected**: Community disagreed with disputer, oracle was correct +/// - **Dispute_Inconclusive**: Insufficient consensus, requires escalation +/// - **Dispute_Invalid**: Dispute did not meet validity requirements +/// +/// # Economic Distribution +/// +/// Fee distribution mechanics: +/// - **Winner Rewards**: Proportional share of loser stakes +/// - **Stake Recovery**: Winners recover their original stakes +/// - **Penalty Application**: Losers forfeit stakes to winners +/// - **Platform Fee**: Small percentage retained for operations +/// +/// # Participant Tracking +/// +/// Winner and loser lists enable: +/// - **Reward Distribution**: Direct transfer to winner addresses +/// - **Reputation Tracking**: Build participant accuracy records +/// - **Analytics**: Analyze voting patterns and success rates +/// - **Transparency**: Public record of dispute participation +/// +/// # Integration Applications +/// +/// - **Reward Processing**: Execute payments to winning participants +/// - **Reputation Systems**: Update participant accuracy scores +/// - **Dispute Analytics**: Track resolution patterns and outcomes +/// - **Community Metrics**: Measure dispute system effectiveness +/// - **Transparency Reporting**: Maintain public dispute resolution records #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct DisputeResolvedEvent { diff --git a/contracts/predictify-hybrid/src/extensions.rs b/contracts/predictify-hybrid/src/extensions.rs index ad4b9bfe..d4258f9e 100644 --- a/contracts/predictify-hybrid/src/extensions.rs +++ b/contracts/predictify-hybrid/src/extensions.rs @@ -23,11 +23,165 @@ const MAX_TOTAL_EXTENSIONS: u32 = crate::config::MAX_TOTAL_EXTENSIONS; // ===== EXTENSION MANAGEMENT ===== -/// Market extension management utilities +/// Comprehensive market extension management system for Predictify Hybrid contracts. +/// +/// The ExtensionManager provides a complete solution for extending market durations +/// beyond their original end times. This system includes validation, fee handling, +/// permission checks, and comprehensive tracking of extension history. +/// +/// # Core Functionality +/// +/// - **Duration Extension**: Safely extend market end times with validation +/// - **Fee Management**: Calculate and handle extension fees automatically +/// - **Permission Control**: Ensure only authorized admins can extend markets +/// - **History Tracking**: Maintain complete extension history for transparency +/// - **Limit Enforcement**: Prevent excessive extensions through configurable limits +/// +/// # Extension Process +/// +/// 1. **Validation**: Check market state and extension parameters +/// 2. **Authorization**: Verify admin permissions for the market +/// 3. **Fee Calculation**: Determine extension costs based on duration +/// 4. **Market Update**: Modify market end time and record extension +/// 5. **Event Emission**: Broadcast extension event for transparency +/// +/// # Economic Model +/// +/// Extensions require fees to prevent abuse: +/// - **Per-Day Pricing**: Fixed fee per additional day (configurable) +/// - **Economic Barrier**: Prevents frivolous extension requests +/// - **Revenue Generation**: Fees support platform sustainability +/// - **Fair Access**: Reasonable pricing ensures legitimate use cases +/// +/// # Use Cases +/// +/// - **Market Adjustment**: Extend markets when circumstances change +/// - **Data Availability**: Allow more time for oracle data collection +/// - **Community Request**: Respond to user demand for longer markets +/// - **Technical Issues**: Compensate for system downtime or problems +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol, String}; +/// # use predictify_hybrid::extensions::ExtensionManager; +/// # let env = Env::default(); +/// # let admin = Address::generate(&env); +/// # let market_id = Symbol::new(&env, "btc_market"); +/// +/// // Extend market by 7 days +/// let result = ExtensionManager::extend_market_duration( +/// &env, +/// admin.clone(), +/// market_id.clone(), +/// 7, // Additional days +/// String::from_str(&env, "Extended due to high community interest") +/// ); +/// +/// match result { +/// Ok(()) => println!("Market successfully extended by 7 days"), +/// Err(e) => println!("Extension failed: {:?}", e), +/// } +/// +/// // Check extension history +/// let history = ExtensionManager::get_market_extension_history( +/// &env, +/// market_id.clone() +/// ).unwrap(); +/// +/// println!("Total extensions: {}", history.len()); +/// ``` pub struct ExtensionManager; impl ExtensionManager { - /// Extend market duration with validation and fee handling + /// Extends a market's duration by the specified number of additional days. + /// + /// This function performs comprehensive validation, fee handling, and market + /// updates to safely extend market durations. It includes permission checks, + /// limit enforcement, and complete audit trail maintenance. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - Address of the administrator requesting the extension (must authenticate) + /// * `market_id` - Unique identifier of the market to extend + /// * `additional_days` - Number of days to add to the market duration (1-30) + /// * `reason` - Human-readable explanation for the extension request + /// + /// # Returns + /// + /// Returns `Ok(())` if the extension is successful, or an `Error` if: + /// - Admin lacks permission to extend this market + /// - Extension days are outside allowed range (1-30) + /// - Market has reached maximum total extension limit + /// - Market is not in a state that allows extension + /// - Fee payment fails + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol, String}; + /// # use predictify_hybrid::extensions::ExtensionManager; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "crypto_prediction"); + /// + /// // Extend market for additional data collection + /// let result = ExtensionManager::extend_market_duration( + /// &env, + /// admin.clone(), + /// market_id.clone(), + /// 14, // Two weeks extension + /// String::from_str(&env, "Oracle data delayed, need more time for accurate resolution") + /// ); + /// + /// match result { + /// Ok(()) => { + /// println!("Market extended successfully"); + /// // Extension fee automatically deducted + /// // Market end time updated + /// // Extension event emitted + /// }, + /// Err(e) => println!("Extension failed: {:?}", e), + /// } + /// ``` + /// + /// # Extension Process + /// + /// 1. **Validation Phase**: + /// - Check market exists and is extendable + /// - Validate extension days within limits (1-30) + /// - Verify admin has permission for this market + /// + /// 2. **Economic Phase**: + /// - Calculate extension fee (days × fee_per_day) + /// - Process fee payment from admin account + /// - Record fee in extension history + /// + /// 3. **Update Phase**: + /// - Extend market end time by specified days + /// - Add extension record to market history + /// - Update total extension counters + /// + /// 4. **Event Phase**: + /// - Emit extension event for transparency + /// - Log extension details for audit trail + /// - Update market state in storage + /// + /// # Fee Structure + /// + /// Extension fees are calculated as: + /// - **Base Rate**: 1 XLM per day (configurable) + /// - **Total Cost**: `additional_days × fee_per_day` + /// - **Payment**: Automatically deducted from admin account + /// - **Refund Policy**: No refunds for completed extensions + /// + /// # Security Considerations + /// + /// - **Authentication**: Admin must sign the transaction + /// - **Authorization**: Only market admin can extend their markets + /// - **Rate Limiting**: Maximum extensions per market enforced + /// - **Economic Barriers**: Fees prevent spam extensions pub fn extend_market_duration( env: &Env, admin: Address, @@ -68,7 +222,76 @@ impl ExtensionManager { Ok(()) } - /// Get extension history for a market + /// Retrieves the complete extension history for a specific market. + /// + /// This function returns a chronological list of all extensions that have been + /// applied to a market, providing complete transparency and audit capabilities + /// for market duration modifications. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to query + /// + /// # Returns + /// + /// Returns a `Vec` containing all extension records, + /// or an `Error` if the market is not found. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::extensions::ExtensionManager; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "btc_market"); + /// + /// // Get complete extension history + /// let history = ExtensionManager::get_market_extension_history( + /// &env, + /// market_id.clone() + /// ).unwrap(); + /// + /// // Analyze extension patterns + /// println!("Total extensions: {}", history.len()); + /// + /// let mut total_days = 0u32; + /// let mut total_fees = 0i128; + /// + /// for extension in history.iter() { + /// total_days += extension.additional_days; + /// total_fees += extension.fee_amount; + /// + /// println!("Extension: {} days by {} (fee: {} XLM)", + /// extension.additional_days, + /// extension.admin.to_string(), + /// extension.fee_amount / 10_000_000); + /// + /// if let Some(reason) = &extension.reason { + /// println!("Reason: {}", reason.to_string()); + /// } + /// } + /// + /// println!("Total extended days: {}", total_days); + /// println!("Total fees paid: {} XLM", total_fees / 10_000_000); + /// ``` + /// + /// # Extension Record Contents + /// + /// Each extension record includes: + /// - **Additional Days**: Number of days added in this extension + /// - **Admin Address**: Who requested the extension + /// - **Reason**: Optional explanation for the extension + /// - **Fee Amount**: Cost paid for this extension + /// - **Timestamp**: When the extension was applied + /// + /// # Use Cases + /// + /// - **Audit Trails**: Complete history for compliance and verification + /// - **Analytics**: Analyze extension patterns and market behavior + /// - **Transparency**: Public record of all market modifications + /// - **Fee Tracking**: Monitor extension costs and revenue + /// - **Pattern Analysis**: Identify markets requiring frequent extensions pub fn get_market_extension_history( env: &Env, market_id: Symbol, @@ -77,7 +300,82 @@ impl ExtensionManager { Ok(market.extension_history) } - /// Get extension statistics for a market + /// Retrieves comprehensive extension statistics and capabilities for a market. + /// + /// This function provides a complete overview of a market's extension status, + /// including historical data, current limits, and future extension capabilities. + /// Essential for UI display and extension planning. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to analyze + /// + /// # Returns + /// + /// Returns an `ExtensionStats` struct containing comprehensive statistics, + /// or an `Error` if the market is not found. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::extensions::ExtensionManager; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "crypto_market"); + /// + /// // Get extension statistics + /// let stats = ExtensionManager::get_extension_stats( + /// &env, + /// market_id.clone() + /// ).unwrap(); + /// + /// // Display extension status + /// println!("Extension Statistics for Market: {}", market_id.to_string()); + /// println!("─────────────────────────────────────────"); + /// println!("Total extensions applied: {}", stats.total_extensions); + /// println!("Total days extended: {}", stats.total_extension_days); + /// println!("Maximum extension days: {}", stats.max_extension_days); + /// println!("Can extend further: {}", stats.can_extend); + /// println!("Extension fee per day: {} XLM", + /// stats.extension_fee_per_day / 10_000_000); + /// + /// // Calculate remaining extension capacity + /// let remaining_days = stats.max_extension_days - stats.total_extension_days; + /// println!("Remaining extension capacity: {} days", remaining_days); + /// + /// // Estimate cost for maximum extension + /// if stats.can_extend && remaining_days > 0 { + /// let max_cost = (remaining_days as i128) * stats.extension_fee_per_day; + /// println!("Cost to use remaining capacity: {} XLM", + /// max_cost / 10_000_000); + /// } + /// ``` + /// + /// # Statistics Breakdown + /// + /// The `ExtensionStats` struct provides: + /// - **total_extensions**: Number of extension operations performed + /// - **total_extension_days**: Cumulative days added to market + /// - **max_extension_days**: Maximum total days that can be extended + /// - **can_extend**: Whether market is currently extendable + /// - **extension_fee_per_day**: Current cost per day of extension + /// + /// # Extension Capacity Analysis + /// + /// Statistics enable capacity planning: + /// - **Remaining Capacity**: `max_extension_days - total_extension_days` + /// - **Extension Availability**: Based on market state and limits + /// - **Cost Estimation**: Calculate fees for planned extensions + /// - **Limit Monitoring**: Track approach to maximum extensions + /// + /// # Integration Applications + /// + /// - **UI Display**: Show extension status and capabilities to users + /// - **Planning Tools**: Help admins plan future extensions + /// - **Cost Estimation**: Calculate extension costs before commitment + /// - **Limit Monitoring**: Alert when approaching extension limits + /// - **Analytics**: Track extension usage patterns across markets pub fn get_extension_stats( env: &Env, market_id: Symbol, @@ -94,13 +392,162 @@ impl ExtensionManager { }) } - /// Check if market can be extended + /// Checks whether a specific market can be extended by a given administrator. + /// + /// This function performs comprehensive validation to determine if a market + /// extension is possible, considering market state, admin permissions, + /// extension limits, and current system configuration. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to check + /// * `admin` - Address of the administrator requesting extension capability check + /// + /// # Returns + /// + /// Returns `true` if the market can be extended by this admin, `false` if not, + /// or an `Error` if validation fails due to system issues. + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol}; + /// # use predictify_hybrid::extensions::ExtensionManager; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "prediction_market"); + /// + /// // Check extension eligibility + /// let can_extend = ExtensionManager::can_extend_market( + /// &env, + /// market_id.clone(), + /// admin.clone() + /// ).unwrap(); + /// + /// if can_extend { + /// println!("Market can be extended by this admin"); + /// + /// // Show extension options + /// let stats = ExtensionManager::get_extension_stats(&env, market_id.clone()).unwrap(); + /// let remaining = stats.max_extension_days - stats.total_extension_days; + /// + /// println!("Remaining extension capacity: {} days", remaining); + /// println!("Cost per day: {} XLM", stats.extension_fee_per_day / 10_000_000); + /// } else { + /// println!("Market cannot be extended:"); + /// println!("- Check admin permissions"); + /// println!("- Verify market state"); + /// println!("- Check extension limits"); + /// } + /// ``` + /// + /// # Validation Criteria + /// + /// Extension eligibility requires: + /// - **Market Exists**: Market must be found in storage + /// - **Admin Permission**: Admin must be authorized for this market + /// - **Market State**: Market must be in extendable state + /// - **Extension Limits**: Must not exceed maximum total extensions + /// - **System Status**: Extension system must be operational + /// + /// # Common Failure Reasons + /// + /// Extensions may be blocked due to: + /// - **Unauthorized Admin**: Admin lacks permission for this market + /// - **Market Finalized**: Market has already been resolved + /// - **Limit Reached**: Maximum extension days already used + /// - **System Maintenance**: Extension system temporarily disabled + /// - **Invalid State**: Market in non-extendable state + /// + /// # Use Cases + /// + /// - **UI State Management**: Enable/disable extension buttons + /// - **Permission Checking**: Validate admin capabilities + /// - **Pre-validation**: Check before expensive extension operations + /// - **User Feedback**: Provide clear extension availability status + /// - **Access Control**: Enforce extension permission policies pub fn can_extend_market(env: &Env, market_id: Symbol, admin: Address) -> Result { ExtensionValidator::can_extend_market(env, &market_id, &admin)?; Ok(true) } - /// Calculate extension fee for given days + /// Calculates the total fee required for extending a market by specified days. + /// + /// This function provides transparent fee calculation based on the current + /// per-day extension rate. The calculation is straightforward: days multiplied + /// by the daily rate, with no hidden fees or complex pricing structures. + /// + /// # Parameters + /// + /// * `additional_days` - Number of days to extend the market (1-30) + /// + /// # Returns + /// + /// Returns the total extension fee in stroops (1 XLM = 10,000,000 stroops). + /// + /// # Example + /// + /// ```rust + /// # use predictify_hybrid::extensions::ExtensionManager; + /// + /// // Calculate fees for different extension periods + /// let one_day_fee = ExtensionManager::calculate_extension_fee(1); + /// let one_week_fee = ExtensionManager::calculate_extension_fee(7); + /// let one_month_fee = ExtensionManager::calculate_extension_fee(30); + /// + /// println!("Extension Fee Calculator"); + /// println!("─────────────────────────"); + /// println!("1 day: {} XLM", one_day_fee / 10_000_000); + /// println!("1 week: {} XLM", one_week_fee / 10_000_000); + /// println!("1 month: {} XLM", one_month_fee / 10_000_000); + /// + /// // Calculate cost per day + /// let daily_rate = one_day_fee; + /// println!("Daily rate: {} XLM", daily_rate / 10_000_000); + /// + /// // Verify linear pricing + /// assert_eq!(one_week_fee, daily_rate * 7); + /// assert_eq!(one_month_fee, daily_rate * 30); + /// + /// // Budget planning example + /// let budget_xlm = 50; // 50 XLM budget + /// let budget_stroops = budget_xlm * 10_000_000; + /// let max_days = budget_stroops / daily_rate; + /// println!("With {} XLM budget, can extend up to {} days", + /// budget_xlm, max_days); + /// ``` + /// + /// # Fee Structure + /// + /// Extension fees follow a simple linear model: + /// - **Base Rate**: 1 XLM per day (10,000,000 stroops) + /// - **Linear Scaling**: Total = days × daily_rate + /// - **No Discounts**: Same rate regardless of duration + /// - **No Hidden Fees**: Transparent, predictable pricing + /// + /// # Economic Rationale + /// + /// The fee structure serves multiple purposes: + /// - **Spam Prevention**: Economic barrier prevents frivolous extensions + /// - **Resource Allocation**: Fees reflect computational and storage costs + /// - **Platform Sustainability**: Revenue supports ongoing operations + /// - **Fair Pricing**: Reasonable rates ensure accessibility + /// + /// # Budget Planning + /// + /// Use this function for: + /// - **Cost Estimation**: Calculate extension costs before commitment + /// - **Budget Planning**: Determine maximum extension days within budget + /// - **Fee Transparency**: Show users exact costs upfront + /// - **Economic Analysis**: Compare extension costs across markets + /// + /// # Integration Notes + /// + /// - **UI Display**: Show calculated fees in user interfaces + /// - **Validation**: Verify user has sufficient balance before extension + /// - **Analytics**: Track fee revenue and extension economics + /// - **Planning**: Help users optimize extension timing and duration pub fn calculate_extension_fee(additional_days: u32) -> i128 { (additional_days as i128) * EXTENSION_FEE_PER_DAY } diff --git a/contracts/predictify-hybrid/src/fees.rs b/contracts/predictify-hybrid/src/fees.rs index 3df7c338..ec448d97 100644 --- a/contracts/predictify-hybrid/src/fees.rs +++ b/contracts/predictify-hybrid/src/fees.rs @@ -34,7 +34,64 @@ pub const FEE_COLLECTION_THRESHOLD: i128 = crate::config::FEE_COLLECTION_THRESHO // ===== FEE TYPES ===== -/// Fee configuration for a market +/// Comprehensive fee configuration structure for market operations. +/// +/// This structure defines all fee-related parameters that govern how fees are +/// calculated, collected, and managed across the Predictify Hybrid platform. +/// It provides flexible configuration for different market types and economic models. +/// +/// # Fee Structure +/// +/// The fee system supports multiple fee types: +/// - **Platform Fees**: Percentage-based fees on market stakes +/// - **Creation Fees**: Fixed fees for creating new markets +/// - **Collection Thresholds**: Minimum amounts before fee collection +/// - **Fee Limits**: Minimum and maximum fee boundaries +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::fees::FeeConfig; +/// # let env = Env::default(); +/// +/// // Standard fee configuration +/// let config = FeeConfig { +/// platform_fee_percentage: 200, // 2.00% (basis points) +/// creation_fee: 10_000_000, // 1.0 XLM +/// min_fee_amount: 1_000_000, // 0.1 XLM minimum +/// max_fee_amount: 1_000_000_000, // 100 XLM maximum +/// collection_threshold: 100_000_000, // 10 XLM threshold +/// fees_enabled: true, +/// }; +/// +/// // Calculate platform fee for 50 XLM stake +/// let stake_amount = 500_000_000; // 50 XLM +/// let platform_fee = (stake_amount * config.platform_fee_percentage) / 10_000; +/// println!("Platform fee: {} XLM", platform_fee / 10_000_000); +/// +/// // Check if fees are collectible +/// if config.fees_enabled && stake_amount >= config.collection_threshold { +/// println!("Fees can be collected"); +/// } +/// ``` +/// +/// # Configuration Parameters +/// +/// - **platform_fee_percentage**: Fee percentage in basis points (100 = 1%) +/// - **creation_fee**: Fixed fee for creating new markets (in stroops) +/// - **min_fee_amount**: Minimum fee that can be charged (prevents dust) +/// - **max_fee_amount**: Maximum fee that can be charged (prevents abuse) +/// - **collection_threshold**: Minimum total stakes before fees can be collected +/// - **fees_enabled**: Global fee system enable/disable flag +/// +/// # Economic Model +/// +/// Fee configuration supports platform sustainability: +/// - **Revenue Generation**: Platform fees support ongoing operations +/// - **Spam Prevention**: Creation fees prevent market spam +/// - **Fair Pricing**: Configurable limits ensure reasonable fee levels +/// - **Flexible Economics**: Adjustable parameters for different market conditions #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct FeeConfig { @@ -52,7 +109,64 @@ pub struct FeeConfig { pub fees_enabled: bool, } -/// Fee collection record +/// Record of a completed fee collection operation from a market. +/// +/// This structure maintains a complete audit trail of fee collection activities, +/// including the amount collected, who collected it, when it occurred, and the +/// fee parameters used. Essential for transparency and financial reporting. +/// +/// # Collection Context +/// +/// Each fee collection record captures: +/// - Market identification and collection amount +/// - Administrative details and timing +/// - Fee calculation parameters used +/// - Complete audit trail for compliance +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol}; +/// # use predictify_hybrid::fees::FeeCollection; +/// # let env = Env::default(); +/// # let admin = Address::generate(&env); +/// +/// // Fee collection record +/// let collection = FeeCollection { +/// market_id: Symbol::new(&env, "btc_prediction"), +/// amount: 5_000_000, // 0.5 XLM collected +/// collected_by: admin.clone(), +/// timestamp: env.ledger().timestamp(), +/// fee_percentage: 200, // 2% fee rate used +/// }; +/// +/// // Analyze collection details +/// println!("Fee Collection Report"); +/// println!("Market: {}", collection.market_id.to_string()); +/// println!("Amount: {} XLM", collection.amount / 10_000_000); +/// println!("Collected by: {}", collection.collected_by.to_string()); +/// println!("Fee rate: {}%", collection.fee_percentage as f64 / 100.0); +/// +/// // Calculate original stake from fee +/// let original_stake = (collection.amount * 10_000) / collection.fee_percentage; +/// println!("Original stake: {} XLM", original_stake / 10_000_000); +/// ``` +/// +/// # Audit Trail Features +/// +/// Fee collection records provide: +/// - **Complete Traceability**: Full record of who collected what and when +/// - **Financial Reporting**: Data for revenue tracking and analysis +/// - **Compliance Support**: Audit trails for regulatory requirements +/// - **Transparency**: Public record of all fee collection activities +/// +/// # Integration Applications +/// +/// - **Financial Dashboards**: Display fee collection history and trends +/// - **Audit Systems**: Maintain compliance and verification records +/// - **Analytics**: Analyze fee collection patterns and efficiency +/// - **Reporting**: Generate financial reports and summaries +/// - **Transparency**: Provide public access to fee collection data #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct FeeCollection { @@ -68,7 +182,84 @@ pub struct FeeCollection { pub fee_percentage: i128, } -/// Fee analytics data +/// Comprehensive analytics and statistics for the fee system. +/// +/// This structure aggregates fee collection data across all markets to provide +/// insights into platform economics, fee efficiency, and revenue patterns. +/// Essential for business intelligence and platform optimization. +/// +/// # Analytics Scope +/// +/// Fee analytics encompass: +/// - Total fee collection across all markets +/// - Market participation and fee distribution +/// - Historical trends and collection patterns +/// - Performance metrics and efficiency indicators +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Map, String, Vec}; +/// # use predictify_hybrid::fees::{FeeAnalytics, FeeCollection}; +/// # let env = Env::default(); +/// +/// // Fee analytics example +/// let analytics = FeeAnalytics { +/// total_fees_collected: 1_000_000_000, // 100 XLM total +/// markets_with_fees: 25, // 25 markets have collected fees +/// average_fee_per_market: 40_000_000, // 4 XLM average +/// collection_history: Vec::new(&env), // Historical records +/// fee_distribution: Map::new(&env), // Distribution by market size +/// }; +/// +/// // Display analytics summary +/// println!("Fee System Analytics"); +/// println!("═══════════════════════════════════════"); +/// println!("Total fees collected: {} XLM", +/// analytics.total_fees_collected / 10_000_000); +/// println!("Markets with fees: {}", analytics.markets_with_fees); +/// println!("Average per market: {} XLM", +/// analytics.average_fee_per_market / 10_000_000); +/// +/// // Calculate fee collection rate +/// if analytics.markets_with_fees > 0 { +/// let collection_efficiency = (analytics.markets_with_fees as f64 / 100.0) * 100.0; +/// println!("Collection efficiency: {:.1}%", collection_efficiency); +/// } +/// +/// // Analyze fee distribution +/// println!("Fee distribution by market category:"); +/// for (category, amount) in analytics.fee_distribution.iter() { +/// println!(" {}: {} XLM", +/// category.to_string(), +/// amount / 10_000_000); +/// } +/// ``` +/// +/// # Key Metrics +/// +/// - **total_fees_collected**: Cumulative fees across all markets +/// - **markets_with_fees**: Number of markets that have generated fees +/// - **average_fee_per_market**: Mean fee collection per participating market +/// - **collection_history**: Chronological record of all fee collections +/// - **fee_distribution**: Breakdown of fees by market categories or sizes +/// +/// # Business Intelligence +/// +/// Analytics enable strategic insights: +/// - **Revenue Tracking**: Monitor platform income and growth +/// - **Market Performance**: Identify high-performing market categories +/// - **Efficiency Analysis**: Measure fee collection effectiveness +/// - **Trend Analysis**: Track fee patterns over time +/// - **Optimization**: Identify opportunities for fee structure improvements +/// +/// # Integration Applications +/// +/// - **Executive Dashboards**: High-level platform performance metrics +/// - **Financial Reporting**: Revenue analysis and forecasting +/// - **Market Analysis**: Understand which markets generate most fees +/// - **Performance Monitoring**: Track fee system health and efficiency +/// - **Strategic Planning**: Data-driven decisions for fee structure changes #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct FeeAnalytics { @@ -84,7 +275,81 @@ pub struct FeeAnalytics { pub fee_distribution: Map, } -/// Fee validation result +/// Result of fee validation operations with detailed feedback and suggestions. +/// +/// This structure provides comprehensive validation results for fee calculations, +/// including validity status, specific error messages, suggested corrections, +/// and detailed breakdowns. Essential for ensuring fee accuracy and compliance. +/// +/// # Validation Scope +/// +/// Fee validation covers: +/// - Fee amount validity and limits +/// - Calculation accuracy and consistency +/// - Configuration compliance +/// - Suggested optimizations and corrections +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String, Vec}; +/// # use predictify_hybrid::fees::{FeeValidationResult, FeeBreakdown}; +/// # let env = Env::default(); +/// +/// // Fee validation result example +/// let validation = FeeValidationResult { +/// is_valid: false, +/// errors: vec![ +/// &env, +/// String::from_str(&env, "Fee amount exceeds maximum limit"), +/// String::from_str(&env, "Market stake below collection threshold") +/// ], +/// suggested_amount: 50_000_000, // 5.0 XLM suggested +/// breakdown: FeeBreakdown { +/// total_staked: 1_000_000_000, // 100 XLM +/// fee_percentage: 200, // 2% +/// fee_amount: 20_000_000, // 2 XLM +/// platform_fee: 20_000_000, // 2 XLM +/// user_payout_amount: 980_000_000, // 98 XLM +/// }, +/// }; +/// +/// // Process validation results +/// if validation.is_valid { +/// println!("Fee validation passed"); +/// println!("Fee amount: {} XLM", validation.breakdown.fee_amount / 10_000_000); +/// } else { +/// println!("Fee validation failed:"); +/// for error in validation.errors.iter() { +/// println!(" - {}", error.to_string()); +/// } +/// println!("Suggested amount: {} XLM", +/// validation.suggested_amount / 10_000_000); +/// } +/// ``` +/// +/// # Validation Features +/// +/// - **is_valid**: Boolean indicating overall validation status +/// - **errors**: Detailed list of validation issues found +/// - **suggested_amount**: Recommended fee amount if current is invalid +/// - **breakdown**: Complete fee calculation breakdown for transparency +/// +/// # Error Categories +/// +/// Common validation errors: +/// - **Amount Limits**: Fee exceeds minimum or maximum bounds +/// - **Calculation Errors**: Mathematical inconsistencies in fee computation +/// - **Configuration Issues**: Fee parameters don't match current config +/// - **Threshold Violations**: Stakes below collection thresholds +/// +/// # Integration Applications +/// +/// - **UI Feedback**: Display validation errors and suggestions to users +/// - **API Responses**: Provide detailed validation results in API calls +/// - **Automated Correction**: Use suggested amounts for automatic fixes +/// - **Compliance Checking**: Ensure fees meet regulatory requirements +/// - **Quality Assurance**: Validate fee calculations before processing #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct FeeValidationResult { @@ -98,7 +363,66 @@ pub struct FeeValidationResult { pub breakdown: FeeBreakdown, } -/// Fee breakdown details +/// Detailed breakdown of fee calculations for complete transparency. +/// +/// This structure provides a comprehensive breakdown of how fees are calculated +/// from the total staked amount, showing each component of the fee calculation +/// and the final amounts. Essential for transparency and user understanding. +/// +/// # Breakdown Components +/// +/// Fee breakdown includes: +/// - Original stake amounts and fee percentages +/// - Calculated fee amounts and platform fees +/// - Final user payout amounts after fee deduction +/// - Complete calculation transparency +/// +/// # Example Usage +/// +/// ```rust +/// # use predictify_hybrid::fees::FeeBreakdown; +/// +/// // Fee breakdown for 100 XLM stake at 2% fee +/// let breakdown = FeeBreakdown { +/// total_staked: 1_000_000_000, // 100 XLM total stake +/// fee_percentage: 200, // 2.00% fee rate +/// fee_amount: 20_000_000, // 2 XLM fee +/// platform_fee: 20_000_000, // 2 XLM platform fee +/// user_payout_amount: 980_000_000, // 98 XLM after fees +/// }; +/// +/// // Display breakdown to user +/// println!("Fee Calculation Breakdown"); +/// println!("─────────────────────────────────────────"); +/// println!("Total Staked: {} XLM", breakdown.total_staked / 10_000_000); +/// println!("Fee Rate: {}%", breakdown.fee_percentage as f64 / 100.0); +/// println!("Fee Amount: {} XLM", breakdown.fee_amount / 10_000_000); +/// println!("Platform Fee: {} XLM", breakdown.platform_fee / 10_000_000); +/// println!("User Payout: {} XLM", breakdown.user_payout_amount / 10_000_000); +/// +/// // Verify calculation accuracy +/// let expected_fee = (breakdown.total_staked * breakdown.fee_percentage) / 10_000; +/// assert_eq!(breakdown.fee_amount, expected_fee); +/// +/// let expected_payout = breakdown.total_staked - breakdown.fee_amount; +/// assert_eq!(breakdown.user_payout_amount, expected_payout); +/// ``` +/// +/// # Calculation Transparency +/// +/// The breakdown ensures users understand: +/// - **How fees are calculated**: Clear percentage-based calculation +/// - **What they pay**: Exact fee amounts in XLM +/// - **What they receive**: Net payout after fee deduction +/// - **Verification**: All calculations can be independently verified +/// +/// # Use Cases +/// +/// - **User Interfaces**: Display fee calculations before confirmation +/// - **API Responses**: Provide detailed fee information in responses +/// - **Audit Trails**: Maintain records of fee calculation details +/// - **Transparency**: Show users exactly how fees are computed +/// - **Validation**: Verify fee calculations are correct and consistent #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct FeeBreakdown { @@ -116,7 +440,83 @@ pub struct FeeBreakdown { // ===== FEE MANAGER ===== -/// Main fee management system +/// Comprehensive fee management system for the Predictify Hybrid platform. +/// +/// The FeeManager provides centralized fee operations including collection, +/// calculation, validation, and configuration management. It handles all +/// fee-related operations with proper authentication, validation, and transparency. +/// +/// # Core Responsibilities +/// +/// - **Fee Collection**: Collect platform fees from resolved markets +/// - **Fee Processing**: Handle market creation and operation fees +/// - **Configuration Management**: Update and retrieve fee configurations +/// - **Analytics**: Generate fee analytics and performance metrics +/// - **Validation**: Ensure fee calculations are accurate and compliant +/// +/// # Fee Operations +/// +/// The system supports multiple fee types: +/// - **Platform Fees**: Percentage-based fees on market stakes +/// - **Creation Fees**: Fixed fees for creating new markets +/// - **Collection Operations**: Automated fee collection from resolved markets +/// - **Configuration Updates**: Dynamic fee parameter adjustments +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, Symbol}; +/// # use predictify_hybrid::fees::FeeManager; +/// # let env = Env::default(); +/// # let admin = Address::generate(&env); +/// # let market_id = Symbol::new(&env, "btc_market"); +/// +/// // Collect fees from a resolved market +/// let collected_amount = FeeManager::collect_fees( +/// &env, +/// admin.clone(), +/// market_id.clone() +/// ).unwrap(); +/// +/// println!("Collected {} XLM in fees", collected_amount / 10_000_000); +/// +/// // Get fee analytics +/// let analytics = FeeManager::get_fee_analytics(&env).unwrap(); +/// println!("Total platform fees: {} XLM", +/// analytics.total_fees_collected / 10_000_000); +/// +/// // Validate market fees +/// let validation = FeeManager::validate_market_fees(&env, &market_id).unwrap(); +/// if validation.is_valid { +/// println!("Market fees are valid"); +/// } else { +/// println!("Fee validation issues found"); +/// } +/// ``` +/// +/// # Security and Authentication +/// +/// Fee operations include: +/// - **Admin Authentication**: All fee operations require proper admin authentication +/// - **Permission Validation**: Verify admin has necessary permissions +/// - **Amount Validation**: Ensure fee amounts are within acceptable limits +/// - **State Validation**: Check market states before fee operations +/// +/// # Economic Model +/// +/// The fee system supports platform sustainability: +/// - **Revenue Generation**: Platform fees provide ongoing operational funding +/// - **Spam Prevention**: Creation fees prevent market spam and abuse +/// - **Fair Distribution**: Transparent fee calculation and collection +/// - **Configurable Economics**: Adjustable fee parameters for different conditions +/// +/// # Integration Points +/// +/// - **Market Resolution**: Automatic fee collection when markets resolve +/// - **Market Creation**: Fee processing during market creation +/// - **Administrative Tools**: Fee configuration and management interfaces +/// - **Analytics Dashboards**: Fee performance and revenue tracking +/// - **User Interfaces**: Fee display and transparency features pub struct FeeManager; impl FeeManager { diff --git a/contracts/predictify-hybrid/src/lib.rs b/contracts/predictify-hybrid/src/lib.rs index 383c20fe..0116dce8 100644 --- a/contracts/predictify-hybrid/src/lib.rs +++ b/contracts/predictify-hybrid/src/lib.rs @@ -39,6 +39,40 @@ const FEE_PERCENTAGE: i128 = 2; // 2% fee for the platform #[contractimpl] impl PredictifyHybrid { + /// Initializes the Predictify Hybrid smart contract with an administrator. + /// + /// This function must be called once after contract deployment to set up the initial + /// administrative configuration. It establishes the contract admin who will have + /// privileges to create markets and perform administrative functions. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The address that will be granted administrative privileges + /// + /// # Panics + /// + /// This function will panic if: + /// - The contract has already been initialized + /// - The admin address is invalid + /// - Storage operations fail + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let admin_address = Address::generate(&env); + /// + /// // Initialize the contract with an admin + /// PredictifyHybrid::initialize(env.clone(), admin_address); + /// ``` + /// + /// # Security + /// + /// The admin address should be carefully chosen as it will have significant + /// control over the contract's operation, including market creation and resolution. pub fn initialize(env: Env, admin: Address) { match AdminInitializer::initialize(&env, &admin) { Ok(_) => (), // Success @@ -46,7 +80,67 @@ impl PredictifyHybrid { } } - // Create a market + /// Creates a new prediction market with specified parameters and oracle configuration. + /// + /// This function allows authorized administrators to create prediction markets + /// with custom questions, possible outcomes, duration, and oracle integration. + /// Each market gets a unique identifier and is stored in persistent contract storage. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The administrator address creating the market (must be authorized) + /// * `question` - The prediction question (must be non-empty) + /// * `outcomes` - Vector of possible outcomes (minimum 2 required, all non-empty) + /// * `duration_days` - Market duration in days (must be between 1-365 days) + /// * `oracle_config` - Configuration for oracle integration (Reflector, Pyth, etc.) + /// + /// # Returns + /// + /// Returns a unique `Symbol` that serves as the market identifier for all future operations. + /// + /// # Panics + /// + /// This function will panic with specific errors if: + /// - `Error::Unauthorized` - Caller is not the contract admin + /// - `Error::InvalidQuestion` - Question is empty + /// - `Error::InvalidOutcomes` - Less than 2 outcomes or any outcome is empty + /// - Storage operations fail + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, String, Vec}; + /// # use predictify_hybrid::{PredictifyHybrid, OracleConfig, OracleType}; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// + /// let question = String::from_str(&env, "Will Bitcoin reach $100,000 by 2024?"); + /// let outcomes = vec![ + /// String::from_str(&env, "Yes"), + /// String::from_str(&env, "No") + /// ]; + /// let oracle_config = OracleConfig { + /// oracle_type: OracleType::Reflector, + /// oracle_contract: Address::generate(&env), + /// asset_code: Some(String::from_str(&env, "BTC")), + /// threshold_value: Some(100000), + /// }; + /// + /// let market_id = PredictifyHybrid::create_market( + /// env.clone(), + /// admin, + /// question, + /// outcomes, + /// 30, // 30 days duration + /// oracle_config + /// ); + /// ``` + /// + /// # Market State + /// + /// New markets are created in `MarketState::Active` state, allowing immediate voting. + /// The market will automatically transition to `MarketState::Ended` when the duration expires. pub fn create_market( env: Env, admin: Address, @@ -124,7 +218,58 @@ impl PredictifyHybrid { } - // Allows users to vote on a market outcome by staking tokens + /// Allows users to vote on a market outcome by staking tokens. + /// + /// This function enables users to participate in prediction markets by voting + /// for their predicted outcome and staking tokens to back their prediction. + /// Users can only vote once per market, and votes cannot be changed after submission. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `user` - The address of the user casting the vote (must be authenticated) + /// * `market_id` - Unique identifier of the market to vote on + /// * `outcome` - The outcome the user is voting for (must match a market outcome) + /// * `stake` - Amount of tokens to stake on this prediction (in base token units) + /// + /// # Panics + /// + /// This function will panic with specific errors if: + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - `Error::MarketClosed` - Market voting period has ended + /// - `Error::InvalidOutcome` - Outcome doesn't match any market outcomes + /// - `Error::AlreadyVoted` - User has already voted on this market + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, String, Symbol}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let user = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "market_1"); + /// + /// // Vote "Yes" with 1000 token units stake + /// PredictifyHybrid::vote( + /// env.clone(), + /// user, + /// market_id, + /// String::from_str(&env, "Yes"), + /// 1000 + /// ); + /// ``` + /// + /// # Token Staking + /// + /// The stake amount represents the user's confidence in their prediction. + /// Higher stakes increase potential rewards but also increase risk. + /// Stakes are locked until market resolution and cannot be withdrawn early. + /// + /// # Market State Requirements + /// + /// - Market must be in `Active` state + /// - Current time must be before market end time + /// - Market must not be cancelled or resolved pub fn vote(env: Env, user: Address, market_id: Symbol, outcome: String, stake: i128) { user.require_auth(); @@ -161,7 +306,61 @@ impl PredictifyHybrid { env.storage().persistent().set(&market_id, &market); } - // Claim winnings + /// Allows users to claim their winnings from resolved prediction markets. + /// + /// This function enables users who voted for the winning outcome to claim + /// their proportional share of the total market pool, minus platform fees. + /// Users can only claim once per market, and only after the market is resolved. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `user` - The address of the user claiming winnings (must be authenticated) + /// * `market_id` - Unique identifier of the resolved market + /// + /// # Panics + /// + /// This function will panic with specific errors if: + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - `Error::AlreadyClaimed` - User has already claimed winnings from this market + /// - `Error::MarketNotResolved` - Market hasn't been resolved yet + /// - `Error::NothingToClaim` - User didn't vote or voted for losing outcome + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let user = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "resolved_market"); + /// + /// // Claim winnings from a resolved market + /// PredictifyHybrid::claim_winnings( + /// env.clone(), + /// user, + /// market_id + /// ); + /// ``` + /// + /// # Payout Calculation + /// + /// Winnings are calculated using the formula: + /// ```text + /// user_payout = (user_stake * (100 - fee_percentage) / 100) * total_pool / winning_total + /// ``` + /// + /// Where: + /// - `user_stake` - Amount the user staked on the winning outcome + /// - `fee_percentage` - Platform fee (currently 2%) + /// - `total_pool` - Sum of all stakes in the market + /// - `winning_total` - Sum of stakes on the winning outcome + /// + /// # Market State Requirements + /// + /// - Market must be in `Resolved` state with a winning outcome set + /// - User must have voted for the winning outcome + /// - User must not have previously claimed winnings pub fn claim_winnings(env: Env, user: Address, market_id: Symbol) { user.require_auth(); @@ -220,12 +419,121 @@ impl PredictifyHybrid { env.storage().persistent().set(&market_id, &market); } - // Get market information + /// Retrieves complete market information by market identifier. + /// + /// This function provides read-only access to all market data including + /// configuration, current state, voting results, stakes, and resolution status. + /// It's the primary way to query market information for display or analysis. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to retrieve + /// + /// # Returns + /// + /// Returns `Some(Market)` if the market exists, `None` if not found. + /// The `Market` struct contains: + /// - Basic info: admin, question, outcomes, end_time + /// - Oracle configuration and results + /// - Voting data: votes, stakes, total_staked + /// - Resolution data: winning_outcome, claimed status + /// - State information: current state, extensions, fee collection + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "market_1"); + /// + /// match PredictifyHybrid::get_market(env.clone(), market_id) { + /// Some(market) => { + /// // Market found - access market data + /// let question = market.question; + /// let state = market.state; + /// let total_staked = market.total_staked; + /// }, + /// None => { + /// // Market not found + /// } + /// } + /// ``` + /// + /// # Use Cases + /// + /// - **UI Display**: Show market details, voting status, and results + /// - **Analytics**: Calculate market statistics and user positions + /// - **Validation**: Check market state before performing operations + /// - **Monitoring**: Track market progress and resolution status + /// + /// # Performance + /// + /// This is a read-only operation that doesn't modify contract state. + /// It retrieves data from persistent storage with minimal computational overhead. pub fn get_market(env: Env, market_id: Symbol) -> Option { env.storage().persistent().get(&market_id) } - // Manually resolve a market (admin only) + /// Manually resolves a prediction market by setting the winning outcome (admin only). + /// + /// This function allows contract administrators to manually resolve markets + /// when automatic oracle resolution is not available or needs override. + /// It's typically used for markets with subjective outcomes or when oracle + /// data is unavailable or disputed. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - The administrator address performing the resolution (must be authorized) + /// * `market_id` - Unique identifier of the market to resolve + /// * `winning_outcome` - The outcome to be declared as the winner + /// + /// # Panics + /// + /// This function will panic with specific errors if: + /// - `Error::Unauthorized` - Caller is not the contract admin + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - `Error::MarketClosed` - Market hasn't reached its end time yet + /// - `Error::InvalidOutcome` - Winning outcome doesn't match any market outcomes + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, String, Symbol}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let admin = Address::generate(&env); + /// # let market_id = Symbol::new(&env, "market_1"); + /// + /// // Manually resolve market with "Yes" as winning outcome + /// PredictifyHybrid::resolve_market_manual( + /// env.clone(), + /// admin, + /// market_id, + /// String::from_str(&env, "Yes") + /// ); + /// ``` + /// + /// # Resolution Process + /// + /// 1. **Authentication**: Verifies caller is the contract admin + /// 2. **Market Validation**: Ensures market exists and has ended + /// 3. **Outcome Validation**: Confirms winning outcome is valid + /// 4. **State Update**: Sets winning outcome and updates market state + /// + /// # Use Cases + /// + /// - **Subjective Markets**: Markets requiring human judgment + /// - **Oracle Failures**: When automated oracles are unavailable + /// - **Dispute Resolution**: Override disputed automatic resolutions + /// - **Emergency Resolution**: Resolve markets in exceptional circumstances + /// + /// # Security + /// + /// This function requires admin privileges and should be used carefully. + /// Manual resolutions should be transparent and follow established governance procedures. pub fn resolve_market_manual(env: Env, admin: Address, market_id: Symbol, winning_outcome: String) { admin.require_auth(); @@ -272,7 +580,69 @@ impl PredictifyHybrid { env.storage().persistent().set(&market_id, &market); } - /// Fetch oracle result for a market + /// Fetches oracle result for a market from external oracle contracts. + /// + /// This function retrieves prediction results from configured oracle sources + /// such as Reflector or Pyth networks. It's used to obtain objective data + /// for market resolution when manual resolution is not appropriate. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to fetch oracle data for + /// * `oracle_contract` - Address of the oracle contract to query + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(String)` - The oracle result as a string representation + /// - `Err(Error)` - Specific error if operation fails + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - `Error::MarketAlreadyResolved` - Market already has oracle result set + /// - `Error::MarketClosed` - Market hasn't reached its end time yet + /// - Oracle-specific errors from the resolution module + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Address, Symbol}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "btc_market"); + /// # let oracle_address = Address::generate(&env); + /// + /// match PredictifyHybrid::fetch_oracle_result( + /// env.clone(), + /// market_id, + /// oracle_address + /// ) { + /// Ok(result) => { + /// // Oracle result retrieved successfully + /// println!("Oracle result: {}", result); + /// }, + /// Err(e) => { + /// // Handle error + /// println!("Failed to fetch oracle result: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Oracle Integration + /// + /// This function integrates with various oracle types: + /// - **Reflector**: For asset price data and market conditions + /// - **Pyth**: For high-frequency financial data feeds + /// - **Custom Oracles**: For specialized data sources + /// + /// # Market State Requirements + /// + /// - Market must exist and be past its end time + /// - Market must not already have an oracle result + /// - Oracle contract must be accessible and responsive pub fn fetch_oracle_result( env: Env, market_id: Symbol, @@ -301,19 +671,244 @@ impl PredictifyHybrid { Ok(oracle_resolution.oracle_result) } - /// Resolve a market automatically using oracle and community consensus + /// Resolves a market automatically using oracle data and community consensus. + /// + /// This function implements the hybrid resolution algorithm that combines + /// objective oracle data with community voting patterns to determine the + /// final market outcome. It's the primary automated resolution mechanism. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to resolve + /// + /// # Returns + /// + /// Returns `Result<(), Error>` where: + /// - `Ok(())` - Market resolved successfully + /// - `Err(Error)` - Specific error if resolution fails + /// + /// # Errors + /// + /// This function returns specific errors: + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - `Error::MarketNotEnded` - Market hasn't reached its end time + /// - `Error::MarketAlreadyResolved` - Market is already resolved + /// - `Error::InsufficientData` - Not enough data for resolution + /// - Resolution-specific errors from the resolution module + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "ended_market"); + /// + /// match PredictifyHybrid::resolve_market(env.clone(), market_id) { + /// Ok(()) => { + /// // Market resolved successfully + /// println!("Market resolved successfully"); + /// }, + /// Err(e) => { + /// // Handle resolution error + /// println!("Resolution failed: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Hybrid Resolution Algorithm + /// + /// The resolution process follows these steps: + /// 1. **Data Collection**: Gather oracle data and community votes + /// 2. **Consensus Analysis**: Analyze agreement between oracle and community + /// 3. **Conflict Resolution**: Handle disagreements using weighted algorithms + /// 4. **Final Determination**: Set winning outcome based on hybrid result + /// 5. **State Update**: Update market state to resolved + /// + /// # Resolution Criteria + /// + /// - Market must be past its end time + /// - Sufficient voting participation required + /// - Oracle data must be available (if configured) + /// - No active disputes that would prevent resolution + /// + /// # Post-Resolution + /// + /// After successful resolution: + /// - Market state changes to `Resolved` + /// - Winning outcome is set + /// - Users can claim winnings + /// - Market statistics are finalized pub fn resolve_market(env: Env, market_id: Symbol) -> Result<(), Error> { // Use the resolution module to resolve the market let _resolution = resolution::MarketResolutionManager::resolve_market(&env, &market_id)?; Ok(()) } - /// Get resolution analytics + /// Retrieves comprehensive analytics about market resolution performance. + /// + /// This function provides detailed statistics about how markets are being + /// resolved across the platform, including success rates, resolution methods, + /// oracle performance, and community consensus patterns. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(ResolutionAnalytics)` - Complete resolution analytics data + /// - `Err(Error)` - Error if analytics calculation fails + /// + /// The `ResolutionAnalytics` struct contains: + /// - Total markets resolved + /// - Resolution method breakdown (manual vs automatic) + /// - Oracle accuracy statistics + /// - Community consensus metrics + /// - Average resolution time + /// - Dispute frequency and outcomes + /// + /// # Errors + /// + /// This function may return: + /// - `Error::InsufficientData` - Not enough resolved markets for analytics + /// - Storage access errors + /// - Calculation errors from the analytics module + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::Env; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// + /// match PredictifyHybrid::get_resolution_analytics(env.clone()) { + /// Ok(analytics) => { + /// // Access resolution statistics + /// let total_resolved = analytics.total_markets_resolved; + /// let oracle_accuracy = analytics.oracle_accuracy_rate; + /// let avg_resolution_time = analytics.average_resolution_time; + /// + /// println!("Resolved markets: {}", total_resolved); + /// println!("Oracle accuracy: {}%", oracle_accuracy); + /// }, + /// Err(e) => { + /// println!("Analytics unavailable: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Use Cases + /// + /// - **Platform Monitoring**: Track overall resolution system health + /// - **Oracle Evaluation**: Assess oracle performance and reliability + /// - **Community Analysis**: Understand voting patterns and accuracy + /// - **System Optimization**: Identify areas for improvement + /// - **Governance Reporting**: Provide transparency to stakeholders + /// + /// # Analytics Metrics + /// + /// Key metrics included: + /// - **Resolution Rate**: Percentage of markets successfully resolved + /// - **Method Distribution**: Manual vs automatic resolution breakdown + /// - **Accuracy Scores**: Oracle vs community prediction accuracy + /// - **Time Metrics**: Average time from market end to resolution + /// - **Dispute Analytics**: Frequency and resolution of disputes + /// + /// # Performance + /// + /// This function performs read-only analytics calculations and may take + /// longer for platforms with many resolved markets. Results may be cached + /// for performance optimization. pub fn get_resolution_analytics(env: Env) -> Result { resolution::MarketResolutionAnalytics::calculate_resolution_analytics(&env) } - /// Get market analytics + /// Retrieves comprehensive analytics and statistics for a specific market. + /// + /// This function provides detailed statistical analysis of a market including + /// participation metrics, voting patterns, stake distribution, and performance + /// indicators. It's essential for market analysis and user interfaces. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to analyze + /// + /// # Returns + /// + /// Returns `Result` where: + /// - `Ok(MarketStats)` - Complete market statistics and analytics + /// - `Err(Error)` - Error if market not found or analysis fails + /// + /// The `MarketStats` struct contains: + /// - Participation metrics (total voters, total stake) + /// - Outcome distribution (stakes per outcome) + /// - Market activity timeline + /// - Consensus and confidence indicators + /// - Resolution status and results + /// + /// # Errors + /// + /// This function returns: + /// - `Error::MarketNotFound` - Market with given ID doesn't exist + /// - Calculation errors from the analytics module + /// + /// # Example + /// + /// ```rust + /// # use soroban_sdk::{Env, Symbol}; + /// # use predictify_hybrid::PredictifyHybrid; + /// # let env = Env::default(); + /// # let market_id = Symbol::new(&env, "market_1"); + /// + /// match PredictifyHybrid::get_market_analytics(env.clone(), market_id) { + /// Ok(stats) => { + /// // Access market statistics + /// let total_participants = stats.total_participants; + /// let total_stake = stats.total_stake; + /// let leading_outcome = stats.leading_outcome; + /// + /// println!("Participants: {}", total_participants); + /// println!("Total stake: {}", total_stake); + /// println!("Leading outcome: {:?}", leading_outcome); + /// }, + /// Err(e) => { + /// println!("Analytics unavailable: {:?}", e); + /// } + /// } + /// ``` + /// + /// # Statistical Metrics + /// + /// Key analytics provided: + /// - **Participation**: Number of unique voters and total stake + /// - **Distribution**: Stake distribution across outcomes + /// - **Confidence**: Market confidence indicators and consensus strength + /// - **Activity**: Voting timeline and participation patterns + /// - **Performance**: Market liquidity and engagement metrics + /// + /// # Use Cases + /// + /// - **UI Display**: Show market statistics to users + /// - **Market Analysis**: Understand market dynamics and trends + /// - **Risk Assessment**: Evaluate market confidence and volatility + /// - **Performance Tracking**: Monitor market engagement over time + /// - **Research**: Academic and commercial market research + /// + /// # Real-time Updates + /// + /// Statistics are calculated in real-time based on current market state. + /// For active markets, analytics reflect the most current voting and staking data. + /// For resolved markets, analytics include final resolution information. + /// + /// # Performance + /// + /// This function performs calculations on market data and may have + /// computational overhead for markets with many participants. Consider + /// caching results for frequently accessed markets. pub fn get_market_analytics(env: Env, market_id: Symbol) -> Result { let market = env.storage().persistent().get::(&market_id) .ok_or(Error::MarketNotFound)?; diff --git a/contracts/predictify-hybrid/src/markets.rs b/contracts/predictify-hybrid/src/markets.rs index ab7cbda9..9a85401d 100644 --- a/contracts/predictify-hybrid/src/markets.rs +++ b/contracts/predictify-hybrid/src/markets.rs @@ -17,11 +17,74 @@ use crate::types::*; // ===== MARKET CREATION ===== -/// Market creation utilities +/// Market creation utilities for the Predictify prediction market platform. +/// +/// This struct provides methods to create different types of prediction markets +/// with various oracle configurations. All market creation functions validate +/// input parameters and handle fee processing automatically. pub struct MarketCreator; impl MarketCreator { - /// Create a new market with full configuration + /// Creates a new prediction market with comprehensive configuration options. + /// + /// This is the primary market creation function that supports all oracle types + /// and validates all input parameters before creating the market. The function + /// automatically generates a unique market ID, processes creation fees, and + /// stores the market in persistent storage. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `admin` - Address of the market administrator (must have sufficient balance for fees) + /// * `question` - The prediction question (1-500 characters, cannot be empty) + /// * `outcomes` - Vector of possible outcomes (minimum 2, maximum 10 outcomes) + /// * `duration_days` - Market duration in days (1-365 days) + /// * `oracle_config` - Oracle configuration specifying data source and resolution criteria + /// + /// # Returns + /// + /// * `Ok(Symbol)` - Unique market identifier for the created market + /// * `Err(Error)` - Creation failed due to validation or processing errors + /// + /// # Errors + /// + /// * `Error::InvalidQuestion` - Question is empty or exceeds character limits + /// * `Error::InvalidOutcomes` - Less than 2 outcomes or empty outcome strings + /// * `Error::InvalidDuration` - Duration is 0 or exceeds 365 days + /// * `Error::InsufficientBalance` - Admin lacks funds for creation fee + /// * `Error::InvalidOracleConfig` - Oracle configuration is malformed + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, String, vec}; + /// use crate::markets::MarketCreator; + /// use crate::types::{OracleConfig, OracleProvider}; + /// + /// let env = Env::default(); + /// let admin = Address::generate(&env); + /// let question = String::from_str(&env, "Will Bitcoin reach $100,000 by end of 2024?"); + /// let outcomes = vec![ + /// &env, + /// String::from_str(&env, "Yes"), + /// String::from_str(&env, "No") + /// ]; + /// let oracle_config = OracleConfig::new( + /// OracleProvider::Pyth, + /// String::from_str(&env, "BTC/USD"), + /// 100_000_00, // $100,000 with 2 decimal places + /// String::from_str(&env, "gte") + /// ); + /// + /// let market_id = MarketCreator::create_market( + /// &env, + /// admin, + /// question, + /// outcomes, + /// 90, // 90 days duration + /// oracle_config + /// ).expect("Market creation should succeed"); + /// ``` pub fn create_market(env: &Env, admin: Address, question: String, outcomes: Vec, duration_days: u32, oracle_config: OracleConfig) -> Result { // Validate market parameters MarketValidator::validate_market_params(env, &question, &outcomes, duration_days)?; @@ -47,7 +110,59 @@ impl MarketCreator { Ok(market_id) } - /// Create a market with Reflector oracle + /// Creates a prediction market using Reflector oracle as the data source. + /// + /// Reflector oracle provides real-time price feeds for various cryptocurrency + /// and traditional assets. This convenience method automatically configures + /// the oracle settings and delegates to the main create_market function. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `admin` - Address of the market administrator + /// * `question` - The prediction question (1-500 characters) + /// * `outcomes` - Vector of possible outcomes (minimum 2, maximum 10) + /// * `duration_days` - Market duration in days (1-365 days) + /// * `asset_symbol` - Reflector asset symbol (e.g., "BTC", "ETH", "XLM") + /// * `threshold` - Price threshold for comparison (in asset's base units) + /// * `comparison` - Comparison operator ("gt", "gte", "lt", "lte", "eq") + /// + /// # Returns + /// + /// * `Ok(Symbol)` - Unique market identifier for the created market + /// * `Err(Error)` - Creation failed due to validation or processing errors + /// + /// # Errors + /// + /// Same as `create_market`, plus: + /// * `Error::InvalidOracleConfig` - Invalid asset symbol or comparison operator + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, String, vec}; + /// use crate::markets::MarketCreator; + /// + /// let env = Env::default(); + /// let admin = Address::generate(&env); + /// let question = String::from_str(&env, "Will XLM price exceed $1.00 this month?"); + /// let outcomes = vec![ + /// &env, + /// String::from_str(&env, "Yes"), + /// String::from_str(&env, "No") + /// ]; + /// + /// let market_id = MarketCreator::create_reflector_market( + /// &env, + /// admin, + /// question, + /// outcomes, + /// 30, // 30 days + /// String::from_str(&env, "XLM"), + /// 1_00, // $1.00 with 2 decimal places + /// String::from_str(&env, "gt") + /// ).expect("Reflector market creation should succeed"); + /// ``` pub fn create_reflector_market(_env: &Env, admin: Address, question: String, outcomes: Vec, duration_days: u32, asset_symbol: String, threshold: i128, comparison: String) -> Result { let oracle_config = OracleConfig { provider: OracleProvider::Reflector, @@ -59,7 +174,59 @@ impl MarketCreator { Self::create_market(_env, admin, question, outcomes, duration_days, oracle_config) } - /// Create a market with Pyth oracle + /// Creates a prediction market using Pyth Network oracle as the data source. + /// + /// Pyth Network provides high-frequency, high-fidelity market data from + /// professional trading firms and exchanges. This method configures a market + /// to use Pyth's price feeds for automated resolution. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `admin` - Address of the market administrator + /// * `question` - The prediction question (1-500 characters) + /// * `outcomes` - Vector of possible outcomes (minimum 2, maximum 10) + /// * `duration_days` - Market duration in days (1-365 days) + /// * `feed_id` - Pyth price feed identifier (e.g., "BTC/USD", "ETH/USD") + /// * `threshold` - Price threshold for comparison (in feed's base units) + /// * `comparison` - Comparison operator ("gt", "gte", "lt", "lte", "eq") + /// + /// # Returns + /// + /// * `Ok(Symbol)` - Unique market identifier for the created market + /// * `Err(Error)` - Creation failed due to validation or processing errors + /// + /// # Errors + /// + /// Same as `create_market`, plus: + /// * `Error::InvalidOracleConfig` - Invalid feed ID or comparison operator + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, String, vec}; + /// use crate::markets::MarketCreator; + /// + /// let env = Env::default(); + /// let admin = Address::generate(&env); + /// let question = String::from_str(&env, "Will ETH break $5,000 before year end?"); + /// let outcomes = vec![ + /// &env, + /// String::from_str(&env, "Yes"), + /// String::from_str(&env, "No") + /// ]; + /// + /// let market_id = MarketCreator::create_pyth_market( + /// &env, + /// admin, + /// question, + /// outcomes, + /// 60, // 60 days + /// String::from_str(&env, "ETH/USD"), + /// 5_000_00, // $5,000 with 2 decimal places + /// String::from_str(&env, "gte") + /// ).expect("Pyth market creation should succeed"); + /// ``` pub fn create_pyth_market(_env: &Env, admin: Address, question: String, outcomes: Vec, duration_days: u32, feed_id: String, threshold: i128, comparison: String) -> Result { let oracle_config = OracleConfig { provider: OracleProvider::Pyth, @@ -71,7 +238,59 @@ impl MarketCreator { Self::create_market(_env, admin, question, outcomes, duration_days, oracle_config) } - /// Create a market with Reflector oracle for specific assets + /// Creates a prediction market using Reflector oracle for specific asset types. + /// + /// This is a specialized version of `create_reflector_market` that provides + /// additional validation and configuration for specific asset classes. It's + /// particularly useful for markets focused on specific cryptocurrency or + /// commodity price predictions. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `admin` - Address of the market administrator + /// * `question` - The prediction question (1-500 characters) + /// * `outcomes` - Vector of possible outcomes (minimum 2, maximum 10) + /// * `duration_days` - Market duration in days (1-365 days) + /// * `asset_symbol` - Specific asset symbol (e.g., "BTC", "ETH", "GOLD") + /// * `threshold` - Price threshold for comparison (in asset's base units) + /// * `comparison` - Comparison operator ("gt", "gte", "lt", "lte", "eq") + /// + /// # Returns + /// + /// * `Ok(Symbol)` - Unique market identifier for the created market + /// * `Err(Error)` - Creation failed due to validation or processing errors + /// + /// # Errors + /// + /// Same as `create_reflector_market` + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, String, vec}; + /// use crate::markets::MarketCreator; + /// + /// let env = Env::default(); + /// let admin = Address::generate(&env); + /// let question = String::from_str(&env, "Will Bitcoin dominance exceed 50% this quarter?"); + /// let outcomes = vec![ + /// &env, + /// String::from_str(&env, "Yes"), + /// String::from_str(&env, "No") + /// ]; + /// + /// let market_id = MarketCreator::create_reflector_asset_market( + /// &env, + /// admin, + /// question, + /// outcomes, + /// 90, // 90 days + /// String::from_str(&env, "BTC"), + /// 50_00, // 50% with 2 decimal places + /// String::from_str(&env, "gt") + /// ).expect("Asset market creation should succeed"); + /// ``` pub fn create_reflector_asset_market(_env: &Env, admin: Address, question: String, outcomes: Vec, duration_days: u32, asset_symbol: String, threshold: i128, comparison: String) -> Result { Self::create_reflector_market(_env, admin, question, outcomes, duration_days, asset_symbol, threshold, comparison) } @@ -79,12 +298,74 @@ impl MarketCreator { // ===== MARKET VALIDATION ===== -/// Market validation utilities +/// Market validation utilities for ensuring data integrity and business rules. +/// +/// This struct provides comprehensive validation functions for market creation, +/// voting operations, and state transitions. All validation functions follow +/// strict business rules to maintain platform integrity and user experience. pub struct MarketValidator; impl MarketValidator { - /// Validate market creation parameters - + /// Validates all parameters required for market creation. + /// + /// This function performs comprehensive validation of market creation parameters + /// to ensure they meet platform requirements and business rules. It checks + /// question validity, outcome constraints, and duration limits. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `question` - The prediction question to validate + /// * `outcomes` - Vector of possible outcomes to validate + /// * `duration_days` - Market duration in days to validate + /// + /// # Returns + /// + /// * `Ok(())` - All parameters are valid + /// * `Err(Error)` - One or more parameters failed validation + /// + /// # Errors + /// + /// * `Error::InvalidQuestion` - Question is empty or exceeds 500 characters + /// * `Error::InvalidOutcomes` - Less than 2 outcomes, more than 10 outcomes, or empty outcome strings + /// * `Error::InvalidDuration` - Duration is 0 or exceeds 365 days + /// + /// # Validation Rules + /// + /// * Question: Must be non-empty and between 1-500 characters + /// * Outcomes: Must have 2-10 unique, non-empty outcome strings + /// * Duration: Must be between 1-365 days inclusive + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String, vec}; + /// use crate::markets::MarketValidator; + /// + /// let env = Env::default(); + /// let question = String::from_str(&env, "Will it rain tomorrow?"); + /// let outcomes = vec![ + /// &env, + /// String::from_str(&env, "Yes"), + /// String::from_str(&env, "No") + /// ]; + /// + /// // Valid parameters + /// assert!(MarketValidator::validate_market_params( + /// &env, + /// &question, + /// &outcomes, + /// 7 // 1 week duration + /// ).is_ok()); + /// + /// // Invalid duration + /// assert!(MarketValidator::validate_market_params( + /// &env, + /// &question, + /// &outcomes, + /// 400 // Too long + /// ).is_err()); + /// ``` pub fn validate_market_params( _env: &Env, question: &String, @@ -116,12 +397,85 @@ impl MarketValidator { Ok(()) } - /// Validate oracle configuration + /// Validates oracle configuration for market creation. + /// + /// This function ensures that the oracle configuration is properly formatted + /// and contains valid parameters for the specified oracle provider. It delegates + /// to the oracle configuration's internal validation method. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `oracle_config` - Oracle configuration to validate + /// + /// # Returns + /// + /// * `Ok(())` - Oracle configuration is valid + /// * `Err(Error)` - Oracle configuration is invalid + /// + /// # Errors + /// + /// * `Error::InvalidOracleConfig` - Invalid provider, feed ID, or comparison operator + /// * `Error::InvalidThreshold` - Threshold value is out of acceptable range + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String}; + /// use crate::markets::MarketValidator; + /// use crate::types::{OracleConfig, OracleProvider}; + /// + /// let env = Env::default(); + /// let oracle_config = OracleConfig::new( + /// OracleProvider::Pyth, + /// String::from_str(&env, "BTC/USD"), + /// 50_000_00, // $50,000 + /// String::from_str(&env, "gt") + /// ); + /// + /// assert!(MarketValidator::validate_oracle_config(&env, &oracle_config).is_ok()); + /// ``` pub fn validate_oracle_config(_env: &Env, oracle_config: &OracleConfig) -> Result<(), Error> { oracle_config.validate(_env) } - /// Validate market state for voting + /// Validates that a market is in the correct state to accept votes. + /// + /// This function checks if a market is still active and accepting votes. + /// It verifies that the market hasn't expired and hasn't been resolved yet. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `market` - Market to validate for voting eligibility + /// + /// # Returns + /// + /// * `Ok(())` - Market is eligible for voting + /// * `Err(Error)` - Market cannot accept votes + /// + /// # Errors + /// + /// * `Error::MarketClosed` - Market has expired (current time >= end_time) + /// * `Error::MarketAlreadyResolved` - Market has already been resolved + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::Env; + /// use crate::markets::{MarketValidator, MarketStateManager}; + /// use crate::types::Symbol; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "test_market"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Check if market accepts votes + /// match MarketValidator::validate_market_for_voting(&env, &market) { + /// Ok(()) => println!("Market is open for voting"), + /// Err(e) => println!("Cannot vote: {:?}", e), + /// } + /// ``` pub fn validate_market_for_voting(_env: &Env, market: &Market) -> Result<(), Error> { let current_time = _env.ledger().timestamp(); @@ -136,7 +490,44 @@ impl MarketValidator { Ok(()) } - /// Validate market state for resolution + /// Validates that a market is ready for resolution. + /// + /// This function checks if a market has expired and has oracle data available + /// for resolution. It ensures that the market is in the correct state to + /// determine the winning outcome. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `market` - Market to validate for resolution eligibility + /// + /// # Returns + /// + /// * `Ok(())` - Market is ready for resolution + /// * `Err(Error)` - Market cannot be resolved yet + /// + /// # Errors + /// + /// * `Error::MarketClosed` - Market hasn't expired yet (current time < end_time) + /// * `Error::OracleUnavailable` - Oracle result is not available yet + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::Env; + /// use crate::markets::{MarketValidator, MarketStateManager}; + /// use crate::types::Symbol; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "expired_market"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Check if market can be resolved + /// match MarketValidator::validate_market_for_resolution(&env, &market) { + /// Ok(()) => println!("Market is ready for resolution"), + /// Err(e) => println!("Cannot resolve yet: {:?}", e), + /// } + /// ``` pub fn validate_market_for_resolution(_env: &Env, market: &Market) -> Result<(), Error> { let current_time = _env.ledger().timestamp(); @@ -151,9 +542,49 @@ impl MarketValidator { Ok(()) } - /// Validate outcome for a market - - + /// Validates that a voting outcome is valid for the specified market. + /// + /// This function checks if the provided outcome string matches one of the + /// predefined outcomes for the market. It performs case-sensitive string + /// comparison to ensure exact matching. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `outcome` - The outcome string to validate + /// * `market_outcomes` - Vector of valid outcomes for the market + /// + /// # Returns + /// + /// * `Ok(())` - Outcome is valid for this market + /// * `Err(Error)` - Outcome is not valid for this market + /// + /// # Errors + /// + /// * `Error::InvalidOutcome` - Outcome does not match any valid market outcomes + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String, vec}; + /// use crate::markets::MarketValidator; + /// + /// let env = Env::default(); + /// let valid_outcomes = vec![ + /// &env, + /// String::from_str(&env, "Yes"), + /// String::from_str(&env, "No"), + /// String::from_str(&env, "Maybe") + /// ]; + /// + /// // Valid outcome + /// let user_vote = String::from_str(&env, "Yes"); + /// assert!(MarketValidator::validate_outcome(&env, &user_vote, &valid_outcomes).is_ok()); + /// + /// // Invalid outcome + /// let invalid_vote = String::from_str(&env, "Perhaps"); + /// assert!(MarketValidator::validate_outcome(&env, &invalid_vote, &valid_outcomes).is_err()); + /// ``` pub fn validate_outcome( _env: &Env, outcome: &String, @@ -169,7 +600,46 @@ impl MarketValidator { Err(Error::InvalidOutcome) } - /// Validate stake amount + /// Validates that a stake amount meets minimum requirements and is positive. + /// + /// This function ensures that users provide adequate stake amounts for voting + /// or disputing. It checks both minimum stake requirements and basic validity + /// (positive values). + /// + /// # Parameters + /// + /// * `stake` - The stake amount to validate (in token base units) + /// * `min_stake` - The minimum required stake amount (in token base units) + /// + /// # Returns + /// + /// * `Ok(())` - Stake amount is valid + /// * `Err(Error)` - Stake amount is invalid + /// + /// # Errors + /// + /// * `Error::InsufficientStake` - Stake is below the minimum required amount + /// * `Error::InvalidState` - Stake is zero or negative + /// + /// # Example + /// + /// ```rust + /// use crate::markets::MarketValidator; + /// + /// let min_stake = 1_000_000; // 0.1 XLM (assuming 7 decimal places) + /// + /// // Valid stake + /// assert!(MarketValidator::validate_stake(5_000_000, min_stake).is_ok()); + /// + /// // Insufficient stake + /// assert!(MarketValidator::validate_stake(500_000, min_stake).is_err()); + /// + /// // Invalid stake (negative) + /// assert!(MarketValidator::validate_stake(-1_000_000, min_stake).is_err()); + /// + /// // Invalid stake (zero) + /// assert!(MarketValidator::validate_stake(0, min_stake).is_err()); + /// ``` pub fn validate_stake(stake: i128, min_stake: i128) -> Result<(), Error> { if stake < min_stake { return Err(Error::InsufficientStake); @@ -185,11 +655,52 @@ impl MarketValidator { // ===== MARKET STATE MANAGEMENT ===== -/// Market state management utilities +/// Market state management utilities for persistent storage operations. +/// +/// This struct provides comprehensive functions for managing market state, +/// including storage operations, vote management, dispute handling, and +/// state transitions. All functions maintain data consistency and emit +/// appropriate events for state changes. pub struct MarketStateManager; impl MarketStateManager { - /// Get market from storage + /// Retrieves a market from persistent storage by its unique identifier. + /// + /// This function fetches market data from the blockchain's persistent storage. + /// It's the primary method for accessing market information and is used + /// throughout the system for market operations. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique symbol identifier for the market + /// + /// # Returns + /// + /// * `Ok(Market)` - The market data if found + /// * `Err(Error)` - Market not found or storage error + /// + /// # Errors + /// + /// * `Error::MarketNotFound` - No market exists with the specified ID + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateManager; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "market_123"); + /// + /// match MarketStateManager::get_market(&env, &market_id) { + /// Ok(market) => { + /// println!("Found market: {}", market.question); + /// println!("Market state: {:?}", market.state); + /// }, + /// Err(e) => println!("Market not found: {:?}", e), + /// } + /// ``` pub fn get_market(_env: &Env, market_id: &Symbol) -> Result { _env.storage() .persistent() @@ -197,12 +708,69 @@ impl MarketStateManager { .ok_or(Error::MarketNotFound) } - /// Update market in storage + /// Updates market data in persistent storage. + /// + /// This function saves the current market state to persistent storage, + /// overwriting any existing data. It's used after making changes to + /// market state, votes, or other market properties. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique symbol identifier for the market + /// * `market` - Updated market data to store + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateManager; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "market_123"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Modify market data + /// market.total_staked += 1_000_000; + /// + /// // Save changes + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn update_market(_env: &Env, market_id: &Symbol, market: &Market) { _env.storage().persistent().set(market_id, market); } - /// Remove market from storage + /// Removes a market from persistent storage after proper closure. + /// + /// This function safely removes a market from storage, ensuring it's + /// properly closed first. It handles state transitions and emits + /// appropriate events before deletion. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique symbol identifier for the market to remove + /// + /// # State Transitions + /// + /// If the market is not already closed, it will be transitioned to + /// `MarketState::Closed` before removal. + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateManager; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "expired_market"); + /// + /// // Remove market (will close it first if needed) + /// MarketStateManager::remove_market(&env, &market_id); + /// + /// // Verify removal + /// assert!(MarketStateManager::get_market(&env, &market_id).is_err()); + /// ``` pub fn remove_market(env: &Env, market_id: &Symbol) { let mut market = match Self::get_market(env, market_id) { Ok(m) => m, @@ -218,7 +786,58 @@ impl MarketStateManager { env.storage().persistent().remove(market_id); } - /// Add vote to market + /// Adds a user's vote to a market with the specified stake amount. + /// + /// This function records a user's vote for a specific outcome and their + /// associated stake. It updates the market's vote mappings, stake tracking, + /// and total staked amount. The function validates market state before + /// allowing the vote. + /// + /// # Parameters + /// + /// * `market` - Mutable reference to the market to add the vote to + /// * `user` - Address of the user placing the vote + /// * `outcome` - The outcome the user is voting for + /// * `stake` - Amount staked on this vote (in token base units) + /// * `_market_id` - Optional market ID for event emission (currently unused) + /// + /// # State Requirements + /// + /// * Market must be in `Active` state + /// * Market must not have expired + /// * User must not have already voted (will overwrite existing vote) + /// + /// # Side Effects + /// + /// * Updates `market.votes` mapping with user's choice + /// * Updates `market.stakes` mapping with user's stake + /// * Increments `market.total_staked` by the stake amount + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, String, Symbol}; + /// use crate::markets::MarketStateManager; + /// + /// let env = Env::default(); + /// let user = Address::generate(&env); + /// let market_id = Symbol::new(&env, "active_market"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// let outcome = String::from_str(&env, "Yes"); + /// let stake = 5_000_000; // 0.5 XLM + /// + /// MarketStateManager::add_vote( + /// &mut market, + /// user, + /// outcome, + /// stake, + /// Some(&market_id) + /// ); + /// + /// // Save updated market + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn add_vote(market: &mut Market, user: Address, outcome: String, stake: i128, _market_id: Option<&Symbol>) { MarketStateLogic::check_function_access_for_state("vote", market.state).unwrap(); market.votes.set(user.clone(), outcome); @@ -227,7 +846,64 @@ impl MarketStateManager { // No state change for voting } - /// Add dispute stake to market + /// Adds a user's dispute stake to challenge the market's oracle result. + /// + /// This function allows users to stake tokens to dispute the oracle's + /// resolution of a market. When dispute stakes are added, the market + /// may transition from `Ended` to `Disputed` state, triggering additional + /// resolution mechanisms. + /// + /// # Parameters + /// + /// * `market` - Mutable reference to the market being disputed + /// * `user` - Address of the user adding dispute stake + /// * `stake` - Amount staked for the dispute (in token base units) + /// * `market_id` - Optional market ID for event emission + /// + /// # State Requirements + /// + /// * Market must be in `Ended` state to initiate dispute + /// * Market must have an oracle result to dispute + /// + /// # State Transitions + /// + /// * `Ended` → `Disputed` when first dispute stake is added + /// + /// # Side Effects + /// + /// * Updates `market.dispute_stakes` mapping (accumulates existing stakes) + /// * May transition market state to `Disputed` + /// * Emits state change event if transition occurs + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, Symbol}; + /// use crate::markets::MarketStateManager; + /// use crate::types::MarketState; + /// + /// let env = Env::default(); + /// let disputer = Address::generate(&env); + /// let market_id = Symbol::new(&env, "ended_market"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Ensure market is in Ended state + /// assert_eq!(market.state, MarketState::Ended); + /// + /// let dispute_stake = 10_000_000; // 1.0 XLM + /// + /// MarketStateManager::add_dispute_stake( + /// &mut market, + /// disputer, + /// dispute_stake, + /// Some(&market_id) + /// ); + /// + /// // Market should now be in Disputed state + /// assert_eq!(market.state, MarketState::Disputed); + /// + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn add_dispute_stake(market: &mut Market, user: Address, stake: i128, market_id: Option<&Symbol>) { MarketStateLogic::check_function_access_for_state("dispute", market.state).unwrap(); let existing_stake = market.dispute_stakes.get(user.clone()).unwrap_or(0); @@ -243,18 +919,154 @@ impl MarketStateManager { } } - /// Mark user as claimed + /// Marks a user as having claimed their winnings from a resolved market. + /// + /// This function updates the market's claimed status for a specific user, + /// preventing double-claiming of rewards. It's called after successful + /// payout distribution to winning participants. + /// + /// # Parameters + /// + /// * `market` - Mutable reference to the market + /// * `user` - Address of the user who has claimed their winnings + /// * `_market_id` - Optional market ID for event emission (currently unused) + /// + /// # State Requirements + /// + /// * Market must be in `Resolved` state + /// * User must have been a winning participant + /// * User must not have already claimed + /// + /// # Side Effects + /// + /// * Updates `market.claimed` mapping to mark user as claimed + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, Symbol}; + /// use crate::markets::MarketStateManager; + /// use crate::types::MarketState; + /// + /// let env = Env::default(); + /// let winner = Address::generate(&env); + /// let market_id = Symbol::new(&env, "resolved_market"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Ensure market is resolved + /// assert_eq!(market.state, MarketState::Resolved); + /// + /// // Check if user hasn't claimed yet + /// assert!(!market.claimed.get(winner.clone()).unwrap_or(false)); + /// + /// // Process payout (external logic) + /// // ... + /// + /// // Mark as claimed + /// MarketStateManager::mark_claimed(&mut market, winner.clone(), Some(&market_id)); + /// + /// // Verify claim status + /// assert!(market.claimed.get(winner).unwrap_or(false)); + /// + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn mark_claimed(market: &mut Market, user: Address, _market_id: Option<&Symbol>) { MarketStateLogic::check_function_access_for_state("claim", market.state).unwrap(); market.claimed.set(user, true); } - /// Set oracle result + /// Sets the oracle result for a market that has reached its end time. + /// + /// This function stores the oracle's resolution data for the market. + /// The oracle result is used in combination with community consensus + /// to determine the final market outcome using the hybrid resolution algorithm. + /// + /// # Parameters + /// + /// * `market` - Mutable reference to the market + /// * `result` - Oracle result string (typically matches one of the market outcomes) + /// + /// # Side Effects + /// + /// * Sets `market.oracle_result` to the provided result + /// * Enables the market for resolution processing + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String, Symbol}; + /// use crate::markets::MarketStateManager; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "ended_market"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// let oracle_result = String::from_str(&env, "Yes"); + /// MarketStateManager::set_oracle_result(&mut market, oracle_result); + /// + /// // Oracle result is now available for resolution + /// assert!(market.oracle_result.is_some()); + /// + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn set_oracle_result(market: &mut Market, result: String) { market.oracle_result = Some(result); } - /// Set winning outcome + /// Sets the winning outcome for a market and transitions it to resolved state. + /// + /// This function finalizes the market resolution by setting the winning outcome + /// and transitioning the market state from `Ended` or `Disputed` to `Resolved`. + /// This enables users to claim their winnings. + /// + /// # Parameters + /// + /// * `market` - Mutable reference to the market + /// * `outcome` - The winning outcome string + /// * `market_id` - Optional market ID for event emission + /// + /// # State Requirements + /// + /// * Market must be in `Ended` or `Disputed` state + /// + /// # State Transitions + /// + /// * `Ended` → `Resolved` + /// * `Disputed` → `Resolved` + /// + /// # Side Effects + /// + /// * Sets `market.winning_outcome` to the specified outcome + /// * Transitions market state to `Resolved` + /// * Emits state change event + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String, Symbol}; + /// use crate::markets::MarketStateManager; + /// use crate::types::MarketState; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "ended_market"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Market should be in Ended state + /// assert_eq!(market.state, MarketState::Ended); + /// + /// let winning_outcome = String::from_str(&env, "Yes"); + /// MarketStateManager::set_winning_outcome( + /// &mut market, + /// winning_outcome, + /// Some(&market_id) + /// ); + /// + /// // Market should now be resolved + /// assert_eq!(market.state, MarketState::Resolved); + /// assert!(market.winning_outcome.is_some()); + /// + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn set_winning_outcome(market: &mut Market, outcome: String, market_id: Option<&Symbol>) { MarketStateLogic::check_function_access_for_state("resolve", market.state).unwrap(); let old_state = market.state; @@ -269,7 +1081,57 @@ impl MarketStateManager { } } - /// Mark fees as collected + /// Marks platform fees as collected and transitions market to closed state. + /// + /// This function is called after platform fees have been successfully collected + /// from a resolved market. It transitions the market from `Resolved` to `Closed` + /// state, indicating the market lifecycle is complete. + /// + /// # Parameters + /// + /// * `market` - Mutable reference to the market + /// * `market_id` - Optional market ID for event emission + /// + /// # State Requirements + /// + /// * Market must be in `Resolved` state + /// + /// # State Transitions + /// + /// * `Resolved` → `Closed` + /// + /// # Side Effects + /// + /// * Sets `market.fee_collected` to true + /// * Transitions market state to `Closed` + /// * Emits state change event + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateManager; + /// use crate::types::MarketState; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "resolved_market"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Market should be resolved + /// assert_eq!(market.state, MarketState::Resolved); + /// + /// // Collect platform fees (external logic) + /// // ... + /// + /// // Mark fees as collected + /// MarketStateManager::mark_fees_collected(&mut market, Some(&market_id)); + /// + /// // Market should now be closed + /// assert_eq!(market.state, MarketState::Closed); + /// assert!(market.fee_collected); + /// + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn mark_fees_collected(market: &mut Market, market_id: Option<&Symbol>) { MarketStateLogic::check_function_access_for_state("close", market.state).unwrap(); let old_state = market.state; @@ -284,7 +1146,55 @@ impl MarketStateManager { market.fee_collected = true; } - /// Extend market end time for disputes + /// Extends the market end time to allow for dispute resolution. + /// + /// This function extends the market's end time when disputes are raised, + /// providing additional time for dispute resolution processes. The extension + /// only applies if it would result in a longer end time than currently set. + /// + /// # Parameters + /// + /// * `market` - Mutable reference to the market + /// * `_env` - The Soroban environment for blockchain operations + /// * `extension_hours` - Number of hours to extend the market (minimum extension) + /// + /// # Logic + /// + /// The market end time is extended only if the new time (current time + extension) + /// would be later than the current end time. This prevents shortening the market + /// duration accidentally. + /// + /// # Side Effects + /// + /// * May update `market.end_time` to a later timestamp + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateManager; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "disputed_market"); + /// let mut market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// let original_end_time = market.end_time; + /// + /// // Extend market by 24 hours for dispute resolution + /// MarketStateManager::extend_for_dispute(&mut market, &env, 24); + /// + /// // End time should be extended if needed + /// let current_time = env.ledger().timestamp(); + /// let expected_extension = current_time + (24 * 60 * 60); + /// + /// if original_end_time < expected_extension { + /// assert_eq!(market.end_time, expected_extension); + /// } else { + /// assert_eq!(market.end_time, original_end_time); + /// } + /// + /// MarketStateManager::update_market(&env, &market_id, &market); + /// ``` pub fn extend_for_dispute(market: &mut Market, _env: &Env, extension_hours: u64) { let current_time = _env.ledger().timestamp(); let extension_seconds = extension_hours * 60 * 60; @@ -297,11 +1207,54 @@ impl MarketStateManager { // ===== MARKET ANALYTICS ===== -/// Market analytics and statistics utilities +/// Market analytics and statistics utilities for data analysis and insights. +/// +/// This struct provides comprehensive analytics functions for extracting +/// meaningful statistics from market data, including participation metrics, +/// outcome distributions, and consensus analysis. These functions are essential +/// for market monitoring, user interfaces, and decision-making processes. pub struct MarketAnalytics; impl MarketAnalytics { - /// Get market statistics + /// Calculates comprehensive statistics for a market. + /// + /// This function analyzes market participation data to generate detailed + /// statistics including vote counts, stake amounts, and outcome distribution. + /// The statistics are useful for market monitoring and user interfaces. + /// + /// # Parameters + /// + /// * `market` - Reference to the market to analyze + /// + /// # Returns + /// + /// * `MarketStats` - Comprehensive statistics structure containing: + /// - Total number of votes cast + /// - Total amount staked across all participants + /// - Total dispute stakes (if any) + /// - Distribution of votes across different outcomes + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::{MarketAnalytics, MarketStateManager}; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "active_market"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// let stats = MarketAnalytics::get_market_stats(&market); + /// + /// println!("Total votes: {}", stats.total_votes); + /// println!("Total staked: {} stroops", stats.total_staked); + /// println!("Dispute stakes: {} stroops", stats.total_dispute_stakes); + /// + /// // Analyze outcome distribution + /// for (outcome, count) in stats.outcome_distribution.iter() { + /// println!("Outcome '{}': {} votes", outcome, count); + /// } + /// ``` pub fn get_market_stats(market: &Market) -> MarketStats { let total_votes = market.votes.len() as u32; let total_staked = market.total_staked; @@ -322,7 +1275,47 @@ impl MarketAnalytics { } } - /// Calculate winning outcome statistics + /// Calculates detailed statistics for the winning outcome of a resolved market. + /// + /// This function analyzes the winning side of a market to determine payout + /// distributions and winner statistics. It's essential for calculating + /// individual payouts and understanding market resolution outcomes. + /// + /// # Parameters + /// + /// * `market` - Reference to the resolved market + /// * `winning_outcome` - The outcome that won the market + /// + /// # Returns + /// + /// * `WinningStats` - Statistics for the winning outcome including: + /// - The winning outcome string + /// - Total stake amount on the winning outcome + /// - Number of users who voted for the winning outcome + /// - Total pool size for payout calculations + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String, Symbol}; + /// use crate::markets::{MarketAnalytics, MarketStateManager}; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "resolved_market"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// let winning_outcome = String::from_str(&env, "Yes"); + /// let winning_stats = MarketAnalytics::calculate_winning_stats(&market, &winning_outcome); + /// + /// println!("Winning outcome: {}", winning_stats.winning_outcome); + /// println!("Winners: {} users", winning_stats.winning_voters); + /// println!("Winning total: {} stroops", winning_stats.winning_total); + /// println!("Total pool: {} stroops", winning_stats.total_pool); + /// + /// // Calculate payout ratio + /// let payout_ratio = winning_stats.total_pool as f64 / winning_stats.winning_total as f64; + /// println!("Payout multiplier: {:.2}x", payout_ratio); + /// ``` pub fn calculate_winning_stats(market: &Market, winning_outcome: &String) -> WinningStats { let mut winning_total = 0; let mut winning_voters = 0; @@ -342,7 +1335,54 @@ impl MarketAnalytics { } } - /// Get user participation statistics + /// Retrieves comprehensive participation statistics for a specific user in a market. + /// + /// This function analyzes a user's involvement in a market, including their + /// voting status, stake amounts, dispute participation, and claim status. + /// It's useful for user interfaces and determining user eligibility for various actions. + /// + /// # Parameters + /// + /// * `market` - Reference to the market to analyze + /// * `user` - Address of the user to get statistics for + /// + /// # Returns + /// + /// * `UserStats` - User-specific statistics including: + /// - Whether the user has voted + /// - Amount staked by the user + /// - Amount staked in disputes by the user + /// - Whether the user has claimed their winnings + /// - The outcome the user voted for (if any) + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, Symbol}; + /// use crate::markets::{MarketAnalytics, MarketStateManager}; + /// + /// let env = Env::default(); + /// let user = Address::generate(&env); + /// let market_id = Symbol::new(&env, "active_market"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// let user_stats = MarketAnalytics::get_user_stats(&market, &user); + /// + /// if user_stats.has_voted { + /// println!("User voted for: {:?}", user_stats.voted_outcome); + /// println!("Stake amount: {} stroops", user_stats.stake); + /// } else { + /// println!("User has not voted yet"); + /// } + /// + /// if user_stats.dispute_stake > 0 { + /// println!("User disputed with: {} stroops", user_stats.dispute_stake); + /// } + /// + /// if user_stats.has_claimed { + /// println!("User has already claimed winnings"); + /// } + /// ``` pub fn get_user_stats(market: &Market, user: &Address) -> UserStats { let has_voted = market.votes.contains_key(user.clone()); let stake = market.stakes.get(user.clone()).unwrap_or(0); @@ -359,7 +1399,51 @@ impl MarketAnalytics { } } - /// Calculate community consensus + /// Calculates the community consensus for a market based on voting patterns. + /// + /// This function analyzes all votes in a market to determine which outcome + /// has the strongest community support. It calculates both absolute vote counts + /// and percentage consensus, which is crucial for the hybrid resolution algorithm. + /// + /// # Parameters + /// + /// * `market` - Reference to the market to analyze + /// + /// # Returns + /// + /// * `CommunityConsensus` - Consensus analysis including: + /// - The outcome with the most votes + /// - Number of votes for the leading outcome + /// - Total number of votes cast + /// - Percentage of votes for the leading outcome + /// + /// # Algorithm + /// + /// The function counts votes for each outcome and identifies the outcome + /// with the highest vote count. The consensus percentage is calculated as + /// (leading_votes / total_votes) * 100. + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::{MarketAnalytics, MarketStateManager}; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "active_market"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// let consensus = MarketAnalytics::calculate_community_consensus(&market); + /// + /// println!("Community consensus: {}", consensus.outcome); + /// println!("Leading votes: {} out of {}", consensus.votes, consensus.total_votes); + /// println!("Consensus strength: {}%", consensus.percentage); + /// + /// // Check if consensus is strong enough for hybrid resolution + /// if consensus.percentage > 50 && consensus.total_votes >= 5 { + /// println!("Strong community consensus detected"); + /// } + /// ``` pub fn calculate_community_consensus(market: &Market) -> CommunityConsensus { let mut vote_counts: Map = Map::new(&market.votes.env()); @@ -394,7 +1478,47 @@ impl MarketAnalytics { } } - /// Calculate basic analytics for a market + /// Calculates basic analytics for a market (placeholder implementation). + /// + /// This function provides a placeholder for basic market analytics calculation. + /// In a production implementation, this would calculate comprehensive market + /// metrics such as volatility, participation trends, and prediction accuracy. + /// + /// # Parameters + /// + /// * `_market` - Reference to the market to analyze (currently unused) + /// + /// # Returns + /// + /// * `MarketAnalytics` - Empty analytics struct (placeholder) + /// + /// # Note + /// + /// This is a placeholder implementation. In a production system, this function + /// would calculate metrics such as: + /// - Market volatility over time + /// - Participation rate trends + /// - Prediction accuracy scores + /// - Stake distribution patterns + /// - Time-series analysis of voting behavior + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::{MarketAnalytics, MarketStateManager}; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "market_123"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Currently returns placeholder analytics + /// let analytics = MarketAnalytics::calculate_basic_analytics(&market); + /// + /// // In future versions, this would provide detailed insights + /// // println!("Market volatility: {}", analytics.volatility); + /// // println!("Participation trend: {:?}", analytics.trend); + /// ``` pub fn calculate_basic_analytics(_market: &Market) -> MarketAnalytics { // This is a placeholder implementation // In a real implementation, you would calculate comprehensive analytics @@ -404,11 +1528,49 @@ impl MarketAnalytics { // ===== MARKET UTILITIES ===== -/// General market utilities +/// General market utilities for common operations and calculations. +/// +/// This struct provides essential utility functions used throughout the market +/// system, including ID generation, time calculations, fee processing, token +/// operations, payout calculations, and hybrid resolution algorithms. pub struct MarketUtils; impl MarketUtils { - /// Generate unique market ID + /// Generates a unique identifier for a new market. + /// + /// This function creates a unique market ID by incrementing a persistent + /// counter stored in the contract's storage. Each call generates a new + /// unique identifier to ensure no market ID collisions occur. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// + /// # Returns + /// + /// * `Symbol` - Unique market identifier + /// + /// # Storage Impact + /// + /// Updates the persistent "MarketCounter" key with the next counter value. + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::Env; + /// use crate::markets::MarketUtils; + /// + /// let env = Env::default(); + /// + /// // Generate unique market IDs + /// let market_id_1 = MarketUtils::generate_market_id(&env); + /// let market_id_2 = MarketUtils::generate_market_id(&env); + /// + /// // IDs are unique + /// assert_ne!(market_id_1, market_id_2); + /// + /// println!("Created market: {}", market_id_1); + /// ``` pub fn generate_market_id(_env: &Env) -> Symbol { let counter_key = Symbol::new(_env, "MarketCounter"); let counter: u32 = _env.storage().persistent().get(&counter_key).unwrap_or(0); @@ -418,21 +1580,136 @@ impl MarketUtils { Symbol::new(_env, "market") } - /// Calculate market end time + /// Calculates the end timestamp for a market based on duration in days. + /// + /// This function determines when a market should end by adding the specified + /// duration to the current blockchain timestamp. The calculation uses precise + /// time arithmetic to ensure accurate market scheduling. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `duration_days` - Market duration in days (1-365) + /// + /// # Returns + /// + /// * `u64` - Unix timestamp when the market should end + /// + /// # Time Calculation + /// + /// End time = Current timestamp + (duration_days × 24 × 60 × 60 seconds) + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::Env; + /// use crate::markets::MarketUtils; + /// + /// let env = Env::default(); + /// let current_time = env.ledger().timestamp(); + /// + /// // Calculate end time for 30-day market + /// let end_time = MarketUtils::calculate_end_time(&env, 30); + /// + /// // Verify calculation + /// let expected_duration = 30 * 24 * 60 * 60; // 30 days in seconds + /// assert_eq!(end_time, current_time + expected_duration); + /// + /// println!("Market ends at timestamp: {}", end_time); + /// ``` pub fn calculate_end_time(_env: &Env, duration_days: u32) -> u64 { let seconds_per_day: u64 = 24 * 60 * 60; let duration_seconds: u64 = (duration_days as u64) * seconds_per_day; _env.ledger().timestamp() + duration_seconds } - /// Process market creation fee (moved to fees module) - /// This function is deprecated and should use FeeManager::process_creation_fee instead + /// Processes the market creation fee by delegating to the fees module. + /// + /// This function handles the collection of market creation fees from the + /// market administrator. It's a convenience wrapper that delegates to the + /// dedicated fees module for consistent fee processing. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `admin` - Address of the market administrator who pays the fee + /// + /// # Returns + /// + /// * `Ok(())` - Fee processed successfully + /// * `Err(Error)` - Fee processing failed + /// + /// # Errors + /// + /// * `Error::InsufficientBalance` - Admin lacks funds for the creation fee + /// * `Error::InvalidState` - Contract is not properly configured + /// + /// # Deprecation Notice + /// + /// This function is a wrapper around `FeeManager::process_creation_fee`. + /// Direct use of the fees module is recommended for new implementations. + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address}; + /// use crate::markets::MarketUtils; + /// + /// let env = Env::default(); + /// let admin = Address::generate(&env); + /// + /// // Process creation fee + /// match MarketUtils::process_creation_fee(&env, &admin) { + /// Ok(()) => println!("Creation fee processed successfully"), + /// Err(e) => println!("Fee processing failed: {:?}", e), + /// } + /// ``` pub fn process_creation_fee(_env: &Env, admin: &Address) -> Result<(), Error> { // Delegate to the fees module crate::fees::FeeManager::process_creation_fee(_env, admin) } - /// Get token client for market operations + /// Retrieves the token client for market-related token operations. + /// + /// This function creates a token client instance for the contract's configured + /// token. The token client is used for transferring stakes, processing fees, + /// and distributing payouts throughout the market lifecycle. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// + /// # Returns + /// + /// * `Ok(token::Client)` - Configured token client for operations + /// * `Err(Error)` - Token configuration is invalid or missing + /// + /// # Errors + /// + /// * `Error::InvalidState` - Token ID is not configured in contract storage + /// + /// # Storage Dependency + /// + /// Requires the "TokenID" key to be set in persistent storage during + /// contract initialization. + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::Env; + /// use crate::markets::MarketUtils; + /// + /// let env = Env::default(); + /// + /// // Get token client for operations + /// match MarketUtils::get_token_client(&env) { + /// Ok(token_client) => { + /// println!("Token client ready for operations"); + /// // Use token_client for transfers, balance checks, etc. + /// }, + /// Err(e) => println!("Token client unavailable: {:?}", e), + /// } + /// ``` pub fn get_token_client(_env: &Env) -> Result { let token_id: Address = _env .storage() @@ -443,7 +1720,51 @@ impl MarketUtils { Ok(token::Client::new(_env, &token_id)) } - /// Calculate payout for winning user + /// Calculates the payout amount for a winning user based on their stake and pool distribution. + /// + /// This function implements the payout algorithm for prediction markets, + /// distributing the total pool among winning participants proportionally + /// to their stakes, minus platform fees. + /// + /// # Parameters + /// + /// * `user_stake` - Amount the user staked on the winning outcome + /// * `winning_total` - Total amount staked on the winning outcome by all users + /// * `total_pool` - Total amount staked across all outcomes + /// * `fee_percentage` - Platform fee percentage (e.g., 2 for 2%) + /// + /// # Returns + /// + /// * `Ok(i128)` - Calculated payout amount for the user + /// * `Err(Error)` - Calculation failed due to invalid parameters + /// + /// # Errors + /// + /// * `Error::NothingToClaim` - No winning stakes exist (winning_total is 0) + /// + /// # Payout Formula + /// + /// ```text + /// user_share = user_stake * (100 - fee_percentage) / 100 + /// payout = user_share * total_pool / winning_total + /// ``` + /// + /// # Example + /// + /// ```rust + /// use crate::markets::MarketUtils; + /// + /// // User staked 1000 tokens on winning outcome + /// // Total winning stakes: 5000 tokens + /// // Total pool: 10000 tokens + /// // Platform fee: 2% + /// let payout = MarketUtils::calculate_payout(1000, 5000, 10000, 2)?; + /// + /// // Expected: (1000 * 98 / 100) * 10000 / 5000 = 1960 tokens + /// assert_eq!(payout, 1960); + /// + /// println!("User payout: {} tokens", payout); + /// ``` pub fn calculate_payout( user_stake: i128, winning_total: i128, @@ -460,7 +1781,62 @@ impl MarketUtils { Ok(payout) } - /// Determine final market result using hybrid algorithm + /// Determines the final market result using the hybrid oracle-community algorithm. + /// + /// This function implements Predictify's core hybrid resolution mechanism, + /// combining oracle data with community consensus to determine the final + /// market outcome. The algorithm provides resilience against oracle failures + /// and incorporates community wisdom. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// * `oracle_result` - The outcome determined by the oracle + /// * `community_consensus` - Community voting consensus data + /// + /// # Returns + /// + /// * `String` - The final determined outcome for the market + /// + /// # Algorithm Logic + /// + /// 1. **Agreement**: If oracle and community agree, use that outcome + /// 2. **Strong Consensus**: If community has >50% consensus with ≥5 votes: + /// - 70% weight to oracle result + /// - 30% weight to community result + /// - Use pseudo-random selection based on blockchain data + /// 3. **Weak Consensus**: Default to oracle result + /// + /// # Randomness Source + /// + /// Uses blockchain timestamp and sequence number for pseudo-random selection + /// when applying the 70-30 weighting mechanism. + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String}; + /// use crate::markets::MarketUtils; + /// use crate::types::CommunityConsensus; + /// + /// let env = Env::default(); + /// let oracle_result = String::from_str(&env, "Yes"); + /// let community_consensus = CommunityConsensus { + /// outcome: String::from_str(&env, "No"), + /// votes: 8, + /// total_votes: 10, + /// percentage: 80, // Strong community consensus + /// }; + /// + /// let final_result = MarketUtils::determine_final_result( + /// &env, + /// &oracle_result, + /// &community_consensus + /// ); + /// + /// // Result will be either "Yes" (70% chance) or "No" (30% chance) + /// println!("Final market result: {}", final_result); + /// ``` pub fn determine_final_result( _env: &Env, oracle_result: &String, @@ -495,7 +1871,34 @@ impl MarketUtils { // ===== MARKET STATISTICS TYPES ===== -/// Market statistics +/// Comprehensive market statistics for analysis and monitoring. +/// +/// This structure contains aggregated data about market participation, +/// including vote counts, stake amounts, and outcome distribution. +/// It's used by analytics functions and user interfaces to display +/// market health and participation metrics. +/// +/// # Fields +/// +/// * `total_votes` - Total number of votes cast in the market +/// * `total_staked` - Total amount staked across all participants (in token base units) +/// * `total_dispute_stakes` - Total amount staked in disputes (in token base units) +/// * `outcome_distribution` - Map of outcomes to their respective vote counts +/// +/// # Example Usage +/// +/// ```rust +/// use crate::markets::{MarketAnalytics, MarketStateManager}; +/// use soroban_sdk::{Env, Symbol}; +/// +/// let env = Env::default(); +/// let market_id = Symbol::new(&env, "market_123"); +/// let market = MarketStateManager::get_market(&env, &market_id)?; +/// let stats = MarketAnalytics::get_market_stats(&market); +/// +/// println!("Market participation: {} votes", stats.total_votes); +/// println!("Total value locked: {} stroops", stats.total_staked); +/// ``` #[contracttype] #[derive(Clone, Debug)] pub struct MarketStats { @@ -505,7 +1908,43 @@ pub struct MarketStats { pub outcome_distribution: Map, } -/// Winning outcome statistics +/// Statistics for the winning outcome of a resolved market. +/// +/// This structure contains detailed information about the winning side +/// of a prediction market, including stake distribution and participant +/// counts. It's essential for calculating individual payouts and +/// understanding market resolution outcomes. +/// +/// # Fields +/// +/// * `winning_outcome` - The outcome that won the market +/// * `winning_total` - Total amount staked on the winning outcome (in token base units) +/// * `winning_voters` - Number of participants who voted for the winning outcome +/// * `total_pool` - Total amount staked across all outcomes (in token base units) +/// +/// # Payout Calculations +/// +/// This structure provides the data needed for payout calculations: +/// - Individual payout = (user_stake / winning_total) × total_pool × (1 - fee_rate) +/// - Payout multiplier = total_pool / winning_total +/// +/// # Example Usage +/// +/// ```rust +/// use crate::markets::MarketAnalytics; +/// use soroban_sdk::{Env, String, Symbol}; +/// +/// let env = Env::default(); +/// let market_id = Symbol::new(&env, "resolved_market"); +/// let market = MarketStateManager::get_market(&env, &market_id)?; +/// let winning_outcome = String::from_str(&env, "Yes"); +/// +/// let winning_stats = MarketAnalytics::calculate_winning_stats(&market, &winning_outcome); +/// let payout_multiplier = winning_stats.total_pool as f64 / winning_stats.winning_total as f64; +/// +/// println!("Winners: {} participants", winning_stats.winning_voters); +/// println!("Payout multiplier: {:.2}x", payout_multiplier); +/// ``` #[derive(Clone, Debug)] pub struct WinningStats { pub winning_outcome: String, @@ -514,7 +1953,50 @@ pub struct WinningStats { pub total_pool: i128, } -/// User participation statistics +/// Individual user participation statistics for a specific market. +/// +/// This structure tracks a user's complete involvement in a market, +/// including voting status, stake amounts, dispute participation, +/// and claim status. It's used for user interfaces and determining +/// user eligibility for various market operations. +/// +/// # Fields +/// +/// * `has_voted` - Whether the user has cast a vote in this market +/// * `stake` - Amount the user staked on their chosen outcome (in token base units) +/// * `dispute_stake` - Amount the user staked in disputes (in token base units) +/// * `has_claimed` - Whether the user has claimed their winnings (if applicable) +/// * `voted_outcome` - The outcome the user voted for (None if hasn't voted) +/// +/// # Use Cases +/// +/// - **UI Display**: Show user's current position and eligibility +/// - **Access Control**: Determine if user can perform specific actions +/// - **Payout Calculation**: Calculate individual winnings +/// - **Analytics**: Track user engagement patterns +/// +/// # Example Usage +/// +/// ```rust +/// use crate::markets::MarketAnalytics; +/// use soroban_sdk::{Env, Address, Symbol}; +/// +/// let env = Env::default(); +/// let user = Address::generate(&env); +/// let market_id = Symbol::new(&env, "market_123"); +/// let market = MarketStateManager::get_market(&env, &market_id)?; +/// +/// let user_stats = MarketAnalytics::get_user_stats(&market, &user); +/// +/// if user_stats.has_voted { +/// println!("User voted for: {:?}", user_stats.voted_outcome); +/// println!("Stake: {} stroops", user_stats.stake); +/// } +/// +/// if !user_stats.has_claimed && market.winning_outcome.is_some() { +/// println!("User may be eligible to claim winnings"); +/// } +/// ``` #[derive(Clone, Debug)] pub struct UserStats { pub has_voted: bool, @@ -524,7 +2006,53 @@ pub struct UserStats { pub voted_outcome: Option, } -/// Community consensus statistics +/// Community consensus analysis for hybrid market resolution. +/// +/// This structure represents the collective opinion of market participants, +/// showing which outcome has the strongest community support. It's a crucial +/// component of Predictify's hybrid resolution algorithm that combines +/// oracle data with community wisdom. +/// +/// # Fields +/// +/// * `outcome` - The outcome with the highest community support +/// * `votes` - Number of votes for the leading outcome +/// * `total_votes` - Total number of votes cast in the market +/// * `percentage` - Percentage of votes for the leading outcome (0-100) +/// +/// # Consensus Strength +/// +/// The consensus is considered "strong" when: +/// - `percentage` > 50% (majority support) +/// - `total_votes` >= 5 (minimum participation threshold) +/// +/// Strong consensus influences the hybrid resolution algorithm by providing +/// a 30% weight against the oracle's 70% weight when they disagree. +/// +/// # Example Usage +/// +/// ```rust +/// use crate::markets::{MarketAnalytics, MarketUtils}; +/// use soroban_sdk::{Env, String, Symbol}; +/// +/// let env = Env::default(); +/// let market_id = Symbol::new(&env, "market_123"); +/// let market = MarketStateManager::get_market(&env, &market_id)?; +/// +/// let consensus = MarketAnalytics::calculate_community_consensus(&market); +/// let oracle_result = String::from_str(&env, "No"); +/// +/// // Check consensus strength +/// if consensus.percentage > 50 && consensus.total_votes >= 5 { +/// println!("Strong community consensus: {} ({}%)", consensus.outcome, consensus.percentage); +/// +/// // Apply hybrid resolution +/// let final_result = MarketUtils::determine_final_result(&env, &oracle_result, &consensus); +/// println!("Final result: {}", final_result); +/// } else { +/// println!("Weak consensus, defaulting to oracle result"); +/// } +/// ``` #[derive(Clone, Debug)] #[contracttype] pub struct CommunityConsensus { @@ -536,11 +2064,60 @@ pub struct CommunityConsensus { // ===== MARKET TESTING UTILITIES ===== -/// Market testing utilities +/// Market testing utilities for development, testing, and debugging. +/// +/// This struct provides helper functions specifically designed for testing +/// market functionality. These functions create test data, simulate market +/// operations, and provide utilities for unit tests and integration testing. +/// +/// **Note**: These functions are intended for testing environments only. pub struct MarketTestHelpers; impl MarketTestHelpers { - /// Create a test market configuration + /// Creates a standardized test market configuration for testing purposes. + /// + /// This function generates a pre-configured market setup with realistic + /// parameters suitable for testing various market scenarios. It provides + /// consistent test data across different test cases. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// + /// # Returns + /// + /// * `MarketCreationParams` - Pre-configured market parameters including: + /// - Test admin address + /// - Sample prediction question about BTC price + /// - Binary outcomes ("yes", "no") + /// - 30-day duration + /// - Pyth oracle configuration for BTC/USD + /// - Standard creation fee (1 XLM) + /// + /// # Test Configuration Details + /// + /// - **Question**: "Will BTC go above $25,000 by December 31?" + /// - **Outcomes**: ["yes", "no"] + /// - **Duration**: 30 days + /// - **Oracle**: Pyth BTC/USD feed with $25,000 threshold + /// - **Fee**: 1,000,000 stroops (1 XLM) + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::Env; + /// use crate::markets::MarketTestHelpers; + /// + /// let env = Env::default(); + /// let test_config = MarketTestHelpers::create_test_market_config(&env); + /// + /// println!("Test question: {}", test_config.question); + /// println!("Duration: {} days", test_config.duration_days); + /// println!("Oracle provider: {:?}", test_config.oracle_config.provider); + /// + /// // Use config for testing market creation + /// // let market_id = MarketCreator::create_market(...); + /// ``` pub fn create_test_market_config(_env: &Env) -> MarketCreationParams { MarketCreationParams::new( Address::from_str( @@ -564,14 +2141,112 @@ impl MarketTestHelpers { ) } - /// Create a test market + /// Creates a complete test market using the standard test configuration. + /// + /// This convenience function combines test configuration generation with + /// actual market creation, providing a one-step solution for creating + /// test markets in testing environments. + /// + /// # Parameters + /// + /// * `_env` - The Soroban environment for blockchain operations + /// + /// # Returns + /// + /// * `Ok(Symbol)` - Unique identifier of the created test market + /// * `Err(Error)` - Market creation failed + /// + /// # Errors + /// + /// Same as `MarketCreator::create_market`, including: + /// * `Error::InsufficientBalance` - Test admin lacks creation fee funds + /// * `Error::InvalidOracleConfig` - Oracle configuration issues + /// + /// # Prerequisites + /// + /// - Contract must be properly initialized + /// - Token configuration must be set + /// - Test admin must have sufficient balance for creation fee + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::Env; + /// use crate::markets::{MarketTestHelpers, MarketStateManager}; + /// + /// let env = Env::default(); + /// + /// // Create a test market + /// let market_id = MarketTestHelpers::create_test_market(&env) + /// .expect("Test market creation should succeed"); + /// + /// // Verify market was created + /// let market = MarketStateManager::get_market(&env, &market_id) + /// .expect("Market should exist"); + /// + /// println!("Created test market: {}", market_id); + /// println!("Market question: {}", market.question); + /// ``` pub fn create_test_market(_env: &Env) -> Result { let config = Self::create_test_market_config(_env); MarketCreator::create_market(_env, config.admin, config.question, config.outcomes, config.duration_days, config.oracle_config) } - /// Add test vote to market + /// Adds a test vote to an existing market with comprehensive validation. + /// + /// This function simulates a complete voting process including validation, + /// token transfer, and market state updates. It's designed for testing + /// voting scenarios and market participation flows. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the target market + /// * `user` - Address of the user placing the vote + /// * `outcome` - The outcome the user is voting for + /// * `stake` - Amount to stake on this vote (in token base units) + /// + /// # Returns + /// + /// * `Ok(())` - Vote added successfully + /// * `Err(Error)` - Vote addition failed + /// + /// # Errors + /// + /// * `Error::MarketNotFound` - Market doesn't exist + /// * `Error::MarketClosed` - Market has expired or is not accepting votes + /// * `Error::InvalidOutcome` - Outcome is not valid for this market + /// * `Error::InsufficientStake` - Stake is below minimum (0.1 XLM) + /// * `Error::InsufficientBalance` - User lacks sufficient token balance + /// + /// # Process Flow + /// + /// 1. Validates market exists and is accepting votes + /// 2. Validates outcome is valid for the market + /// 3. Validates stake meets minimum requirements + /// 4. Transfers tokens from user to contract + /// 5. Updates market with user's vote and stake + /// 6. Saves updated market state + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Address, String, Symbol}; + /// use crate::markets::MarketTestHelpers; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "test_market"); + /// let user = Address::generate(&env); + /// let outcome = String::from_str(&env, "yes"); + /// let stake = 5_000_000; // 0.5 XLM + /// + /// // Add test vote + /// match MarketTestHelpers::add_test_vote(&env, &market_id, user, outcome, stake) { + /// Ok(()) => println!("Test vote added successfully"), + /// Err(e) => println!("Vote failed: {:?}", e), + /// } + /// ``` pub fn add_test_vote( env: &Env, market_id: &Symbol, @@ -597,7 +2272,64 @@ impl MarketTestHelpers { Ok(()) } - /// Simulate market resolution + /// Simulates the complete market resolution process for testing purposes. + /// + /// This function provides a comprehensive simulation of market resolution, + /// including oracle result processing, community consensus calculation, + /// hybrid algorithm application, and final outcome determination. It's + /// essential for testing resolution logic and payout calculations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market to resolve + /// * `oracle_result` - Simulated oracle result for the market + /// + /// # Returns + /// + /// * `Ok(String)` - Final determined outcome after hybrid resolution + /// * `Err(Error)` - Resolution simulation failed + /// + /// # Errors + /// + /// * `Error::MarketNotFound` - Market doesn't exist + /// * `Error::MarketClosed` - Market hasn't expired yet or is in wrong state + /// * `Error::OracleUnavailable` - Oracle result processing failed + /// + /// # Resolution Process + /// + /// 1. Validates market is ready for resolution + /// 2. Sets the provided oracle result + /// 3. Calculates community consensus from votes + /// 4. Applies hybrid resolution algorithm + /// 5. Sets winning outcome and updates market state + /// 6. Returns the final determined outcome + /// + /// # State Changes + /// + /// - Market state transitions to `Resolved` + /// - `oracle_result` is set + /// - `winning_outcome` is determined and set + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, String, Symbol}; + /// use crate::markets::MarketTestHelpers; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "expired_market"); + /// let oracle_result = String::from_str(&env, "yes"); + /// + /// // Simulate resolution + /// match MarketTestHelpers::simulate_market_resolution(&env, &market_id, oracle_result) { + /// Ok(final_outcome) => { + /// println!("Market resolved with outcome: {}", final_outcome); + /// // Proceed with payout calculations + /// }, + /// Err(e) => println!("Resolution failed: {:?}", e), + /// } + /// ``` pub fn simulate_market_resolution( env: &Env, market_id: &Symbol, @@ -627,10 +2359,62 @@ impl MarketTestHelpers { // ===== MARKET STATE LOGIC ===== +/// Market state logic and transition management utilities. +/// +/// This struct provides comprehensive functions for managing market state +/// transitions, validating state-dependent operations, and ensuring proper +/// market lifecycle management. It enforces business rules and maintains +/// data consistency throughout market operations. pub struct MarketStateLogic; impl MarketStateLogic { - /// Validate allowed state transitions + /// Validates that a market state transition is allowed by business rules. + /// + /// This function enforces the market state machine by validating that + /// transitions between states follow the defined business logic. It prevents + /// invalid state changes that could compromise market integrity. + /// + /// # Parameters + /// + /// * `from` - Current market state + /// * `to` - Target market state + /// + /// # Returns + /// + /// * `Ok(())` - Transition is valid and allowed + /// * `Err(Error)` - Transition is not allowed + /// + /// # Errors + /// + /// * `Error::InvalidState` - The requested state transition is not allowed + /// + /// # Valid State Transitions + /// + /// * `Active` → `Ended`, `Cancelled`, `Closed`, `Disputed` + /// * `Ended` → `Resolved`, `Disputed`, `Closed`, `Cancelled` + /// * `Disputed` → `Resolved`, `Closed`, `Cancelled` + /// * `Resolved` → `Closed` + /// * `Closed` → (no transitions allowed) + /// * `Cancelled` → (no transitions allowed) + /// + /// # Example + /// + /// ```rust + /// use crate::markets::MarketStateLogic; + /// use crate::types::MarketState; + /// + /// // Valid transition + /// assert!(MarketStateLogic::validate_state_transition( + /// MarketState::Active, + /// MarketState::Ended + /// ).is_ok()); + /// + /// // Invalid transition + /// assert!(MarketStateLogic::validate_state_transition( + /// MarketState::Closed, + /// MarketState::Active + /// ).is_err()); + /// ``` pub fn validate_state_transition(from: MarketState, to: MarketState) -> Result<(), Error> { use MarketState::*; let allowed = match from { @@ -648,7 +2432,53 @@ impl MarketStateLogic { } } - /// Check if a function is allowed in the given state + /// Validates that a specific function can be executed in the given market state. + /// + /// This function enforces access control based on market state, ensuring + /// that operations are only performed when appropriate. It prevents actions + /// like voting on closed markets or claiming from unresolved markets. + /// + /// # Parameters + /// + /// * `function` - Name of the function to validate ("vote", "dispute", "resolve", "claim", "close") + /// * `state` - Current market state to check against + /// + /// # Returns + /// + /// * `Ok(())` - Function is allowed in the current state + /// * `Err(Error)` - Function is not allowed in the current state + /// + /// # Errors + /// + /// * `Error::MarketClosed` - Function is not allowed in the current market state + /// + /// # Function Access Rules + /// + /// * **vote**: Only allowed in `Active` state + /// * **dispute**: Only allowed in `Ended` state + /// * **resolve**: Allowed in `Ended` or `Disputed` states + /// * **claim**: Only allowed in `Resolved` state + /// * **close**: Allowed in `Resolved`, `Cancelled`, or `Closed` states + /// * **other**: All other functions are allowed by default + /// + /// # Example + /// + /// ```rust + /// use crate::markets::MarketStateLogic; + /// use crate::types::MarketState; + /// + /// // Check if voting is allowed + /// match MarketStateLogic::check_function_access_for_state("vote", MarketState::Active) { + /// Ok(()) => println!("Voting is allowed"), + /// Err(_) => println!("Voting is not allowed"), + /// } + /// + /// // Check if claiming is allowed + /// assert!(MarketStateLogic::check_function_access_for_state( + /// "claim", + /// MarketState::Resolved + /// ).is_ok()); + /// ``` pub fn check_function_access_for_state(function: &str, state: MarketState) -> Result<(), Error> { use MarketState::*; let allowed = match function { @@ -666,12 +2496,93 @@ impl MarketStateLogic { } } - /// Emit a state change event (placeholder: use env.events().publish) + /// Emits a blockchain event when a market state changes. + /// + /// This function publishes state change events to the blockchain event system, + /// enabling external systems and user interfaces to track market lifecycle + /// changes in real-time. Events are essential for monitoring and analytics. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market that changed state + /// * `old_state` - Previous market state + /// * `new_state` - New market state after transition + /// + /// # Event Structure + /// + /// The event is published with: + /// - **Topic**: `("market_state_change", market_id)` + /// - **Data**: `(old_state, new_state)` + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateLogic; + /// use crate::types::MarketState; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "market_123"); + /// + /// // Emit state change event + /// MarketStateLogic::emit_state_change_event( + /// &env, + /// &market_id, + /// MarketState::Active, + /// MarketState::Ended + /// ); + /// + /// // External systems can now detect this state change + /// ``` pub fn emit_state_change_event(env: &Env, market_id: &Symbol, old_state: MarketState, new_state: MarketState) { env.events().publish(("market_state_change", market_id), (old_state, new_state)); } - /// Validate that the market's state is consistent with its data + /// Validates that a market's state is consistent with its internal data. + /// + /// This function performs comprehensive consistency checks to ensure that + /// the market's state matches its data properties. It helps detect and + /// prevent data corruption or invalid state combinations. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market` - Market to validate for state consistency + /// + /// # Returns + /// + /// * `Ok(())` - Market state is consistent with its data + /// * `Err(Error)` - Market state is inconsistent + /// + /// # Errors + /// + /// * `Error::InvalidState` - Market state doesn't match its data properties + /// + /// # Consistency Rules + /// + /// * **Active**: Must not be expired, must not have winning outcome + /// * **Ended**: Must be expired, must not have winning outcome + /// * **Disputed**: Must have dispute stakes + /// * **Resolved**: Must have winning outcome set + /// * **Closed/Cancelled**: No specific data requirements + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::{MarketStateLogic, MarketStateManager}; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "market_123"); + /// let market = MarketStateManager::get_market(&env, &market_id)?; + /// + /// // Validate state consistency + /// match MarketStateLogic::validate_market_state_consistency(&env, &market) { + /// Ok(()) => println!("Market state is consistent"), + /// Err(e) => println!("State inconsistency detected: {:?}", e), + /// } + /// ``` pub fn validate_market_state_consistency(env: &Env, market: &Market) -> Result<(), Error> { use MarketState::*; let now = env.ledger().timestamp(); @@ -707,13 +2618,102 @@ impl MarketStateLogic { Ok(()) } - /// Get the current state of a market + /// Retrieves the current state of a market by its identifier. + /// + /// This convenience function fetches a market from storage and returns + /// its current state. It's useful for quick state checks without loading + /// the entire market data structure. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market + /// + /// # Returns + /// + /// * `Ok(MarketState)` - Current state of the market + /// * `Err(Error)` - Market not found or access error + /// + /// # Errors + /// + /// * `Error::MarketNotFound` - No market exists with the specified ID + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateLogic; + /// use crate::types::MarketState; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "market_123"); + /// + /// match MarketStateLogic::get_market_state(&env, &market_id) { + /// Ok(state) => { + /// match state { + /// MarketState::Active => println!("Market is accepting votes"), + /// MarketState::Ended => println!("Market has ended, awaiting resolution"), + /// MarketState::Resolved => println!("Market is resolved, users can claim"), + /// _ => println!("Market state: {:?}", state), + /// } + /// }, + /// Err(e) => println!("Could not get market state: {:?}", e), + /// } + /// ``` pub fn get_market_state(env: &Env, market_id: &Symbol) -> Result { let market = MarketStateManager::get_market(env, market_id)?; Ok(market.state) } - /// Check if a market can transition to a target state + /// Checks if a market can transition to a specific target state. + /// + /// This function determines whether a state transition is possible for + /// a given market by checking the current state against the target state + /// using the state transition validation rules. + /// + /// # Parameters + /// + /// * `env` - The Soroban environment for blockchain operations + /// * `market_id` - Unique identifier of the market + /// * `target_state` - Desired state to transition to + /// + /// # Returns + /// + /// * `Ok(bool)` - `true` if transition is allowed, `false` if not + /// * `Err(Error)` - Market not found or access error + /// + /// # Errors + /// + /// * `Error::MarketNotFound` - No market exists with the specified ID + /// + /// # Example + /// + /// ```rust + /// use soroban_sdk::{Env, Symbol}; + /// use crate::markets::MarketStateLogic; + /// use crate::types::MarketState; + /// + /// let env = Env::default(); + /// let market_id = Symbol::new(&env, "market_123"); + /// + /// // Check if market can be resolved + /// match MarketStateLogic::can_transition_to_state(&env, &market_id, MarketState::Resolved) { + /// Ok(true) => println!("Market can be resolved"), + /// Ok(false) => println!("Market cannot be resolved yet"), + /// Err(e) => println!("Error checking transition: {:?}", e), + /// } + /// + /// // Check if market can be closed + /// let can_close = MarketStateLogic::can_transition_to_state( + /// &env, + /// &market_id, + /// MarketState::Closed + /// )?; + /// + /// if can_close { + /// println!("Market is ready to be closed"); + /// } + /// ``` pub fn can_transition_to_state(env: &Env, market_id: &Symbol, target_state: MarketState) -> Result { let market = MarketStateManager::get_market(env, market_id)?; Ok(MarketStateLogic::validate_state_transition(market.state, target_state).is_ok()) diff --git a/contracts/predictify-hybrid/src/oracles.rs b/contracts/predictify-hybrid/src/oracles.rs index 14c3af82..a1909700 100644 --- a/contracts/predictify-hybrid/src/oracles.rs +++ b/contracts/predictify-hybrid/src/oracles.rs @@ -17,7 +17,77 @@ use crate::types::*; // ===== ORACLE INTERFACE ===== -/// Standard interface for all oracle implementations +/// Standard interface defining the contract for all oracle implementations. +/// +/// This trait establishes a unified API for interacting with different oracle providers, +/// enabling seamless switching between oracle sources and consistent behavior across +/// the platform. All oracle implementations must conform to this interface. +/// +/// # Design Philosophy +/// +/// The interface follows these principles: +/// - **Provider Agnostic**: Works with any oracle provider (Pyth, Reflector, etc.) +/// - **Consistent API**: Uniform method signatures across all implementations +/// - **Error Handling**: Standardized error types for predictable behavior +/// - **Health Monitoring**: Built-in oracle health and availability checking +/// +/// # Supported Operations +/// +/// All oracle implementations must support: +/// - **Price Retrieval**: Get current prices for specified asset feeds +/// - **Provider Identification**: Return the oracle provider type +/// - **Contract Access**: Provide oracle contract address information +/// - **Health Checking**: Verify oracle availability and operational status +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::oracles::{OracleInterface, ReflectorOracle}; +/// # use predictify_hybrid::types::OracleProvider; +/// # let env = Env::default(); +/// # let oracle_address = soroban_sdk::Address::generate(&env); +/// +/// // Create oracle instance +/// let oracle = ReflectorOracle::new(oracle_address); +/// +/// // Check oracle health before use +/// if oracle.is_healthy(&env).unwrap_or(false) { +/// // Get price for BTC/USD feed +/// let btc_price = oracle.get_price( +/// &env, +/// &String::from_str(&env, "BTC/USD") +/// ); +/// +/// match btc_price { +/// Ok(price) => println!("BTC price: ${}", price / 100), +/// Err(e) => println!("Failed to get price: {:?}", e), +/// } +/// +/// // Verify provider type +/// assert_eq!(oracle.provider(), OracleProvider::Reflector); +/// } else { +/// println!("Oracle is not healthy, using fallback"); +/// } +/// ``` +/// +/// # Implementation Requirements +/// +/// Oracle implementations must: +/// - Handle network failures gracefully with appropriate error codes +/// - Validate feed IDs and return meaningful errors for invalid feeds +/// - Implement proper authentication and authorization where required +/// - Provide accurate health status based on actual oracle availability +/// - Return prices in consistent units (typically with 8 decimal precision) +/// +/// # Error Handling +/// +/// Common error scenarios: +/// - **Network Issues**: Oracle service unavailable or unreachable +/// - **Invalid Feeds**: Requested feed ID not supported by oracle +/// - **Authentication**: Oracle requires authentication that failed +/// - **Rate Limiting**: Too many requests to oracle service +/// - **Data Quality**: Oracle returned invalid or stale price data pub trait OracleInterface { /// Get the current price for a given feed ID fn get_price(&self, env: &Env, feed_id: &String) -> Result; @@ -34,22 +104,165 @@ pub trait OracleInterface { // ===== PYTH ORACLE IMPLEMENTATION ===== -/// Pyth Network oracle implementation +/// Pyth Network oracle implementation for future Stellar blockchain support. +/// +/// **Current Status**: Pyth Network does not currently support Stellar blockchain. +/// This implementation is designed to be future-proof and follows Rust best practices +/// for when Pyth becomes available on Stellar. +/// +/// # Implementation Strategy +/// +/// This oracle implementation: +/// - **Future-Ready**: Designed for easy integration when Pyth supports Stellar +/// - **Error Handling**: Returns appropriate errors indicating unavailability +/// - **Configuration Support**: Maintains feed configurations for future use +/// - **Standard Interface**: Implements OracleInterface for consistency /// -/// **Important**: Pyth Network does not currently support Stellar blockchain. -/// This implementation is designed to be future-proof and follows Rust best practices. -/// When Pyth becomes available on Stellar, this implementation can be easily updated -/// to use the actual Pyth price feeds. +/// # Pyth Network Overview /// -/// For now, this implementation returns appropriate errors to indicate that Pyth -/// is not available on Stellar. +/// Pyth Network is a high-frequency, cross-chain oracle network that provides +/// real-time financial market data. Key features include: +/// - **High Frequency**: Sub-second price updates +/// - **Institutional Grade**: Data from major trading firms and exchanges +/// - **Cross-Chain**: Supports multiple blockchain networks +/// - **Decentralized**: Distributed network of data providers +/// +/// # Example Usage (Future) +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String, Vec}; +/// # use predictify_hybrid::oracles::{PythOracle, PythFeedConfig, OracleInterface}; +/// # let env = Env::default(); +/// # let contract_id = Address::generate(&env); +/// +/// // Create Pyth oracle with feed configurations +/// let mut oracle = PythOracle::new(contract_id.clone()); +/// +/// // Add BTC/USD feed configuration +/// oracle.add_feed_config(PythFeedConfig { +/// feed_id: String::from_str(&env, "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"), +/// asset_symbol: String::from_str(&env, "BTC/USD"), +/// decimals: 8, +/// is_active: true, +/// }); +/// +/// // Currently returns error (Pyth not available on Stellar) +/// let price_result = oracle.get_price(&env, &String::from_str(&env, "BTC/USD")); +/// assert!(price_result.is_err()); +/// +/// // Check oracle provider +/// assert_eq!(oracle.provider(), OracleProvider::Pyth); +/// +/// // Validate feed configurations +/// assert_eq!(oracle.get_feed_count(), 1); +/// assert!(oracle.is_feed_active(&String::from_str(&env, "BTC/USD"))); +/// ``` +/// +/// # Feed Configuration +/// +/// Pyth feeds are identified by: +/// - **Feed ID**: Unique 64-character hexadecimal identifier +/// - **Asset Symbol**: Human-readable symbol (e.g., "BTC/USD") +/// - **Decimals**: Price precision (typically 8 for crypto) +/// - **Active Status**: Whether the feed is currently active +/// +/// # Migration Path +/// +/// When Pyth becomes available on Stellar: +/// 1. **Update Dependencies**: Add Pyth Stellar SDK +/// 2. **Implement get_price()**: Replace error with actual Pyth price fetching +/// 3. **Add Authentication**: Implement any required Pyth authentication +/// 4. **Update Health Check**: Connect to actual Pyth network status +/// 5. **Test Integration**: Comprehensive testing with live Pyth feeds +/// +/// # Current Limitations +/// +/// - All price requests return `Error::OracleNotAvailable` +/// - Health checks always return `false` +/// - No actual network connectivity to Pyth services +/// - Feed configurations are stored but not used for price fetching #[derive(Debug, Clone)] pub struct PythOracle { contract_id: Address, feed_configurations: Vec, } -/// Pyth feed configuration +/// Configuration structure for Pyth Network price feeds. +/// +/// This structure defines the parameters needed to configure and manage +/// individual price feeds from the Pyth Network. Each feed represents +/// a specific asset pair with its own unique identifier and characteristics. +/// +/// # Feed Identification +/// +/// Pyth feeds use: +/// - **Unique Feed IDs**: 64-character hexadecimal identifiers +/// - **Asset Symbols**: Human-readable trading pair names +/// - **Precision Settings**: Decimal places for price representation +/// - **Status Flags**: Active/inactive feed management +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::oracles::PythFeedConfig; +/// # let env = Env::default(); +/// +/// // Configure BTC/USD feed +/// let btc_config = PythFeedConfig { +/// feed_id: String::from_str(&env, +/// "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"), +/// asset_symbol: String::from_str(&env, "BTC/USD"), +/// decimals: 8, // 8 decimal places for crypto prices +/// is_active: true, +/// }; +/// +/// // Configure ETH/USD feed +/// let eth_config = PythFeedConfig { +/// feed_id: String::from_str(&env, +/// "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"), +/// asset_symbol: String::from_str(&env, "ETH/USD"), +/// decimals: 8, +/// is_active: true, +/// }; +/// +/// // Configure stock feed with different precision +/// let aapl_config = PythFeedConfig { +/// feed_id: String::from_str(&env, +/// "0x49f6b65cb1de6b10eaf75e7c03ca029c306d0357e91b5311b175084a5ad55688"), +/// asset_symbol: String::from_str(&env, "AAPL/USD"), +/// decimals: 2, // 2 decimal places for stock prices +/// is_active: true, +/// }; +/// +/// println!("Configured {} with {} decimals", +/// btc_config.asset_symbol.to_string(), +/// btc_config.decimals); +/// ``` +/// +/// # Feed ID Format +/// +/// Pyth feed IDs are: +/// - **64 characters long**: Hexadecimal representation +/// - **Globally unique**: Each feed has a unique identifier across all assets +/// - **Immutable**: Feed IDs don't change once assigned +/// - **Network specific**: Different IDs for different blockchain networks +/// +/// # Decimal Precision +/// +/// Common decimal configurations: +/// - **Crypto pairs**: 8 decimals (e.g., BTC/USD: $45,123.45678901) +/// - **Forex pairs**: 6 decimals (e.g., EUR/USD: 1.123456) +/// - **Stock prices**: 2 decimals (e.g., AAPL: $150.25) +/// - **Commodities**: Variable based on asset type +/// +/// # Feed Management +/// +/// Feed configurations support: +/// - **Dynamic activation**: Enable/disable feeds without removing configuration +/// - **Batch operations**: Configure multiple feeds simultaneously +/// - **Validation**: Ensure feed IDs and symbols are properly formatted +/// - **Asset discovery**: List all configured assets and their symbols #[contracttype] #[derive(Debug, Clone)] pub struct PythFeedConfig { @@ -296,10 +509,87 @@ impl OracleInterface for PythOracle { // ===== REFLECTOR ORACLE CLIENT ===== -/// Client for interacting with Reflector oracle contract +/// Client for interacting with Reflector oracle contract on Stellar Network. +/// +/// Reflector is the primary oracle provider for the Stellar Network, offering +/// institutional-grade price feeds with high reliability, security, and native +/// integration with the Stellar ecosystem. This client provides a convenient +/// interface for accessing Reflector's price data and oracle services. +/// +/// # Reflector Network Overview +/// +/// Reflector provides: +/// - **Real-time Price Feeds**: Live market data for major cryptocurrencies +/// - **TWAP Calculations**: Time-weighted average prices for volatility smoothing +/// - **High Availability**: Enterprise-grade uptime and reliability +/// - **Stellar Native**: Built specifically for Stellar blockchain +/// - **Multiple Assets**: Support for BTC, ETH, XLM, and other major cryptocurrencies +/// +/// # Supported Operations +/// +/// The client supports: +/// - **Latest Price**: Get the most recent price for any supported asset +/// - **Historical Price**: Retrieve price data at specific timestamps +/// - **TWAP**: Calculate time-weighted average prices over specified periods +/// - **Health Monitoring**: Check oracle availability and responsiveness +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address}; +/// # use predictify_hybrid::oracles::ReflectorOracleClient; +/// # use predictify_hybrid::types::ReflectorAsset; +/// # let env = Env::default(); +/// # let oracle_address = Address::generate(&env); +/// +/// // Create Reflector oracle client +/// let client = ReflectorOracleClient::new(&env, oracle_address); +/// +/// // Check oracle health before use +/// if client.is_healthy() { +/// // Get latest BTC price +/// if let Some(btc_data) = client.lastprice(ReflectorAsset::BTC) { +/// println!("BTC price: ${}", btc_data.price / 100); +/// println!("Last updated: {}", btc_data.timestamp); +/// } +/// +/// // Get TWAP for ETH over last 10 records +/// if let Some(eth_twap) = client.twap(ReflectorAsset::ETH, 10) { +/// println!("ETH TWAP: ${}", eth_twap / 100); +/// } +/// +/// // Get historical price at specific timestamp +/// let timestamp = env.ledger().timestamp() - 3600; // 1 hour ago +/// if let Some(historical) = client.price(ReflectorAsset::XLM, timestamp) { +/// println!("XLM price 1h ago: ${}", historical.price / 100); +/// } +/// } else { +/// println!("Reflector oracle is not responding"); +/// } +/// ``` /// -/// Reflector is the primary oracle provider for the Stellar Network, -/// providing real-time price feeds with high reliability and security. +/// # Asset Support +/// +/// Reflector supports major cryptocurrencies including: +/// - **BTC**: Bitcoin price feeds +/// - **ETH**: Ethereum price feeds +/// - **XLM**: Stellar Lumens (native asset) +/// - **Other**: Custom assets via symbol specification +/// +/// # Error Handling +/// +/// The client handles various scenarios: +/// - **Network Issues**: Returns None when oracle is unreachable +/// - **Invalid Assets**: Returns None for unsupported asset types +/// - **Stale Data**: Provides timestamp information for data freshness validation +/// - **Service Downtime**: Health check indicates oracle availability +/// +/// # Performance Considerations +/// +/// - **Caching**: Consider caching price data to reduce oracle calls +/// - **Batch Requests**: Group multiple price requests when possible +/// - **Fallback Strategy**: Implement fallback mechanisms for oracle downtime +/// - **Rate Limiting**: Respect oracle rate limits to avoid service disruption pub struct ReflectorOracleClient<'a> { env: &'a Env, contract_id: Address, @@ -350,13 +640,114 @@ impl<'a> ReflectorOracleClient<'a> { // ===== REFLECTOR ORACLE IMPLEMENTATION ===== -/// Reflector oracle implementation for Stellar Network +/// Reflector oracle implementation for Stellar Network integration. +/// +/// This is the primary and recommended oracle provider for Stellar blockchain, +/// offering enterprise-grade price feeds with native Stellar integration. +/// The implementation provides a standardized interface for accessing Reflector's +/// comprehensive oracle services. +/// +/// # Key Features +/// +/// Reflector oracle provides: +/// - **Real-time Price Feeds**: Live market data with sub-second updates +/// - **TWAP Calculations**: Time-weighted average prices for volatility smoothing +/// - **High Reliability**: Enterprise-grade uptime and service availability +/// - **Stellar Native**: Built specifically for Stellar blockchain ecosystem +/// - **Multi-Asset Support**: BTC, ETH, XLM, and other major cryptocurrencies +/// - **Historical Data**: Access to historical price information +/// +/// # Implementation Strategy +/// +/// This oracle implementation: +/// - **Production Ready**: Fully functional with live Reflector network +/// - **Error Resilient**: Comprehensive error handling for network issues +/// - **Feed Validation**: Validates feed IDs and asset symbols +/// - **Health Monitoring**: Real-time oracle availability checking +/// - **Standard Interface**: Implements OracleInterface for consistency +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::oracles::{ReflectorOracle, OracleInterface}; +/// # use predictify_hybrid::types::OracleProvider; +/// # let env = Env::default(); +/// # let oracle_address = Address::generate(&env); +/// +/// // Create Reflector oracle instance +/// let oracle = ReflectorOracle::new(oracle_address.clone()); +/// +/// // Verify oracle provider type +/// assert_eq!(oracle.provider(), OracleProvider::Reflector); +/// assert_eq!(oracle.contract_id(), oracle_address); +/// +/// // Check oracle health before use +/// if oracle.is_healthy(&env).unwrap_or(false) { +/// // Get BTC price +/// let btc_price = oracle.get_price( +/// &env, +/// &String::from_str(&env, "BTC/USD") +/// ); +/// +/// match btc_price { +/// Ok(price) => { +/// println!("BTC price: ${}", price / 100); +/// +/// // Use price for market resolution +/// let threshold = 50_000_00; // $50,000 +/// if price > threshold { +/// println!("BTC is above $50k threshold"); +/// } +/// }, +/// Err(e) => println!("Failed to get BTC price: {:?}", e), +/// } +/// +/// // Get ETH price +/// let eth_price = oracle.get_price( +/// &env, +/// &String::from_str(&env, "ETH/USD") +/// ); +/// +/// if let Ok(price) = eth_price { +/// println!("ETH price: ${}", price / 100); +/// } +/// } else { +/// println!("Reflector oracle is not healthy, using fallback"); +/// } +/// ``` +/// +/// # Feed ID Format /// -/// This is the primary oracle provider for Stellar, offering: -/// - Real-time price feeds for major cryptocurrencies -/// - TWAP (Time-Weighted Average Price) calculations -/// - High reliability and uptime -/// - Native integration with Stellar ecosystem +/// Reflector accepts feed IDs in formats: +/// - **Standard Pairs**: "BTC/USD", "ETH/USD", "XLM/USD" +/// - **Asset Only**: "BTC", "ETH", "XLM" (assumes USD denomination) +/// - **Custom Symbols**: Any symbol supported by Reflector network +/// +/// # Price Format +/// +/// Prices are returned as: +/// - **Integer Values**: No floating point arithmetic +/// - **8 Decimal Precision**: Prices multiplied by 100,000,000 +/// - **USD Denomination**: All prices in US Dollar terms +/// - **Positive Values**: Always positive integers representing price +/// +/// # Error Scenarios +/// +/// Common error conditions: +/// - **Network Issues**: Reflector service temporarily unavailable +/// - **Invalid Feeds**: Requested asset not supported by Reflector +/// - **Stale Data**: Price data older than acceptable threshold +/// - **Service Limits**: Rate limiting or quota exceeded +/// +/// # Integration Best Practices +/// +/// For production use: +/// - **Health Checks**: Always verify oracle health before price requests +/// - **Error Handling**: Implement comprehensive error handling and fallbacks +/// - **Caching**: Cache price data to reduce oracle calls and improve performance +/// - **Monitoring**: Monitor oracle responses and implement alerting +/// - **Fallback Strategy**: Have backup oracle or manual resolution procedures #[derive(Debug)] pub struct ReflectorOracle { contract_id: Address, @@ -473,10 +864,111 @@ impl OracleInterface for ReflectorOracle { // ===== ORACLE FACTORY ===== -/// Factory for creating oracle instances +/// Factory pattern implementation for creating oracle instances across different providers. +/// +/// The Oracle Factory provides a centralized mechanism for creating and managing +/// oracle instances, with built-in support for provider validation, configuration +/// management, and Stellar Network compatibility checking. +/// +/// # Supported Providers +/// +/// **Stellar Network Compatible:** +/// - **Reflector**: Primary and recommended oracle provider for Stellar +/// - **Production Ready**: Fully functional with live price feeds +/// +/// **Not Supported on Stellar:** +/// - **Pyth Network**: Not available on Stellar blockchain +/// - **Band Protocol**: Not integrated with Stellar ecosystem +/// - **DIA**: Not available for Stellar Network +/// +/// # Design Philosophy +/// +/// The factory follows these principles: +/// - **Provider Abstraction**: Hide implementation details behind common interface +/// - **Validation**: Ensure only supported providers are instantiated +/// - **Configuration Driven**: Support configuration-based oracle creation +/// - **Error Handling**: Clear error messages for unsupported configurations +/// - **Future Extensibility**: Easy to add new providers when they become available +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address}; +/// # use predictify_hybrid::oracles::{OracleFactory, OracleInstance}; +/// # use predictify_hybrid::types::{OracleProvider, OracleConfig}; +/// # let env = Env::default(); +/// # let oracle_address = Address::generate(&env); +/// +/// // Create Reflector oracle (recommended for Stellar) +/// let reflector_oracle = OracleFactory::create_oracle( +/// OracleProvider::Reflector, +/// oracle_address.clone() +/// ); +/// +/// match reflector_oracle { +/// Ok(OracleInstance::Reflector(oracle)) => { +/// println!("Successfully created Reflector oracle"); +/// // Use oracle for price feeds +/// }, +/// Err(e) => println!("Failed to create oracle: {:?}", e), +/// } +/// +/// // Check provider support before creation +/// if OracleFactory::is_provider_supported(&OracleProvider::Reflector) { +/// println!("Reflector is supported on Stellar"); +/// } +/// +/// // Get recommended provider for Stellar +/// let recommended = OracleFactory::get_recommended_provider(); +/// assert_eq!(recommended, OracleProvider::Reflector); +/// +/// // Create from configuration +/// let config = OracleConfig { +/// provider: OracleProvider::Reflector, +/// // ... other config fields +/// }; +/// +/// let oracle_from_config = OracleFactory::create_from_config( +/// &config, +/// oracle_address +/// ); +/// +/// assert!(oracle_from_config.is_ok()); +/// ``` /// -/// Primary focus on Reflector oracle for Stellar Network. -/// Pyth is marked as unsupported since it's not available on Stellar. +/// # Provider Validation +/// +/// The factory performs validation to ensure: +/// - **Stellar Compatibility**: Only Stellar-compatible providers are allowed +/// - **Implementation Status**: Providers must have working implementations +/// - **Network Support**: Providers must support the target blockchain network +/// - **Configuration Validity**: Oracle configurations must be valid and complete +/// +/// # Error Handling +/// +/// Common error scenarios: +/// - **Unsupported Provider**: Attempting to create oracle for unsupported provider +/// - **Invalid Configuration**: Malformed or incomplete oracle configuration +/// - **Network Mismatch**: Provider not available on current blockchain network +/// - **Contract Issues**: Invalid or unreachable oracle contract address +/// +/// # Future Extensibility +/// +/// When new oracle providers become available on Stellar: +/// 1. **Add Provider Type**: Update OracleProvider enum +/// 2. **Implement Oracle**: Create provider-specific oracle implementation +/// 3. **Update Factory**: Add creation logic in create_oracle method +/// 4. **Update Validation**: Mark provider as supported in is_provider_supported +/// 5. **Test Integration**: Comprehensive testing with new provider +/// +/// # Production Considerations +/// +/// For production deployments: +/// - **Provider Selection**: Use Reflector as primary oracle provider +/// - **Fallback Strategy**: Implement fallback mechanisms for oracle failures +/// - **Configuration Management**: Store oracle configurations securely +/// - **Monitoring**: Monitor oracle creation and health status +/// - **Error Handling**: Implement comprehensive error handling and logging pub struct OracleFactory; impl OracleFactory { @@ -660,9 +1152,118 @@ impl OracleFactory { // ===== ORACLE INSTANCE ENUM ===== -/// Enum to hold different oracle implementations +/// Enumeration of supported oracle implementations for runtime polymorphism. +/// +/// This enum provides a unified interface for working with different oracle providers +/// while maintaining type safety and enabling runtime oracle selection. It abstracts +/// the underlying oracle implementation details behind a common interface. +/// +/// # Supported Implementations +/// +/// **Production Ready:** +/// - **Reflector**: Primary oracle provider for Stellar Network with full functionality +/// +/// **Future/Placeholder:** +/// - **Pyth**: Placeholder implementation for future Stellar support +/// +/// # Design Benefits +/// +/// The enum approach provides: +/// - **Type Safety**: Compile-time guarantees about oracle operations +/// - **Runtime Selection**: Choose oracle provider based on configuration +/// - **Unified Interface**: Common methods across all oracle implementations +/// - **Easy Extension**: Simple to add new oracle providers +/// - **Pattern Matching**: Leverage Rust's powerful pattern matching /// -/// Currently only Reflector is fully supported on Stellar +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::oracles::{OracleFactory, OracleInstance}; +/// # use predictify_hybrid::types::OracleProvider; +/// # let env = Env::default(); +/// # let oracle_address = Address::generate(&env); +/// +/// // Create oracle instance through factory +/// let oracle_result = OracleFactory::create_oracle( +/// OracleProvider::Reflector, +/// oracle_address +/// ); +/// +/// match oracle_result { +/// Ok(oracle_instance) => { +/// // Use unified interface regardless of underlying implementation +/// println!("Oracle provider: {:?}", oracle_instance.provider()); +/// println!("Contract ID: {}", oracle_instance.contract_id()); +/// +/// // Check health before use +/// if oracle_instance.is_healthy(&env).unwrap_or(false) { +/// // Get price using unified interface +/// let price = oracle_instance.get_price( +/// &env, +/// &String::from_str(&env, "BTC/USD") +/// ); +/// +/// match price { +/// Ok(btc_price) => println!("BTC: ${}", btc_price / 100), +/// Err(e) => println!("Price error: {:?}", e), +/// } +/// } +/// +/// // Pattern match for provider-specific operations +/// match oracle_instance { +/// OracleInstance::Reflector(ref reflector) => { +/// println!("Using Reflector oracle"); +/// // Reflector-specific operations if needed +/// }, +/// OracleInstance::Pyth(ref pyth) => { +/// println!("Using Pyth oracle (placeholder)"); +/// // Pyth-specific operations if needed +/// }, +/// } +/// }, +/// Err(e) => println!("Failed to create oracle: {:?}", e), +/// } +/// ``` +/// +/// # Runtime Oracle Selection +/// +/// ```rust +/// # use soroban_sdk::{Env, Address}; +/// # use predictify_hybrid::oracles::{OracleFactory, OracleInstance}; +/// # use predictify_hybrid::types::OracleProvider; +/// # let env = Env::default(); +/// # let oracle_address = Address::generate(&env); +/// +/// // Select oracle based on configuration or conditions +/// let preferred_provider = if cfg!(feature = "use-reflector") { +/// OracleProvider::Reflector +/// } else { +/// OracleFactory::get_recommended_provider() +/// }; +/// +/// let oracle = OracleFactory::create_oracle(preferred_provider, oracle_address)?; +/// +/// // Use oracle regardless of which provider was selected +/// let is_healthy = oracle.is_healthy(&env)?; +/// println!("Oracle health: {}", is_healthy); +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Error Handling +/// +/// All methods return Results for consistent error handling: +/// - **Network Errors**: Oracle service unavailable or unreachable +/// - **Invalid Feeds**: Requested feed not supported by oracle +/// - **Authentication**: Oracle requires authentication that failed +/// - **Rate Limiting**: Too many requests to oracle service +/// +/// # Performance Considerations +/// +/// - **Enum Dispatch**: Minimal overhead for method calls through enum +/// - **Zero-Cost Abstractions**: No runtime cost for abstraction layer +/// - **Memory Efficiency**: Only one oracle instance stored per enum +/// - **Compile-Time Optimization**: Rust compiler optimizes enum dispatch #[derive(Debug)] pub enum OracleInstance { Pyth(PythOracle), // Placeholder - not supported on Stellar @@ -705,7 +1306,119 @@ impl OracleInstance { // ===== ORACLE UTILITIES ===== -/// General oracle utilities +/// Comprehensive utilities for oracle operations, price analysis, and market resolution. +/// +/// The Oracle Utils module provides essential functionality for working with oracle data, +/// including price comparison logic, market outcome determination, data validation, +/// and various helper functions for oracle-based market resolution. +/// +/// # Core Functionality +/// +/// **Price Operations:** +/// - **Price Comparison**: Compare oracle prices against thresholds with various operators +/// - **Outcome Determination**: Determine market outcomes based on price conditions +/// - **Data Validation**: Validate oracle responses for reasonableness and safety +/// - **Format Conversion**: Convert between different price formats and precisions +/// +/// **Market Resolution:** +/// - **Condition Evaluation**: Evaluate market conditions against oracle data +/// - **Threshold Checking**: Check if prices meet specified threshold conditions +/// - **Boolean Outcomes**: Convert price comparisons to yes/no market outcomes +/// - **Error Handling**: Robust error handling for invalid comparisons or data +/// +/// # Supported Comparisons +/// +/// The utilities support various comparison operators: +/// - **Greater Than ("gt")**: Price > threshold +/// - **Less Than ("lt")**: Price < threshold +/// - **Equal To ("eq")**: Price == threshold +/// - **Greater or Equal ("gte")**: Price >= threshold (if implemented) +/// - **Less or Equal ("lte")**: Price <= threshold (if implemented) +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::oracles::OracleUtils; +/// # let env = Env::default(); +/// +/// // Compare BTC price against $50k threshold +/// let btc_price = 52_000_00; // $52,000 (8 decimal precision) +/// let threshold = 50_000_00; // $50,000 +/// +/// // Check if BTC is above $50k +/// let is_above_threshold = OracleUtils::compare_prices( +/// btc_price, +/// threshold, +/// &String::from_str(&env, "gt"), +/// &env +/// )?; +/// +/// assert!(is_above_threshold); // BTC is above $50k +/// +/// // Determine market outcome +/// let outcome = OracleUtils::determine_outcome( +/// btc_price, +/// threshold, +/// &String::from_str(&env, "gt"), +/// &env +/// )?; +/// +/// assert_eq!(outcome, String::from_str(&env, "yes")); +/// +/// // Validate oracle response +/// OracleUtils::validate_oracle_response(btc_price)?; +/// +/// println!("BTC ${} is above ${} threshold: {}", +/// btc_price / 100, threshold / 100, is_above_threshold); +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Price Format Standards +/// +/// Oracle prices follow these conventions: +/// - **Integer Representation**: No floating point arithmetic +/// - **8 Decimal Precision**: Prices multiplied by 100,000,000 +/// - **USD Denomination**: All prices in US Dollar terms +/// - **Positive Values**: Always positive integers +/// +/// Examples: +/// - $1.00 = 100 (2 decimal precision) +/// - $1.00 = 100_000_000 (8 decimal precision) +/// - $50,000.00 = 50_000_00 (2 decimal precision) +/// - $50,000.00 = 5_000_000_000_000 (8 decimal precision) +/// +/// # Validation Rules +/// +/// Oracle response validation includes: +/// - **Positive Prices**: Prices must be greater than zero +/// - **Reasonable Range**: Prices between $0.01 and $1,000,000 +/// - **Precision Limits**: Prices within acceptable precision bounds +/// - **Overflow Protection**: Prevent integer overflow in calculations +/// +/// # Market Resolution Logic +/// +/// Market outcomes are determined as follows: +/// 1. **Get Oracle Price**: Retrieve current price from oracle +/// 2. **Compare with Threshold**: Apply comparison operator +/// 3. **Determine Outcome**: Convert boolean result to "yes"/"no" +/// 4. **Validate Result**: Ensure outcome is valid and reasonable +/// +/// # Error Scenarios +/// +/// Common error conditions: +/// - **Invalid Comparison**: Unsupported comparison operator +/// - **Invalid Threshold**: Threshold price out of reasonable range +/// - **Oracle Failure**: Oracle price unavailable or invalid +/// - **Calculation Error**: Mathematical operation failed +/// +/// # Integration with Markets +/// +/// Oracle Utils integrates with market resolution: +/// - **Automated Resolution**: Markets can auto-resolve based on oracle data +/// - **Condition Checking**: Verify market conditions are met +/// - **Outcome Generation**: Generate final market outcomes +/// - **Validation**: Ensure oracle data is suitable for market resolution pub struct OracleUtils; impl OracleUtils { diff --git a/contracts/predictify-hybrid/src/resolution.rs b/contracts/predictify-hybrid/src/resolution.rs index cc2b358f..222ea5ce 100644 --- a/contracts/predictify-hybrid/src/resolution.rs +++ b/contracts/predictify-hybrid/src/resolution.rs @@ -20,7 +20,86 @@ use crate::types::*; // ===== RESOLUTION TYPES ===== -/// Resolution state enumeration +/// Enumeration of possible resolution states for market lifecycle management. +/// +/// This enum tracks the progression of a market through its resolution phases, +/// from initial creation through final outcome determination. Each state represents +/// a specific stage in the resolution process with distinct validation rules and +/// available operations. +/// +/// # State Transitions +/// +/// The typical resolution flow follows this pattern: +/// ```text +/// Active → OracleResolved → MarketResolved → [Disputed] → Finalized +/// ``` +/// +/// **Alternative flows:** +/// - Direct admin resolution: `Active → MarketResolved → Finalized` +/// - Dispute flow: `MarketResolved → Disputed → Finalized` +/// - Oracle-only flow: `Active → OracleResolved → MarketResolved → Finalized` +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol}; +/// # use predictify_hybrid::resolution::{ResolutionState, ResolutionUtils}; +/// # use predictify_hybrid::markets::Market; +/// # let env = Env::default(); +/// # let market = Market::default(); // Placeholder +/// +/// // Check current resolution state +/// let current_state = ResolutionUtils::get_resolution_state(&env, &market); +/// +/// match current_state { +/// ResolutionState::Active => { +/// println!("Market is active, ready for oracle resolution"); +/// // Can fetch oracle results +/// }, +/// ResolutionState::OracleResolved => { +/// println!("Oracle result available, can proceed to market resolution"); +/// // Can combine with community consensus +/// }, +/// ResolutionState::MarketResolved => { +/// println!("Market resolved, awaiting finalization or disputes"); +/// // Can be disputed or finalized +/// }, +/// ResolutionState::Disputed => { +/// println!("Resolution is under dispute"); +/// // Dispute resolution process active +/// }, +/// ResolutionState::Finalized => { +/// println!("Resolution is final and immutable"); +/// // No further changes allowed +/// }, +/// } +/// ``` +/// +/// # State Validation +/// +/// Each state has specific validation requirements: +/// - **Active**: Market must be within voting period +/// - **OracleResolved**: Oracle data must be valid and recent +/// - **MarketResolved**: Final outcome must be determined +/// - **Disputed**: Dispute must be properly filed and active +/// - **Finalized**: Resolution must be complete and immutable +/// +/// # Business Rules +/// +/// State transitions enforce business logic: +/// - Markets cannot skip resolution states arbitrarily +/// - Finalized resolutions cannot be changed +/// - Disputed resolutions require proper dispute resolution +/// - Oracle resolution requires valid oracle data +/// +/// # Integration Points +/// +/// Resolution states integrate with: +/// - **Market Management**: Controls available market operations +/// - **Voting System**: Determines when voting periods end +/// - **Dispute System**: Manages dispute lifecycle +/// - **Oracle System**: Coordinates oracle data fetching +/// - **Admin Functions**: Enables administrative overrides #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[contracttype] pub enum ResolutionState { @@ -36,7 +115,111 @@ pub enum ResolutionState { Finalized, } -/// Oracle resolution result +/// Comprehensive oracle resolution result containing all data needed for market resolution. +/// +/// This structure captures the complete oracle response for a market, including +/// the raw price data, comparison logic, outcome determination, and metadata +/// necessary for validation and audit trails. +/// +/// # Core Components +/// +/// **Market Context:** +/// - **Market ID**: Unique identifier linking resolution to specific market +/// - **Timestamp**: When the oracle resolution was performed +/// - **Provider**: Which oracle service provided the data +/// +/// **Oracle Data:** +/// - **Price**: Current asset price from oracle feed +/// - **Threshold**: Market-defined price threshold for comparison +/// - **Comparison**: Comparison operator ("gt", "lt", "eq") +/// - **Feed ID**: Specific oracle feed identifier used +/// +/// **Resolution Result:** +/// - **Oracle Result**: Final outcome ("yes"/"no") based on price comparison +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, String, Address}; +/// # use predictify_hybrid::resolution::{OracleResolutionManager, OracleResolution}; +/// # use predictify_hybrid::types::OracleProvider; +/// # let env = Env::default(); +/// # let market_id = Symbol::new(&env, "btc_50k"); +/// # let oracle_contract = Address::generate(&env); +/// +/// // Fetch oracle resolution for a market +/// let oracle_resolution = OracleResolutionManager::fetch_oracle_result( +/// &env, +/// &market_id, +/// &oracle_contract +/// )?; +/// +/// // Examine oracle resolution details +/// println!("Market: {}", oracle_resolution.market_id); +/// println!("Oracle result: {}", oracle_resolution.oracle_result); +/// println!("Price: ${}", oracle_resolution.price / 100); +/// println!("Threshold: ${}", oracle_resolution.threshold / 100); +/// println!("Comparison: {}", oracle_resolution.comparison); +/// println!("Provider: {:?}", oracle_resolution.provider); +/// println!("Feed: {}", oracle_resolution.feed_id); +/// +/// // Validate oracle resolution +/// OracleResolutionManager::validate_oracle_resolution(&env, &oracle_resolution)?; +/// +/// // Calculate confidence score +/// let confidence = OracleResolutionManager::calculate_oracle_confidence(&oracle_resolution); +/// println!("Oracle confidence: {}%", confidence); +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Price Comparison Logic +/// +/// The oracle resolution evaluates market conditions: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::oracles::OracleUtils; +/// # let env = Env::default(); +/// +/// // Example: BTC above $50,000? +/// let btc_price = 52_000_00; // $52,000 (8 decimal precision) +/// let threshold = 50_000_00; // $50,000 +/// let comparison = String::from_str(&env, "gt"); // Greater than +/// +/// let outcome = OracleUtils::determine_outcome( +/// btc_price, +/// threshold, +/// &comparison, +/// &env +/// )?; +/// +/// assert_eq!(outcome, String::from_str(&env, "yes")); // BTC > $50k = "yes" +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Validation Requirements +/// +/// Oracle resolutions must meet criteria: +/// - **Valid Price**: Price must be positive and within reasonable bounds +/// - **Recent Data**: Timestamp must be within acceptable staleness limits +/// - **Supported Provider**: Oracle provider must be supported on current network +/// - **Valid Feed**: Feed ID must exist and be active +/// - **Proper Comparison**: Comparison operator must be supported +/// +/// # Integration with Market Resolution +/// +/// Oracle resolutions feed into broader market resolution: +/// - **Hybrid Resolution**: Combined with community consensus +/// - **Oracle-Only**: Used directly as final outcome +/// - **Dispute Input**: Provides data for dispute resolution +/// - **Confidence Scoring**: Contributes to overall resolution confidence +/// +/// # Audit and Transparency +/// +/// All oracle resolution data is preserved for: +/// - **Audit Trails**: Complete record of resolution process +/// - **Dispute Evidence**: Data available for dispute proceedings +/// - **Analytics**: Historical analysis of oracle performance +/// - **Transparency**: Public verification of resolution logic #[derive(Clone, Debug)] #[contracttype] pub struct OracleResolution { @@ -50,7 +233,121 @@ pub struct OracleResolution { pub feed_id: String, } -/// Market resolution result +/// Comprehensive market resolution result combining oracle data with community consensus. +/// +/// This structure represents the final resolution of a prediction market, incorporating +/// data from multiple sources (oracle feeds, community voting, admin decisions) to +/// determine the authoritative market outcome with confidence scoring and audit trails. +/// +/// # Resolution Components +/// +/// **Core Resolution Data:** +/// - **Market ID**: Unique identifier for the resolved market +/// - **Final Outcome**: Definitive market result ("yes"/"no" or custom outcomes) +/// - **Resolution Timestamp**: When the resolution was finalized +/// - **Resolution Method**: How the resolution was determined +/// +/// **Data Sources:** +/// - **Oracle Result**: Outcome from oracle price feeds +/// - **Community Consensus**: Aggregated community voting results +/// - **Confidence Score**: Statistical confidence in the resolution (0-100) +/// +/// # Resolution Methods +/// +/// Markets can be resolved through various methods: +/// - **Oracle Only**: Based purely on oracle price data +/// - **Community Only**: Based on community voting consensus +/// - **Hybrid**: Combines oracle data with community input +/// - **Admin Override**: Administrative decision overrides other methods +/// - **Dispute Resolution**: Outcome determined through dispute process +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, String}; +/// # use predictify_hybrid::resolution::{MarketResolutionManager, MarketResolution, ResolutionMethod}; +/// # let env = Env::default(); +/// # let market_id = Symbol::new(&env, "btc_prediction"); +/// +/// // Resolve a market using hybrid method +/// let resolution = MarketResolutionManager::resolve_market(&env, &market_id)?; +/// +/// // Examine resolution details +/// println!("Market: {}", resolution.market_id); +/// println!("Final outcome: {}", resolution.final_outcome); +/// println!("Oracle result: {}", resolution.oracle_result); +/// println!("Community consensus: {}% ({})", +/// resolution.community_consensus.percentage, +/// resolution.community_consensus.outcome +/// ); +/// println!("Resolution method: {:?}", resolution.resolution_method); +/// println!("Confidence: {}%", resolution.confidence_score); +/// +/// // Validate the resolution +/// MarketResolutionManager::validate_market_resolution(&env, &resolution)?; +/// +/// // Check resolution method +/// match resolution.resolution_method { +/// ResolutionMethod::Hybrid => { +/// println!("Resolution combines oracle and community data"); +/// }, +/// ResolutionMethod::OracleOnly => { +/// println!("Resolution based purely on oracle data"); +/// }, +/// ResolutionMethod::AdminOverride => { +/// println!("Resolution was administratively determined"); +/// }, +/// _ => println!("Other resolution method used"), +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Confidence Scoring +/// +/// Resolution confidence is calculated based on: +/// - **Oracle Reliability**: Historical oracle accuracy and freshness +/// - **Community Agreement**: Level of consensus in community voting +/// - **Data Quality**: Quality and recency of underlying data +/// - **Method Reliability**: Inherent reliability of resolution method +/// +/// ```rust +/// # use predictify_hybrid::resolution::MarketResolution; +/// # let resolution = MarketResolution::default(); // Placeholder +/// +/// // Interpret confidence scores +/// match resolution.confidence_score { +/// 90..=100 => println!("Very high confidence resolution"), +/// 80..=89 => println!("High confidence resolution"), +/// 70..=79 => println!("Moderate confidence resolution"), +/// 60..=69 => println!("Low confidence resolution"), +/// _ => println!("Very low confidence - may need review"), +/// } +/// ``` +/// +/// # Resolution Validation +/// +/// Market resolutions undergo validation to ensure: +/// - **Outcome Consistency**: Oracle and community data alignment +/// - **Method Appropriateness**: Resolution method suitable for market type +/// - **Data Quality**: All input data meets quality standards +/// - **Timestamp Validity**: Resolution timing is appropriate +/// - **Confidence Thresholds**: Confidence score meets minimum requirements +/// +/// # Integration Points +/// +/// Market resolutions integrate with: +/// - **Payout System**: Determines winner payouts and distributions +/// - **Dispute System**: Can be challenged through dispute mechanisms +/// - **Analytics**: Contributes to platform performance metrics +/// - **Audit System**: Provides complete resolution audit trails +/// - **Event System**: Triggers resolution events for transparency +/// +/// # Immutability and Finalization +/// +/// Once finalized, market resolutions are immutable except through: +/// - **Dispute Process**: Formal dispute resolution procedures +/// - **Admin Override**: Emergency administrative corrections +/// - **System Upgrades**: Protocol-level corrections (rare) #[derive(Clone, Debug)] #[contracttype] pub struct MarketResolution { @@ -63,7 +360,135 @@ pub struct MarketResolution { pub confidence_score: u32, } -/// Resolution method enumeration +/// Enumeration of available market resolution methods and their characteristics. +/// +/// This enum defines the different approaches available for resolving prediction markets, +/// each with distinct data sources, validation requirements, and confidence characteristics. +/// The choice of resolution method depends on market type, data availability, and +/// community participation levels. +/// +/// # Resolution Method Types +/// +/// **Automated Methods:** +/// - **Oracle Only**: Purely algorithmic based on price feed data +/// - **Community Only**: Based entirely on community voting consensus +/// - **Hybrid**: Combines oracle data with community input for balanced resolution +/// +/// **Manual Methods:** +/// - **Admin Override**: Administrative decision for exceptional circumstances +/// - **Dispute Resolution**: Outcome determined through formal dispute process +/// +/// # Method Selection Logic +/// +/// Resolution methods are typically selected based on: +/// ```rust +/// # use predictify_hybrid::resolution::ResolutionMethod; +/// # use predictify_hybrid::markets::CommunityConsensus; +/// # use soroban_sdk::{Env, String}; +/// # let env = Env::default(); +/// +/// // Example method selection logic +/// fn select_resolution_method( +/// oracle_available: bool, +/// community_participation: u32, +/// consensus_strength: u32 +/// ) -> ResolutionMethod { +/// match (oracle_available, community_participation, consensus_strength) { +/// (true, participation, consensus) if participation > 50 && consensus > 75 => { +/// ResolutionMethod::Hybrid // Strong community + oracle +/// }, +/// (true, participation, _) if participation < 30 => { +/// ResolutionMethod::OracleOnly // Low community participation +/// }, +/// (false, participation, consensus) if participation > 100 && consensus > 80 => { +/// ResolutionMethod::CommunityOnly // No oracle, strong community +/// }, +/// _ => ResolutionMethod::AdminOverride // Fallback to admin +/// } +/// } +/// ``` +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::resolution::{ResolutionMethod, MarketResolutionAnalytics}; +/// # use predictify_hybrid::markets::CommunityConsensus; +/// # let env = Env::default(); +/// +/// // Determine resolution method based on available data +/// let oracle_result = String::from_str(&env, "yes"); +/// let community_consensus = CommunityConsensus { +/// outcome: String::from_str(&env, "yes"), +/// votes: 150, +/// total_votes: 200, +/// percentage: 75, +/// }; +/// +/// let method = MarketResolutionAnalytics::determine_resolution_method( +/// &oracle_result, +/// &community_consensus +/// ); +/// +/// match method { +/// ResolutionMethod::Hybrid => { +/// println!("Using hybrid resolution - oracle and community agree"); +/// }, +/// ResolutionMethod::OracleOnly => { +/// println!("Using oracle-only resolution - low community participation"); +/// }, +/// ResolutionMethod::CommunityOnly => { +/// println!("Using community-only resolution - oracle unavailable"); +/// }, +/// ResolutionMethod::AdminOverride => { +/// println!("Using admin override - exceptional circumstances"); +/// }, +/// ResolutionMethod::DisputeResolution => { +/// println!("Using dispute resolution - conflicting data sources"); +/// }, +/// } +/// ``` +/// +/// # Method Characteristics +/// +/// **Oracle Only:** +/// - **Speed**: Fastest resolution method +/// - **Objectivity**: Purely algorithmic, no human bias +/// - **Reliability**: Depends on oracle data quality +/// - **Use Case**: Clear-cut price-based markets +/// +/// **Community Only:** +/// - **Participation**: Requires active community engagement +/// - **Flexibility**: Can handle subjective or complex outcomes +/// - **Consensus**: Relies on community agreement +/// - **Use Case**: Subjective or oracle-unavailable markets +/// +/// **Hybrid:** +/// - **Balance**: Combines objective data with community wisdom +/// - **Validation**: Cross-validates oracle data with community input +/// - **Confidence**: Generally highest confidence scores +/// - **Use Case**: Most standard prediction markets +/// +/// **Admin Override:** +/// - **Authority**: Administrative decision with full authority +/// - **Speed**: Can be immediate when needed +/// - **Responsibility**: Requires admin accountability +/// - **Use Case**: Emergency situations or system failures +/// +/// **Dispute Resolution:** +/// - **Process**: Formal dispute resolution procedures +/// - **Thoroughness**: Most comprehensive review process +/// - **Time**: Longest resolution time +/// - **Use Case**: Contested or controversial outcomes +/// +/// # Integration with Confidence Scoring +/// +/// Different methods contribute to confidence scores: +/// - **Hybrid**: Highest confidence when oracle and community agree +/// - **Oracle Only**: High confidence for clear price-based outcomes +/// - **Community Only**: Confidence based on participation and consensus +/// - **Admin Override**: Confidence based on admin justification +/// - **Dispute Resolution**: Confidence based on dispute outcome strength #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[contracttype] pub enum ResolutionMethod { @@ -79,7 +504,120 @@ pub enum ResolutionMethod { DisputeResolution, } -/// Resolution analytics +/// Comprehensive analytics and metrics for resolution system performance. +/// +/// This structure tracks detailed statistics about the resolution system's +/// performance, method usage, timing characteristics, and outcome distributions. +/// It provides essential data for system optimization, transparency reporting, +/// and platform analytics. +/// +/// # Analytics Categories +/// +/// **Volume Metrics:** +/// - **Total Resolutions**: Overall count of resolved markets +/// - **Method Breakdown**: Count by resolution method type +/// - **Outcome Distribution**: Frequency of different outcomes +/// +/// **Quality Metrics:** +/// - **Average Confidence**: Mean confidence score across resolutions +/// - **Resolution Times**: Time taken for different resolution methods +/// - **Success Rates**: Percentage of successful resolutions by method +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Map, String, Vec}; +/// # use predictify_hybrid::resolution::{ResolutionAnalytics, ResolutionAnalyticsManager}; +/// # let env = Env::default(); +/// +/// // Get current resolution analytics +/// let analytics = ResolutionAnalyticsManager::get_resolution_analytics(&env)?; +/// +/// // Display system performance metrics +/// println!("=== Resolution System Analytics ==="); +/// println!("Total resolutions: {}", analytics.total_resolutions); +/// println!("Oracle resolutions: {}", analytics.oracle_resolutions); +/// println!("Community resolutions: {}", analytics.community_resolutions); +/// println!("Hybrid resolutions: {}", analytics.hybrid_resolutions); +/// println!("Average confidence: {}%", analytics.average_confidence / 100); +/// +/// // Calculate method distribution +/// let total = analytics.total_resolutions as f64; +/// if total > 0.0 { +/// println!("Oracle-only: {:.1}%", (analytics.oracle_resolutions as f64 / total) * 100.0); +/// println!("Community-only: {:.1}%", (analytics.community_resolutions as f64 / total) * 100.0); +/// println!("Hybrid: {:.1}%", (analytics.hybrid_resolutions as f64 / total) * 100.0); +/// } +/// +/// // Analyze resolution times +/// if !analytics.resolution_times.is_empty() { +/// let avg_time = analytics.resolution_times.iter().sum::() / analytics.resolution_times.len() as u64; +/// println!("Average resolution time: {} seconds", avg_time); +/// } +/// +/// // Display outcome distribution +/// for (outcome, count) in analytics.outcome_distribution.iter() { +/// println!("Outcome '{}': {} markets", outcome, count); +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Performance Monitoring +/// +/// Analytics enable monitoring of: +/// ```rust +/// # use predictify_hybrid::resolution::ResolutionAnalytics; +/// # let analytics = ResolutionAnalytics::default(); +/// +/// // Monitor system health +/// fn assess_system_health(analytics: &ResolutionAnalytics) -> String { +/// let confidence_threshold = 80_00; // 80% in basis points +/// let hybrid_ratio = if analytics.total_resolutions > 0 { +/// (analytics.hybrid_resolutions as f64 / analytics.total_resolutions as f64) * 100.0 +/// } else { +/// 0.0 +/// }; +/// +/// match (analytics.average_confidence >= confidence_threshold, hybrid_ratio >= 50.0) { +/// (true, true) => "Excellent - High confidence and balanced resolution methods".to_string(), +/// (true, false) => "Good - High confidence but method imbalance".to_string(), +/// (false, true) => "Fair - Balanced methods but lower confidence".to_string(), +/// (false, false) => "Needs attention - Low confidence and method imbalance".to_string(), +/// } +/// } +/// ``` +/// +/// # Trend Analysis +/// +/// Resolution analytics support trend analysis: +/// - **Method Evolution**: How resolution method preferences change over time +/// - **Confidence Trends**: Whether resolution confidence is improving +/// - **Outcome Patterns**: Distribution of market outcomes +/// - **Performance Optimization**: Identifying areas for system improvement +/// +/// # Business Intelligence +/// +/// Analytics provide insights for: +/// - **Platform Performance**: Overall system effectiveness metrics +/// - **User Behavior**: How community participates in resolution +/// - **Oracle Reliability**: Performance of different oracle providers +/// - **Market Types**: Which market types work best with which methods +/// +/// # Data Privacy and Aggregation +/// +/// Analytics maintain privacy through: +/// - **Aggregated Data**: No individual user information exposed +/// - **Statistical Summaries**: Focus on system-level metrics +/// - **Time-based Aggregation**: Historical trends without personal data +/// - **Public Transparency**: Safe for public consumption +/// +/// # Integration with Reporting +/// +/// Resolution analytics integrate with: +/// - **Dashboard Systems**: Real-time performance monitoring +/// - **Audit Reports**: Compliance and transparency reporting +/// - **API Endpoints**: External system integration +/// - **Governance Metrics**: DAO governance decision support #[derive(Clone, Debug)] #[contracttype] pub struct ResolutionAnalytics { @@ -92,7 +630,156 @@ pub struct ResolutionAnalytics { pub outcome_distribution: Map, } -/// Resolution validation result +/// Comprehensive validation result for resolution processes and outcomes. +/// +/// This structure provides detailed feedback on the validity of resolution attempts, +/// including validation status, specific error conditions, warnings about potential +/// issues, and recommendations for improvement. It serves as a comprehensive +/// diagnostic tool for resolution quality assurance. +/// +/// # Validation Components +/// +/// **Status Indicators:** +/// - **Is Valid**: Boolean indicating overall validation success +/// - **Errors**: Critical issues that prevent resolution +/// - **Warnings**: Non-critical issues that should be addressed +/// - **Recommendations**: Suggestions for improving resolution quality +/// +/// # Validation Categories +/// +/// **Data Quality Validation:** +/// - Oracle data freshness and accuracy +/// - Community voting participation levels +/// - Consensus strength and distribution +/// - Timestamp validity and sequencing +/// +/// **Business Logic Validation:** +/// - Market state compatibility with resolution method +/// - Outcome consistency across data sources +/// - Confidence score reasonableness +/// - Resolution method appropriateness +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Vec, String}; +/// # use predictify_hybrid::resolution::{ResolutionValidation, MarketResolutionManager, MarketResolution}; +/// # let env = Env::default(); +/// # let resolution = MarketResolution::default(); // Placeholder +/// +/// // Validate a market resolution +/// let validation = MarketResolutionManager::validate_market_resolution(&env, &resolution)?; +/// +/// if validation.is_valid { +/// println!("✅ Resolution is valid and ready for finalization"); +/// +/// // Check for warnings +/// if !validation.warnings.is_empty() { +/// println!("⚠️ Warnings to consider:"); +/// for warning in validation.warnings.iter() { +/// println!(" - {}", warning); +/// } +/// } +/// +/// // Review recommendations +/// if !validation.recommendations.is_empty() { +/// println!("💡 Recommendations for improvement:"); +/// for recommendation in validation.recommendations.iter() { +/// println!(" - {}", recommendation); +/// } +/// } +/// } else { +/// println!("❌ Resolution validation failed"); +/// println!("Errors that must be resolved:"); +/// for error in validation.errors.iter() { +/// println!(" - {}", error); +/// } +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Validation Workflow +/// +/// ```rust +/// # use predictify_hybrid::resolution::{ResolutionValidation, OracleResolution}; +/// # use soroban_sdk::{Env, Vec, String}; +/// # let env = Env::default(); +/// +/// // Example validation workflow +/// fn comprehensive_validation_workflow( +/// env: &Env, +/// oracle_resolution: &OracleResolution +/// ) -> Result { +/// // Step 1: Validate oracle resolution +/// let oracle_validation = validate_oracle_data(env, oracle_resolution)?; +/// +/// if !oracle_validation.is_valid { +/// println!("Oracle validation failed: {:?}", oracle_validation.errors); +/// return Ok(false); +/// } +/// +/// // Step 2: Check for warnings +/// if !oracle_validation.warnings.is_empty() { +/// println!("Oracle warnings: {:?}", oracle_validation.warnings); +/// } +/// +/// // Step 3: Apply recommendations if possible +/// for recommendation in oracle_validation.recommendations.iter() { +/// println!("Consider: {}", recommendation); +/// } +/// +/// Ok(true) +/// } +/// +/// fn validate_oracle_data( +/// _env: &Env, +/// _oracle_resolution: &OracleResolution +/// ) -> Result { +/// // Placeholder implementation +/// Ok(ResolutionValidation { +/// is_valid: true, +/// errors: Vec::new(_env), +/// warnings: Vec::new(_env), +/// recommendations: Vec::new(_env), +/// }) +/// } +/// ``` +/// +/// # Error Categories +/// +/// **Critical Errors (Block Resolution):** +/// - Invalid oracle data or stale timestamps +/// - Insufficient community participation +/// - Conflicting outcomes without resolution method +/// - Missing required data for chosen resolution method +/// +/// **Warnings (Proceed with Caution):** +/// - Low confidence scores +/// - Minimal community participation +/// - Oracle data approaching staleness limits +/// - Unusual outcome patterns +/// +/// **Recommendations (Optimization):** +/// - Increase community engagement +/// - Use hybrid resolution for better confidence +/// - Consider additional oracle sources +/// - Implement dispute period for controversial outcomes +/// +/// # Integration with Resolution Process +/// +/// Validation integrates at multiple points: +/// - **Pre-Resolution**: Validate readiness before attempting resolution +/// - **Post-Resolution**: Validate outcome quality and consistency +/// - **Dispute Handling**: Validate dispute claims and evidence +/// - **Finalization**: Final validation before immutable storage +/// +/// # Quality Assurance +/// +/// Validation supports quality assurance through: +/// - **Automated Checks**: Systematic validation of all resolution components +/// - **Consistency Verification**: Cross-validation between data sources +/// - **Business Rule Enforcement**: Ensure compliance with platform rules +/// - **Audit Trail Generation**: Document validation decisions and rationale #[derive(Clone, Debug)] #[contracttype] pub struct ResolutionValidation { @@ -104,7 +791,155 @@ pub struct ResolutionValidation { // ===== ORACLE RESOLUTION ===== -/// Oracle resolution management +/// Comprehensive oracle resolution management system for prediction markets. +/// +/// The Oracle Resolution Manager handles all aspects of oracle-based market resolution, +/// including fetching oracle data, validating oracle responses, calculating confidence +/// scores, and managing the oracle resolution lifecycle. It serves as the primary +/// interface between the prediction market system and external oracle providers. +/// +/// # Core Responsibilities +/// +/// **Oracle Data Management:** +/// - **Data Fetching**: Retrieve price data from configured oracle providers +/// - **Data Validation**: Ensure oracle responses meet quality standards +/// - **Confidence Scoring**: Calculate reliability scores for oracle data +/// - **Error Handling**: Manage oracle failures and fallback strategies +/// +/// **Market Integration:** +/// - **Market Validation**: Ensure markets are ready for oracle resolution +/// - **Outcome Determination**: Convert oracle data to market outcomes +/// - **Resolution Storage**: Persist oracle resolution results +/// - **Event Emission**: Notify system of oracle resolution events +/// +/// # Oracle Resolution Process +/// +/// The typical oracle resolution workflow: +/// ```text +/// 1. Validate Market → 2. Fetch Oracle Data → 3. Validate Response → +/// 4. Calculate Outcome → 5. Score Confidence → 6. Store Resolution +/// ``` +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, Address}; +/// # use predictify_hybrid::resolution::{OracleResolutionManager, OracleResolution}; +/// # let env = Env::default(); +/// # let market_id = Symbol::new(&env, "btc_50k_market"); +/// # let oracle_contract = Address::generate(&env); +/// +/// // Fetch oracle resolution for a market +/// let oracle_resolution = OracleResolutionManager::fetch_oracle_result( +/// &env, +/// &market_id, +/// &oracle_contract +/// )?; +/// +/// println!("Oracle Resolution Results:"); +/// println!("Market: {}", oracle_resolution.market_id); +/// println!("Result: {}", oracle_resolution.oracle_result); +/// println!("Price: ${}", oracle_resolution.price / 100); +/// println!("Threshold: ${}", oracle_resolution.threshold / 100); +/// println!("Provider: {:?}", oracle_resolution.provider); +/// +/// // Validate the oracle resolution +/// OracleResolutionManager::validate_oracle_resolution(&env, &oracle_resolution)?; +/// +/// // Calculate confidence score +/// let confidence = OracleResolutionManager::calculate_oracle_confidence(&oracle_resolution); +/// println!("Oracle confidence: {}%", confidence); +/// +/// // Store resolution for later retrieval +/// // (Implementation would store in contract storage) +/// +/// // Retrieve stored resolution +/// if let Some(stored_resolution) = OracleResolutionManager::get_oracle_resolution( +/// &env, +/// &market_id +/// )? { +/// println!("Successfully retrieved stored oracle resolution"); +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Oracle Provider Integration +/// +/// The manager integrates with multiple oracle providers: +/// ```rust +/// # use soroban_sdk::{Env, Address}; +/// # use predictify_hybrid::oracles::{OracleFactory, OracleInstance}; +/// # use predictify_hybrid::types::OracleProvider; +/// # let env = Env::default(); +/// # let oracle_contract = Address::generate(&env); +/// +/// // Create oracle instance based on provider +/// let oracle = OracleFactory::create_oracle( +/// OracleProvider::Reflector, // Primary provider for Stellar +/// oracle_contract +/// )?; +/// +/// // Use oracle for price fetching +/// match oracle { +/// OracleInstance::Reflector(reflector_oracle) => { +/// println!("Using Reflector oracle for price data"); +/// // Reflector-specific operations +/// }, +/// OracleInstance::Pyth(pyth_oracle) => { +/// println!("Using Pyth oracle (future implementation)"); +/// // Pyth-specific operations +/// }, +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Confidence Scoring Algorithm +/// +/// Oracle confidence is calculated based on: +/// - **Data Freshness**: How recent the oracle data is +/// - **Provider Reliability**: Historical accuracy of the oracle provider +/// - **Price Stability**: Volatility and consistency of price data +/// - **Network Health**: Oracle network status and availability +/// +/// ```rust +/// # use predictify_hybrid::resolution::{OracleResolution, OracleResolutionManager}; +/// # let oracle_resolution = OracleResolution::default(); // Placeholder +/// +/// // Confidence scoring factors +/// let confidence = OracleResolutionManager::calculate_oracle_confidence(&oracle_resolution); +/// +/// match confidence { +/// 90..=100 => println!("Very high confidence - excellent oracle data"), +/// 80..=89 => println!("High confidence - reliable oracle data"), +/// 70..=79 => println!("Moderate confidence - acceptable oracle data"), +/// 60..=69 => println!("Low confidence - oracle data has issues"), +/// _ => println!("Very low confidence - oracle data unreliable"), +/// } +/// ``` +/// +/// # Error Handling and Fallbacks +/// +/// The manager handles various error scenarios: +/// - **Oracle Unavailable**: Network issues or service downtime +/// - **Invalid Data**: Malformed or unreasonable oracle responses +/// - **Stale Data**: Oracle data older than acceptable thresholds +/// - **Feed Errors**: Requested price feed not available +/// +/// # Integration with Market Resolution +/// +/// Oracle resolutions feed into broader market resolution: +/// - **Hybrid Resolution**: Combined with community consensus +/// - **Oracle-Only Markets**: Direct outcome determination +/// - **Dispute Evidence**: Oracle data used in dispute resolution +/// - **Confidence Weighting**: Oracle confidence affects final resolution confidence +/// +/// # Performance and Optimization +/// +/// The manager optimizes performance through: +/// - **Caching**: Cache oracle responses to reduce network calls +/// - **Batch Processing**: Handle multiple markets efficiently +/// - **Async Operations**: Non-blocking oracle data fetching +/// - **Fallback Strategies**: Multiple oracle providers for reliability pub struct OracleResolutionManager; impl OracleResolutionManager { @@ -198,7 +1033,184 @@ impl OracleResolutionManager { // ===== MARKET RESOLUTION ===== -/// Market resolution management +/// Comprehensive market resolution management system combining multiple data sources. +/// +/// The Market Resolution Manager orchestrates the complete market resolution process, +/// integrating oracle data, community consensus, admin decisions, and dispute outcomes +/// to determine final market results. It serves as the central coordinator for all +/// resolution methods and ensures consistent, reliable market outcomes. +/// +/// # Core Responsibilities +/// +/// **Resolution Orchestration:** +/// - **Multi-Source Integration**: Combine oracle, community, and admin data +/// - **Method Selection**: Choose appropriate resolution method based on available data +/// - **Confidence Calculation**: Determine overall confidence in resolution outcome +/// - **Validation**: Ensure resolution meets quality and consistency standards +/// +/// **Market Lifecycle Management:** +/// - **Resolution Triggering**: Initiate resolution when markets are ready +/// - **State Management**: Track resolution progress through various states +/// - **Finalization**: Complete resolution process and make outcomes immutable +/// - **Event Emission**: Notify system components of resolution events +/// +/// # Resolution Methods Supported +/// +/// **Hybrid Resolution (Recommended):** +/// - Combines oracle price data with community voting +/// - Highest confidence when sources agree +/// - Fallback logic when sources disagree +/// +/// **Oracle-Only Resolution:** +/// - Pure algorithmic resolution based on price feeds +/// - Fast and objective for clear-cut price-based markets +/// - Used when community participation is insufficient +/// +/// **Community-Only Resolution:** +/// - Based entirely on community voting consensus +/// - Used when oracle data is unavailable or inappropriate +/// - Requires sufficient participation and consensus +/// +/// **Admin Override:** +/// - Administrative decision for exceptional circumstances +/// - Used for emergency situations or system failures +/// - Requires proper admin authentication and justification +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Symbol, Address, String}; +/// # use predictify_hybrid::resolution::{MarketResolutionManager, MarketResolution, ResolutionMethod}; +/// # let env = Env::default(); +/// # let market_id = Symbol::new(&env, "btc_prediction_market"); +/// # let admin = Address::generate(&env); +/// +/// // Resolve a market using hybrid method (oracle + community) +/// let resolution = MarketResolutionManager::resolve_market(&env, &market_id)?; +/// +/// println!("Market Resolution Complete:"); +/// println!("Market: {}", resolution.market_id); +/// println!("Final outcome: {}", resolution.final_outcome); +/// println!("Method: {:?}", resolution.resolution_method); +/// println!("Confidence: {}%", resolution.confidence_score); +/// +/// // Display resolution details +/// match resolution.resolution_method { +/// ResolutionMethod::Hybrid => { +/// println!("Oracle result: {}", resolution.oracle_result); +/// println!("Community consensus: {}% ({})", +/// resolution.community_consensus.percentage, +/// resolution.community_consensus.outcome +/// ); +/// }, +/// ResolutionMethod::OracleOnly => { +/// println!("Resolved purely based on oracle: {}", resolution.oracle_result); +/// }, +/// ResolutionMethod::AdminOverride => { +/// println!("Administrative override resolution"); +/// }, +/// _ => println!("Other resolution method used"), +/// } +/// +/// // Validate the resolution +/// MarketResolutionManager::validate_market_resolution(&env, &resolution)?; +/// +/// // Admin can finalize with override if needed +/// if resolution.confidence_score < 70 { +/// let admin_resolution = MarketResolutionManager::finalize_market( +/// &env, +/// &admin, +/// &market_id, +/// &String::from_str(&env, "yes") +/// )?; +/// println!("Admin finalized with outcome: {}", admin_resolution.final_outcome); +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Resolution Decision Logic +/// +/// The manager uses sophisticated logic to determine final outcomes: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::resolution::ResolutionMethod; +/// # use predictify_hybrid::markets::CommunityConsensus; +/// # let env = Env::default(); +/// +/// // Example resolution decision logic +/// fn determine_final_outcome( +/// oracle_result: &String, +/// community_consensus: &CommunityConsensus, +/// oracle_confidence: u32, +/// community_confidence: u32 +/// ) -> (String, ResolutionMethod) { +/// let env = Env::default(); +/// +/// // Check if oracle and community agree +/// if oracle_result == &community_consensus.outcome { +/// // Agreement - use hybrid method with high confidence +/// (oracle_result.clone(), ResolutionMethod::Hybrid) +/// } else if oracle_confidence > 85 && community_confidence < 60 { +/// // Strong oracle, weak community - use oracle +/// (oracle_result.clone(), ResolutionMethod::OracleOnly) +/// } else if community_confidence > 85 && oracle_confidence < 60 { +/// // Strong community, weak oracle - use community +/// (community_consensus.outcome.clone(), ResolutionMethod::CommunityOnly) +/// } else { +/// // Conflict requires admin intervention +/// (String::from_str(&env, "disputed"), ResolutionMethod::AdminOverride) +/// } +/// } +/// ``` +/// +/// # Confidence Scoring +/// +/// Resolution confidence is calculated from multiple factors: +/// - **Oracle Confidence**: Quality and freshness of oracle data +/// - **Community Confidence**: Participation level and consensus strength +/// - **Method Reliability**: Inherent reliability of chosen resolution method +/// - **Data Consistency**: Agreement between different data sources +/// +/// ```rust +/// # use predictify_hybrid::resolution::MarketResolution; +/// # let resolution = MarketResolution::default(); // Placeholder +/// +/// // Interpret confidence levels +/// match resolution.confidence_score { +/// 95..=100 => println!("Extremely high confidence - virtually certain outcome"), +/// 85..=94 => println!("Very high confidence - strong evidence for outcome"), +/// 75..=84 => println!("High confidence - good evidence for outcome"), +/// 65..=74 => println!("Moderate confidence - reasonable evidence"), +/// 50..=64 => println!("Low confidence - weak evidence, consider review"), +/// _ => println!("Very low confidence - outcome uncertain, needs attention"), +/// } +/// ``` +/// +/// # Error Handling and Fallbacks +/// +/// The manager handles various failure scenarios: +/// - **Oracle Failures**: Fallback to community-only resolution +/// - **Low Participation**: Fallback to oracle-only or admin resolution +/// - **Data Conflicts**: Escalate to dispute resolution process +/// - **System Errors**: Graceful degradation with error reporting +/// +/// # Integration with Other Systems +/// +/// Market Resolution Manager integrates with: +/// - **Oracle System**: Fetches and validates oracle data +/// - **Voting System**: Retrieves community consensus data +/// - **Dispute System**: Handles disputed resolutions +/// - **Admin System**: Processes administrative overrides +/// - **Event System**: Emits resolution events for transparency +/// - **Analytics System**: Records resolution metrics and performance +/// +/// # Performance and Scalability +/// +/// The manager optimizes for: +/// - **Batch Processing**: Resolve multiple markets efficiently +/// - **Parallel Resolution**: Handle independent resolutions concurrently +/// - **Caching**: Cache resolution data to avoid redundant calculations +/// - **Event-Driven**: React to market state changes automatically pub struct MarketResolutionManager; impl MarketResolutionManager { diff --git a/contracts/predictify-hybrid/src/types.rs b/contracts/predictify-hybrid/src/types.rs index 7c21bd5f..6ad2f578 100644 --- a/contracts/predictify-hybrid/src/types.rs +++ b/contracts/predictify-hybrid/src/types.rs @@ -4,7 +4,124 @@ use soroban_sdk::{contracttype, Address, Env, Map, String, Symbol, Vec}; // ===== MARKET STATE ===== -/// Market state enumeration +/// Enumeration of possible market states throughout the prediction market lifecycle. +/// +/// This enum defines the various states a prediction market can be in, from initial +/// creation through final resolution and closure. Each state represents a distinct +/// phase with specific business rules, available operations, and state transition +/// requirements. +/// +/// # State Lifecycle +/// +/// The typical market progression follows this pattern: +/// ```text +/// Active → Ended → [Disputed] → Resolved → Closed +/// ``` +/// +/// **Alternative flows:** +/// - **Cancellation**: `Active → Cancelled` (emergency situations) +/// - **Direct Resolution**: `Active → Resolved` (admin override) +/// - **Dispute Flow**: `Ended → Disputed → Resolved` +/// +/// # State Descriptions +/// +/// **Active**: Market is live and accepting user participation +/// - Users can place votes and stakes +/// - Market question and outcomes are fixed +/// - Oracle configuration is immutable +/// - Voting period is ongoing +/// +/// **Ended**: Market voting period has concluded +/// - No new votes or stakes accepted +/// - Oracle resolution can be triggered +/// - Community consensus can be calculated +/// - Dispute period may be active +/// +/// **Disputed**: Market resolution is under dispute +/// - Formal dispute process is active +/// - Additional evidence may be collected +/// - Dispute resolution mechanisms engaged +/// - Final outcome pending dispute resolution +/// +/// **Resolved**: Market outcome has been determined +/// - Final outcome is established +/// - Payouts can be calculated and distributed +/// - Resolution method and confidence recorded +/// - Market moves toward closure +/// +/// **Closed**: Market is permanently closed +/// - All payouts have been distributed +/// - No further operations allowed +/// - Market data preserved for historical analysis +/// - Final state for completed markets +/// +/// **Cancelled**: Market has been cancelled +/// - Emergency cancellation due to issues +/// - Stakes returned to participants +/// - No winner determination +/// - Administrative action required +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::types::{MarketState, Market}; +/// # let env = Env::default(); +/// # let market = Market::default(); // Placeholder +/// # let current_time = env.ledger().timestamp(); +/// +/// // Check market state and determine available operations +/// match market.state { +/// MarketState::Active => { +/// if market.is_active(current_time) { +/// println!("Market is active - users can vote"); +/// // Allow voting operations +/// } else { +/// println!("Market should transition to Ended state"); +/// } +/// }, +/// MarketState::Ended => { +/// println!("Market ended - ready for resolution"); +/// // Trigger oracle resolution or community consensus +/// }, +/// MarketState::Disputed => { +/// println!("Market under dispute - awaiting resolution"); +/// // Handle dispute process +/// }, +/// MarketState::Resolved => { +/// println!("Market resolved - calculating payouts"); +/// // Process winner payouts +/// }, +/// MarketState::Closed => { +/// println!("Market closed - no further operations"); +/// // Read-only access for historical data +/// }, +/// MarketState::Cancelled => { +/// println!("Market cancelled - refunding stakes"); +/// // Process stake refunds +/// }, +/// } +/// ``` +/// +/// # State Validation Rules +/// +/// Each state has specific validation requirements: +/// - **Active**: Must have valid end time, oracle config, and outcomes +/// - **Ended**: Current time must be past market end time +/// - **Disputed**: Must have active disputes filed within dispute period +/// - **Resolved**: Must have valid resolution with outcome and method +/// - **Closed**: All payouts must be completed and verified +/// - **Cancelled**: Must have valid cancellation reason and admin authorization +/// +/// # Integration Points +/// +/// Market states integrate with: +/// - **Voting System**: Controls when votes can be accepted +/// - **Oracle System**: Determines when oracle resolution can occur +/// - **Dispute System**: Manages dispute lifecycle and resolution +/// - **Payout System**: Controls when payouts can be distributed +/// - **Admin System**: Handles state transitions and overrides +/// - **Event System**: Emits state change events for transparency #[contracttype] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum MarketState { @@ -24,7 +141,136 @@ pub enum MarketState { // ===== ORACLE TYPES ===== -/// Oracle provider enumeration +/// Enumeration of supported oracle providers for price feed data. +/// +/// This enum defines the various oracle providers that can supply price data +/// for prediction market resolution. Each provider has different characteristics, +/// availability, and integration requirements specific to the Stellar blockchain +/// ecosystem. +/// +/// # Provider Categories +/// +/// **Production Ready (Stellar Network):** +/// - **Reflector**: Primary oracle provider with full Stellar integration +/// +/// **Future/Placeholder (Not Yet Available):** +/// - **Pyth**: High-frequency oracle network (future Stellar support) +/// - **Band Protocol**: Decentralized oracle network (not on Stellar) +/// - **DIA**: Multi-chain oracle platform (not on Stellar) +/// +/// # Provider Characteristics +/// +/// **Reflector Oracle:** +/// - **Status**: Production ready and recommended +/// - **Network**: Native Stellar blockchain integration +/// - **Assets**: BTC, ETH, XLM, and other major cryptocurrencies +/// - **Features**: Real-time prices, TWAP calculations, high reliability +/// - **Use Case**: Primary oracle for all Stellar-based prediction markets +/// +/// **Pyth Network:** +/// - **Status**: Placeholder for future implementation +/// - **Network**: Not currently available on Stellar +/// - **Assets**: Extensive coverage of crypto, forex, and traditional assets +/// - **Features**: Sub-second updates, institutional-grade data +/// - **Use Case**: Future high-frequency prediction markets +/// +/// **Band Protocol:** +/// - **Status**: Not supported on Stellar +/// - **Network**: Primarily Cosmos and EVM-compatible chains +/// - **Assets**: Wide range of crypto and traditional assets +/// - **Features**: Decentralized data aggregation +/// - **Use Case**: Not applicable for Stellar deployment +/// +/// **DIA:** +/// - **Status**: Not supported on Stellar +/// - **Network**: Multi-chain but no Stellar integration +/// - **Assets**: Comprehensive DeFi and traditional asset coverage +/// - **Features**: Transparent data sourcing and aggregation +/// - **Use Case**: Not applicable for Stellar deployment +/// +/// # Example Usage +/// +/// ```rust +/// # use predictify_hybrid::types::OracleProvider; +/// +/// // Check provider support before using +/// let provider = OracleProvider::Reflector; +/// +/// if provider.is_supported() { +/// println!("Using {} oracle provider", provider.name()); +/// // Proceed with oracle integration +/// } else { +/// println!("Provider {} not supported on Stellar", provider.name()); +/// // Use fallback or error handling +/// } +/// +/// // Provider selection logic +/// let recommended_provider = match std::env::var("ORACLE_PREFERENCE") { +/// Ok(pref) if pref == "pyth" => { +/// if OracleProvider::Pyth.is_supported() { +/// OracleProvider::Pyth +/// } else { +/// println!("Pyth not available, using Reflector"); +/// OracleProvider::Reflector +/// } +/// }, +/// _ => OracleProvider::Reflector, // Default to Reflector +/// }; +/// +/// println!("Selected oracle: {}", recommended_provider.name()); +/// ``` +/// +/// # Integration with Oracle Factory +/// +/// Oracle providers work with the Oracle Factory pattern: +/// ```rust +/// # use soroban_sdk::{Env, Address}; +/// # use predictify_hybrid::types::OracleProvider; +/// # use predictify_hybrid::oracles::OracleFactory; +/// # let env = Env::default(); +/// # let oracle_contract = Address::generate(&env); +/// +/// // Create oracle instance based on provider +/// let provider = OracleProvider::Reflector; +/// let oracle_result = OracleFactory::create_oracle(provider, oracle_contract); +/// +/// match oracle_result { +/// Ok(oracle_instance) => { +/// println!("Successfully created {} oracle", provider.name()); +/// // Use oracle for price feeds +/// }, +/// Err(e) => { +/// println!("Failed to create oracle: {:?}", e); +/// // Handle creation failure +/// }, +/// } +/// ``` +/// +/// # Provider Migration Strategy +/// +/// For future provider additions: +/// 1. **Add Provider Variant**: Update enum with new provider +/// 2. **Update Support Check**: Modify `is_supported()` method +/// 3. **Add Name Mapping**: Update `name()` method +/// 4. **Implement Integration**: Add provider-specific oracle implementation +/// 5. **Update Factory**: Add creation logic in OracleFactory +/// 6. **Test Integration**: Comprehensive testing with new provider +/// +/// # Network Compatibility +/// +/// Provider support varies by blockchain network: +/// - **Stellar**: Only Reflector is currently supported +/// - **Ethereum**: Pyth, Band Protocol, and DIA are available +/// - **Cosmos**: Band Protocol is native +/// - **Multi-chain**: DIA supports multiple networks +/// +/// # Error Handling +/// +/// When using unsupported providers: +/// - Oracle creation will return `Error::InvalidOracleConfig` +/// - Price requests will return `Error::OracleNotAvailable` +/// - Health checks will return `false` +/// - Validation will fail with appropriate error messages #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub enum OracleProvider { @@ -55,7 +301,161 @@ impl OracleProvider { } } -/// Oracle configuration for markets +/// Comprehensive oracle configuration for prediction market resolution. +/// +/// This structure defines all parameters needed to configure oracle-based market +/// resolution, including provider selection, price feed identification, threshold +/// values, and comparison logic. It serves as the bridge between prediction markets +/// and external oracle data sources. +/// +/// # Configuration Components +/// +/// **Provider Selection:** +/// - **Provider**: Which oracle service to use (Reflector, Pyth, etc.) +/// - **Feed ID**: Specific price feed identifier for the asset +/// +/// **Resolution Logic:** +/// - **Threshold**: Price level that determines market outcome +/// - **Comparison**: How to compare oracle price against threshold +/// +/// # Supported Comparisons +/// +/// The oracle configuration supports various comparison operators: +/// - **"gt"**: Greater than - price > threshold resolves to "yes" +/// - **"lt"**: Less than - price < threshold resolves to "yes" +/// - **"eq"**: Equal to - price == threshold resolves to "yes" +/// +/// # Price Format Standards +/// +/// Thresholds follow consistent pricing conventions: +/// - **Integer Values**: No floating point arithmetic +/// - **Cent Precision**: Prices in cents (e.g., 5000000 = $50,000) +/// - **Positive Values**: All thresholds must be positive +/// - **Reasonable Range**: Between $0.01 and $10,000,000 +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::types::{OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// +/// // Create oracle config for "Will BTC be above $50,000?" +/// let btc_config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "BTC/USD"), +/// 50_000_00, // $50,000 in cents +/// String::from_str(&env, "gt") // Greater than +/// ); +/// +/// // Validate the configuration +/// btc_config.validate(&env)?; +/// +/// println!("Oracle Config:"); +/// println!("Provider: {}", btc_config.provider.name()); +/// println!("Feed: {}", btc_config.feed_id); +/// println!("Threshold: ${}", btc_config.threshold / 100); +/// println!("Comparison: {}", btc_config.comparison); +/// +/// // Create config for "Will ETH drop below $2,000?" +/// let eth_config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "ETH/USD"), +/// 2_000_00, // $2,000 in cents +/// String::from_str(&env, "lt") // Less than +/// ); +/// +/// // Create config for "Will XLM equal exactly $0.50?" +/// let xlm_config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "XLM/USD"), +/// 50, // $0.50 in cents +/// String::from_str(&env, "eq") // Equal to +/// ); +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Feed ID Formats +/// +/// Different oracle providers use different feed ID formats: +/// +/// **Reflector Oracle:** +/// - Standard pairs: "BTC/USD", "ETH/USD", "XLM/USD" +/// - Asset only: "BTC", "ETH", "XLM" (assumes USD) +/// - Custom symbols: Any symbol supported by Reflector +/// +/// **Pyth Network (Future):** +/// - Hex identifiers: "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" +/// - 64-character hexadecimal strings +/// - Globally unique across all assets +/// +/// # Validation Rules +/// +/// Oracle configurations must pass validation: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::types::{OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// +/// let config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "BTC/USD"), +/// 50_000_00, +/// String::from_str(&env, "gt") +/// ); +/// +/// // Validation checks: +/// // 1. Threshold must be positive +/// // 2. Comparison must be "gt", "lt", or "eq" +/// // 3. Provider must be supported on current network +/// // 4. Feed ID must not be empty +/// +/// match config.validate(&env) { +/// Ok(()) => println!("Configuration is valid"), +/// Err(e) => println!("Validation failed: {:?}", e), +/// } +/// ``` +/// +/// # Integration with Market Resolution +/// +/// Oracle configurations integrate with resolution systems: +/// - **Oracle Manager**: Uses config to fetch appropriate price data +/// - **Resolution Logic**: Applies comparison to determine outcomes +/// - **Validation System**: Ensures config meets quality standards +/// - **Event System**: Logs oracle configuration for transparency +/// +/// # Common Configuration Patterns +/// +/// **Price Threshold Markets:** +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::types::{OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// +/// // "Will BTC reach $100k by year end?" +/// let btc_100k = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "BTC/USD"), +/// 100_000_00, +/// String::from_str(&env, "gt") +/// ); +/// +/// // "Will ETH stay above $1,500?" +/// let eth_support = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "ETH/USD"), +/// 1_500_00, +/// String::from_str(&env, "gt") +/// ); +/// ``` +/// +/// # Error Handling +/// +/// Common configuration errors: +/// - **InvalidThreshold**: Threshold is zero or negative +/// - **InvalidComparison**: Unsupported comparison operator +/// - **InvalidOracleConfig**: Unsupported oracle provider +/// - **InvalidFeed**: Empty or malformed feed identifier #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct OracleConfig { @@ -113,7 +513,190 @@ impl OracleConfig { // ===== MARKET TYPES ===== -/// Market state and data structure +/// Comprehensive market data structure representing a complete prediction market. +/// +/// This structure contains all data necessary to manage a prediction market throughout +/// its entire lifecycle, from creation through resolution and payout distribution. +/// It serves as the central data model for all market operations and state management. +/// +/// # Core Market Components +/// +/// **Market Identity:** +/// - **Admin**: Market administrator with special privileges +/// - **Question**: The prediction question being resolved +/// - **Outcomes**: Available outcomes users can vote on +/// - **End Time**: When the voting period concludes +/// +/// **Oracle Integration:** +/// - **Oracle Config**: Configuration for oracle-based resolution +/// - **Oracle Result**: Final oracle outcome (set after resolution) +/// +/// **User Participation:** +/// - **Votes**: User outcome predictions +/// - **Stakes**: User financial commitments +/// - **Claimed**: Payout claim status tracking +/// +/// **Financial Tracking:** +/// - **Total Staked**: Aggregate stake amount across all users +/// - **Dispute Stakes**: Stakes committed to dispute processes +/// - **Market State**: Current lifecycle state +/// +/// # Market Lifecycle +/// +/// Markets progress through distinct phases: +/// ```text +/// Creation → Active Voting → Ended → Resolution → Payout → Closed +/// ``` +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String, Vec}; +/// # use predictify_hybrid::types::{Market, MarketState, OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// # let admin = Address::generate(&env); +/// +/// // Create a new prediction market +/// let market = Market::new( +/// &env, +/// admin.clone(), +/// String::from_str(&env, "Will BTC reach $100,000 by December 31, 2024?"), +/// Vec::from_array(&env, [ +/// String::from_str(&env, "yes"), +/// String::from_str(&env, "no") +/// ]), +/// env.ledger().timestamp() + (30 * 24 * 60 * 60), // 30 days +/// OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "BTC/USD"), +/// 100_000_00, // $100,000 +/// String::from_str(&env, "gt") +/// ), +/// MarketState::Active +/// ); +/// +/// // Validate the market +/// market.validate(&env)?; +/// +/// // Check market status +/// let current_time = env.ledger().timestamp(); +/// if market.is_active(current_time) { +/// println!("Market is active and accepting votes"); +/// } else if market.has_ended(current_time) { +/// println!("Market has ended, ready for resolution"); +/// } +/// +/// // Display market information +/// println!("Market Question: {}", market.question); +/// println!("Admin: {}", market.admin); +/// println!("Total Staked: {} stroops", market.total_staked); +/// println!("State: {:?}", market.state); +/// +/// // Check if market is resolved +/// if market.is_resolved() { +/// if let Some(result) = &market.oracle_result { +/// println!("Oracle Result: {}", result); +/// } +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # User Participation Tracking +/// +/// Markets track comprehensive user participation: +/// ```rust +/// # use soroban_sdk::{Address, String}; +/// # use predictify_hybrid::types::Market; +/// # let mut market = Market::default(); // Placeholder +/// # let user = Address::generate(&soroban_sdk::Env::default()); +/// +/// // Add user vote and stake (for testing) +/// market.add_vote( +/// user.clone(), +/// String::from_str(&soroban_sdk::Env::default(), "yes"), +/// 1_000_000 // 1 XLM in stroops +/// ); +/// +/// // Check user's vote +/// if let Some(user_vote) = market.votes.get(user.clone()) { +/// println!("User voted: {}", user_vote); +/// } +/// +/// // Check user's stake +/// if let Some(user_stake) = market.stakes.get(user.clone()) { +/// println!("User staked: {} stroops", user_stake); +/// } +/// +/// // Check if user has claimed payout +/// let has_claimed = market.claimed.get(user.clone()).unwrap_or(false); +/// println!("User claimed payout: {}", has_claimed); +/// ``` +/// +/// # Market Validation +/// +/// Markets undergo comprehensive validation: +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::types::Market; +/// # let env = Env::default(); +/// # let market = Market::default(); // Placeholder +/// +/// // Validation checks multiple aspects: +/// match market.validate(&env) { +/// Ok(()) => { +/// println!("Market validation passed"); +/// // Market is ready for use +/// }, +/// Err(e) => { +/// println!("Market validation failed: {:?}", e); +/// // Handle validation errors: +/// // - InvalidQuestion: Empty or invalid question +/// // - InvalidOutcomes: Less than 2 outcomes +/// // - InvalidDuration: End time in the past +/// // - Oracle validation errors +/// } +/// } +/// ``` +/// +/// # Financial Management +/// +/// Markets track financial flows: +/// ```rust +/// # use predictify_hybrid::types::Market; +/// # let market = Market::default(); // Placeholder +/// +/// // Total market value +/// println!("Total staked: {} stroops", market.total_staked); +/// +/// // Dispute stakes (for contested resolutions) +/// let dispute_total = market.total_dispute_stakes(); +/// println!("Total dispute stakes: {} stroops", dispute_total); +/// +/// // Calculate potential payouts +/// let winner_pool = market.total_staked; // Simplified +/// println!("Winner pool: {} stroops", winner_pool); +/// ``` +/// +/// # Integration Points +/// +/// Markets integrate with multiple systems: +/// - **Voting System**: Manages user votes and stakes +/// - **Oracle System**: Handles oracle-based resolution +/// - **Dispute System**: Manages dispute processes +/// - **Payout System**: Distributes winnings to users +/// - **Admin System**: Handles administrative operations +/// - **Event System**: Emits market events for transparency +/// - **Analytics System**: Tracks market performance metrics +/// +/// # State Management +/// +/// Market state transitions are carefully managed: +/// - **Active**: Users can vote, stakes accepted +/// - **Ended**: Voting closed, resolution pending +/// - **Disputed**: Under dispute resolution +/// - **Resolved**: Outcome determined, payouts available +/// - **Closed**: All operations complete +/// - **Cancelled**: Market cancelled, stakes refunded #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct Market { @@ -247,7 +830,168 @@ impl Market { // ===== REFLECTOR ORACLE TYPES ===== -/// Reflector asset enumeration +/// Enumeration of supported assets in the Reflector Oracle ecosystem. +/// +/// This enum defines the cryptocurrency assets for which the Reflector Oracle +/// provides price feeds on the Stellar network. Reflector is the primary oracle +/// provider for Stellar-based prediction markets, offering real-time price data +/// for major cryptocurrencies. +/// +/// # Supported Assets +/// +/// **Bitcoin (BTC):** +/// - Symbol: BTC +/// - Description: Bitcoin, the original cryptocurrency +/// - Typical precision: 8 decimal places +/// - Price range: $10,000 - $200,000+ (historical and projected) +/// +/// **Ethereum (ETH):** +/// - Symbol: ETH +/// - Description: Ethereum native token +/// - Typical precision: 18 decimal places +/// - Price range: $500 - $10,000+ (historical and projected) +/// +/// **Stellar Lumens (XLM):** +/// - Symbol: XLM +/// - Description: Stellar network native token +/// - Typical precision: 7 decimal places +/// - Price range: $0.05 - $2.00+ (historical and projected) +/// +/// # Example Usage +/// +/// ```rust +/// # use predictify_hybrid::types::ReflectorAsset; +/// +/// // Asset identification and properties +/// let btc = ReflectorAsset::BTC; +/// println!("Asset: {}", btc.symbol()); +/// println!("Name: {}", btc.name()); +/// println!("Decimals: {}", btc.decimals()); +/// +/// // Asset validation +/// let assets = vec![ReflectorAsset::BTC, ReflectorAsset::ETH, ReflectorAsset::XLM]; +/// for asset in assets { +/// if asset.is_supported() { +/// println!("{} is supported by Reflector", asset.symbol()); +/// } +/// } +/// +/// // Feed ID generation +/// let btc_feed = ReflectorAsset::BTC.feed_id(); +/// println!("BTC feed ID: {}", btc_feed); // "BTC/USD" +/// +/// let eth_feed = ReflectorAsset::ETH.feed_id(); +/// println!("ETH feed ID: {}", eth_feed); // "ETH/USD" +/// ``` +/// +/// # Price Feed Integration +/// +/// Reflector assets integrate with oracle price feeds: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::types::{ReflectorAsset, OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// +/// // Create oracle config for BTC price prediction +/// let btc_asset = ReflectorAsset::BTC; +/// let oracle_config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, &btc_asset.feed_id()), +/// 50_000_00, // $50,000 threshold +/// String::from_str(&env, "gt") +/// ); +/// +/// // Validate asset support +/// if btc_asset.is_supported() { +/// println!("BTC oracle config created successfully"); +/// } +/// ``` +/// +/// # Asset Properties +/// +/// Each asset has specific characteristics: +/// ```rust +/// # use predictify_hybrid::types::ReflectorAsset; +/// +/// // Bitcoin properties +/// let btc = ReflectorAsset::BTC; +/// assert_eq!(btc.symbol(), "BTC"); +/// assert_eq!(btc.name(), "Bitcoin"); +/// assert_eq!(btc.decimals(), 8); +/// assert!(btc.is_supported()); +/// +/// // Ethereum properties +/// let eth = ReflectorAsset::ETH; +/// assert_eq!(eth.symbol(), "ETH"); +/// assert_eq!(eth.name(), "Ethereum"); +/// assert_eq!(eth.decimals(), 18); +/// assert!(eth.is_supported()); +/// +/// // Stellar Lumens properties +/// let xlm = ReflectorAsset::XLM; +/// assert_eq!(xlm.symbol(), "XLM"); +/// assert_eq!(xlm.name(), "Stellar Lumens"); +/// assert_eq!(xlm.decimals(), 7); +/// assert!(xlm.is_supported()); +/// ``` +/// +/// # Feed ID Format +/// +/// Reflector uses standardized feed identifiers: +/// - **Format**: "{ASSET}/USD" +/// - **Examples**: "BTC/USD", "ETH/USD", "XLM/USD" +/// - **Base Currency**: All prices quoted in USD +/// - **Case Sensitivity**: Uppercase asset symbols +/// +/// # Integration with Market Creation +/// +/// Assets are commonly used in market creation: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::types::{ReflectorAsset, OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// +/// // Create market for "Will BTC reach $100k?" +/// let btc_market_config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, &ReflectorAsset::BTC.feed_id()), +/// 100_000_00, +/// String::from_str(&env, "gt") +/// ); +/// +/// // Create market for "Will ETH drop below $1,000?" +/// let eth_market_config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, &ReflectorAsset::ETH.feed_id()), +/// 1_000_00, +/// String::from_str(&env, "lt") +/// ); +/// +/// // Create market for "Will XLM reach $1?" +/// let xlm_market_config = OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, &ReflectorAsset::XLM.feed_id()), +/// 100, // $1.00 +/// String::from_str(&env, "gt") +/// ); +/// ``` +/// +/// # Future Asset Additions +/// +/// To add new assets to Reflector support: +/// 1. **Add Enum Variant**: Add new asset to enum +/// 2. **Update Methods**: Add symbol, name, decimals mapping +/// 3. **Test Integration**: Verify Reflector feed availability +/// 4. **Update Documentation**: Add asset characteristics +/// 5. **Validate Feeds**: Ensure price feed reliability +/// +/// # Error Handling +/// +/// Asset-related errors: +/// - **UnsupportedAsset**: Asset not available in Reflector +/// - **InvalidFeedId**: Malformed feed identifier +/// - **PriceFeedUnavailable**: Reflector feed temporarily down +/// - **InvalidPriceData**: Corrupted or invalid price information #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub enum ReflectorAsset { @@ -258,7 +1002,202 @@ pub enum ReflectorAsset { } -/// Reflector price data structure +/// Comprehensive price data structure from Reflector Oracle. +/// +/// This structure contains all price information returned by the Reflector Oracle, +/// including current price, timestamp, and metadata necessary for market resolution +/// and validation. It serves as the standardized format for oracle price data +/// within the prediction market system. +/// +/// # Price Data Components +/// +/// **Core Price Information:** +/// - **Price**: Current asset price in cents (integer format) +/// - **Timestamp**: When the price was last updated +/// - **Decimals**: Number of decimal places for precision +/// +/// **Data Quality Indicators:** +/// - **Source**: Oracle provider identifier +/// - **Confidence**: Price data reliability score +/// - **Volume**: Trading volume (if available) +/// +/// # Price Format Standards +/// +/// Prices follow consistent formatting: +/// - **Integer Values**: No floating point arithmetic +/// - **Cent Precision**: All prices in cents (e.g., 5000000 = $50,000.00) +/// - **Positive Values**: All prices are positive integers +/// - **Range Validation**: Prices within reasonable market bounds +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::types::ReflectorPriceData; +/// # let env = Env::default(); +/// +/// // Create price data from Reflector response +/// let btc_price = ReflectorPriceData::new( +/// 5_000_000, // $50,000.00 in cents +/// env.ledger().timestamp(), +/// 8, // Bitcoin decimals +/// "Reflector".to_string(), +/// 95, // 95% confidence +/// Some(1_000_000_000) // $10M volume +/// ); +/// +/// // Display price information +/// println!("BTC Price: ${:.2}", btc_price.price_in_dollars()); +/// println!("Updated: {}", btc_price.timestamp); +/// println!("Confidence: {}%", btc_price.confidence); +/// +/// // Validate price data quality +/// if btc_price.is_valid() { +/// println!("Price data is valid and reliable"); +/// } else { +/// println!("Price data quality concerns detected"); +/// } +/// +/// // Check data freshness +/// let current_time = env.ledger().timestamp(); +/// if btc_price.is_fresh(current_time, 300) { // 5 minutes +/// println!("Price data is fresh (within 5 minutes)"); +/// } else { +/// println!("Price data is stale - consider refreshing"); +/// } +/// ``` +/// +/// # Price Validation +/// +/// Price data undergoes comprehensive validation: +/// ```rust +/// # use predictify_hybrid::types::ReflectorPriceData; +/// # let price_data = ReflectorPriceData::default(); // Placeholder +/// +/// // Validation checks multiple aspects: +/// let validation_result = price_data.validate(); +/// match validation_result { +/// Ok(()) => { +/// println!("Price data validation passed"); +/// // Safe to use for market resolution +/// }, +/// Err(e) => { +/// println!("Price validation failed: {:?}", e); +/// // Handle validation errors: +/// // - InvalidPrice: Price is zero or negative +/// // - StaleData: Timestamp too old +/// // - LowConfidence: Confidence below threshold +/// // - InvalidSource: Unknown oracle source +/// } +/// } +/// ``` +/// +/// # Market Resolution Integration +/// +/// Price data integrates with market resolution: +/// ```rust +/// # use predictify_hybrid::types::{ReflectorPriceData, OracleConfig}; +/// # let price_data = ReflectorPriceData::default(); // Placeholder +/// # let oracle_config = OracleConfig::default(); // Placeholder +/// +/// // Apply oracle configuration to determine outcome +/// let market_outcome = price_data.resolve_outcome(&oracle_config); +/// +/// match market_outcome { +/// Ok(outcome) => { +/// println!("Market resolved to: {}", outcome); +/// // "yes" if condition met, "no" otherwise +/// }, +/// Err(e) => { +/// println!("Resolution failed: {:?}", e); +/// // Handle resolution errors +/// } +/// } +/// +/// // Example: BTC > $50,000 check +/// let btc_price = 5_500_000; // $55,000 +/// let threshold = 5_000_000; // $50,000 +/// let comparison = "gt"; // Greater than +/// +/// let result = if comparison == "gt" { +/// btc_price > threshold +/// } else if comparison == "lt" { +/// btc_price < threshold +/// } else { +/// btc_price == threshold +/// }; +/// +/// println!("Market outcome: {}", if result { "yes" } else { "no" }); +/// ``` +/// +/// # Data Quality Metrics +/// +/// Price data includes quality indicators: +/// ```rust +/// # use predictify_hybrid::types::ReflectorPriceData; +/// # let price_data = ReflectorPriceData::default(); // Placeholder +/// +/// // Check confidence level +/// if price_data.confidence >= 90 { +/// println!("High confidence price data"); +/// } else if price_data.confidence >= 70 { +/// println!("Medium confidence price data"); +/// } else { +/// println!("Low confidence - use with caution"); +/// } +/// +/// // Check trading volume (if available) +/// if let Some(volume) = price_data.volume { +/// if volume > 1_000_000_00 { // $1M+ +/// println!("High liquidity market"); +/// } else { +/// println!("Lower liquidity - price may be volatile"); +/// } +/// } +/// ``` +/// +/// # Time-based Validation +/// +/// Price data freshness is critical: +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::types::ReflectorPriceData; +/// # let env = Env::default(); +/// # let price_data = ReflectorPriceData::default(); // Placeholder +/// +/// let current_time = env.ledger().timestamp(); +/// let max_age = 600; // 10 minutes +/// +/// if price_data.is_fresh(current_time, max_age) { +/// println!("Price data is current"); +/// } else { +/// let age = current_time - price_data.timestamp; +/// println!("Price data is {} seconds old", age); +/// +/// if age > 3600 { // 1 hour +/// println!("Data is very stale - reject for resolution"); +/// } +/// } +/// ``` +/// +/// # Integration Points +/// +/// Price data integrates with: +/// - **Oracle Manager**: Fetches and validates price data +/// - **Resolution System**: Uses price for market outcome determination +/// - **Validation System**: Ensures data quality and freshness +/// - **Analytics System**: Tracks price trends and market performance +/// - **Event System**: Logs price updates for transparency +/// - **Dispute System**: Provides evidence for dispute resolution +/// +/// # Error Handling +/// +/// Common price data errors: +/// - **InvalidPrice**: Zero, negative, or unreasonable price +/// - **StaleTimestamp**: Price data too old for reliable use +/// - **LowConfidence**: Confidence score below acceptance threshold +/// - **MissingVolume**: Volume data unavailable when required +/// - **SourceMismatch**: Price from unexpected oracle source #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct ReflectorPriceData { @@ -272,7 +1211,225 @@ pub struct ReflectorPriceData { // ===== MARKET EXTENSION TYPES ===== -/// Market extension data structure +/// Market extension data structure for time-based market lifecycle management. +/// +/// This structure manages the extension of market voting periods, allowing markets +/// to have their end times adjusted under specific conditions. Extensions provide +/// flexibility for markets that may need additional time due to low participation, +/// significant events, or community requests. +/// +/// # Extension Components +/// +/// **Extension Request:** +/// - **Requester**: Address that requested the extension +/// - **Original End Time**: Market's initial end time +/// - **New End Time**: Proposed new end time after extension +/// - **Extension Duration**: Length of the extension in seconds +/// +/// **Extension Justification:** +/// - **Reason**: Explanation for why extension is needed +/// - **Fee**: Cost paid for the extension request +/// - **Approval Status**: Whether extension has been approved +/// +/// **Extension Limits:** +/// - **Max Extensions**: Maximum number of extensions allowed +/// - **Max Duration**: Maximum total extension time +/// - **Min Participation**: Minimum participation required to avoid extension +/// +/// # Extension Scenarios +/// +/// **Low Participation Extension:** +/// - Market has insufficient votes or stakes +/// - Automatic extension to encourage participation +/// - Extends by standard duration (e.g., 24-48 hours) +/// +/// **Community Requested Extension:** +/// - Users request more time for consideration +/// - Requires fee payment and admin approval +/// - Extends by requested duration (within limits) +/// +/// **Event-Based Extension:** +/// - Significant market-relevant events occur +/// - Admin-initiated extension for fair resolution +/// - Duration based on event significance +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::types::MarketExtension; +/// # let env = Env::default(); +/// # let requester = Address::generate(&env); +/// +/// // Create extension request for low participation +/// let extension = MarketExtension::new( +/// &env, +/// requester.clone(), +/// env.ledger().timestamp() + (7 * 24 * 60 * 60), // Original: 7 days +/// env.ledger().timestamp() + (9 * 24 * 60 * 60), // Extended: 9 days +/// String::from_str(&env, "Low participation - extending for more votes"), +/// 1_000_000, // 1 XLM extension fee +/// false // Pending approval +/// ); +/// +/// // Validate extension request +/// extension.validate(&env)?; +/// +/// // Display extension information +/// println!("Extension requested by: {}", extension.requester); +/// println!("Extension duration: {} hours", extension.duration_hours()); +/// println!("Extension fee: {} stroops", extension.fee); +/// println!("Reason: {}", extension.reason); +/// +/// // Check if extension is within limits +/// if extension.is_within_limits() { +/// println!("Extension request is valid"); +/// } else { +/// println!("Extension exceeds maximum allowed duration"); +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Extension Validation +/// +/// Extensions undergo comprehensive validation: +/// ```rust +/// # use predictify_hybrid::types::MarketExtension; +/// # let extension = MarketExtension::default(); // Placeholder +/// +/// // Validation checks multiple aspects: +/// let validation_result = extension.validate(&soroban_sdk::Env::default()); +/// match validation_result { +/// Ok(()) => { +/// println!("Extension validation passed"); +/// // Extension can be processed +/// }, +/// Err(e) => { +/// println!("Extension validation failed: {:?}", e); +/// // Handle validation errors: +/// // - InvalidDuration: Extension too long or negative +/// // - InsufficientFee: Fee below minimum requirement +/// // - InvalidReason: Empty or inappropriate reason +/// // - ExceedsLimits: Too many extensions or total duration +/// } +/// } +/// ``` +/// +/// # Fee Structure +/// +/// Extension fees vary by type and duration: +/// ```rust +/// # use predictify_hybrid::types::MarketExtension; +/// +/// // Calculate extension fee based on duration +/// let base_fee = 1_000_000; // 1 XLM base fee +/// let duration_hours = 48; // 48 hour extension +/// +/// let total_fee = if duration_hours <= 24 { +/// base_fee // Standard 24-hour extension +/// } else if duration_hours <= 72 { +/// base_fee * 2 // Extended duration (25-72 hours) +/// } else { +/// base_fee * 5 // Long extension (73+ hours) +/// }; +/// +/// println!("Extension fee for {} hours: {} stroops", duration_hours, total_fee); +/// ``` +/// +/// # Extension Approval Process +/// +/// Extensions follow a structured approval workflow: +/// ```rust +/// # use predictify_hybrid::types::MarketExtension; +/// # let mut extension = MarketExtension::default(); // Placeholder +/// +/// // Step 1: Request submitted with fee +/// extension.set_status("pending"); +/// +/// // Step 2: Admin review +/// if extension.meets_criteria() { +/// extension.approve(); +/// println!("Extension approved"); +/// } else { +/// extension.reject("Insufficient justification"); +/// println!("Extension rejected"); +/// } +/// +/// // Step 3: Apply extension if approved +/// if extension.is_approved() { +/// extension.apply_to_market(); +/// println!("Market end time updated"); +/// } +/// ``` +/// +/// # Integration with Market Lifecycle +/// +/// Extensions integrate with market state management: +/// - **Active Markets**: Can request extensions before end time +/// - **Ended Markets**: Cannot be extended (voting already closed) +/// - **Disputed Markets**: May receive extensions for dispute resolution +/// - **Admin Override**: Admins can extend markets in special circumstances +/// +/// # Extension Analytics +/// +/// Track extension usage and effectiveness: +/// ```rust +/// # use predictify_hybrid::types::MarketExtension; +/// # let extension = MarketExtension::default(); // Placeholder +/// +/// // Extension statistics +/// println!("Extension type: {}", extension.extension_type()); +/// println!("Participation before: {}%", extension.participation_before()); +/// println!("Participation after: {}%", extension.participation_after()); +/// println!("Extension effectiveness: {}%", extension.effectiveness()); +/// ``` +/// +/// # Common Extension Patterns +/// +/// **Low Participation Auto-Extension:** +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::types::MarketExtension; +/// # let env = Env::default(); +/// # let system = Address::generate(&env); +/// +/// let auto_extension = MarketExtension::new( +/// &env, +/// system, // System-initiated +/// env.ledger().timestamp() + (7 * 24 * 60 * 60), +/// env.ledger().timestamp() + (8 * 24 * 60 * 60), // +24 hours +/// String::from_str(&env, "Auto-extension: Low participation detected"), +/// 0, // No fee for auto-extensions +/// true // Auto-approved +/// ); +/// ``` +/// +/// **Community Requested Extension:** +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::types::MarketExtension; +/// # let env = Env::default(); +/// # let community_member = Address::generate(&env); +/// +/// let community_extension = MarketExtension::new( +/// &env, +/// community_member, +/// env.ledger().timestamp() + (7 * 24 * 60 * 60), +/// env.ledger().timestamp() + (10 * 24 * 60 * 60), // +72 hours +/// String::from_str(&env, "Major announcement expected - need more time"), +/// 2_000_000, // 2 XLM fee +/// false // Pending admin approval +/// ); +/// ``` +/// +/// # Error Handling +/// +/// Common extension errors: +/// - **InvalidDuration**: Extension duration is negative or too long +/// - **InsufficientFee**: Fee payment below required amount +/// - **MarketEnded**: Cannot extend market that has already ended +/// - **ExceedsLimits**: Extension would exceed maximum allowed duration +/// - **UnauthorizedRequester**: Requester lacks permission for extension #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct MarketExtension { @@ -307,7 +1464,225 @@ impl MarketExtension { } } -/// Extension statistics +/// Comprehensive statistics tracking for market extension usage and effectiveness. +/// +/// This structure captures detailed metrics about market extensions, including +/// usage patterns, effectiveness measurements, and impact on market participation. +/// It provides valuable insights for optimizing extension policies and understanding +/// user behavior in prediction markets. +/// +/// # Statistics Categories +/// +/// **Usage Metrics:** +/// - **Total Extensions**: Number of extensions requested +/// - **Approved Extensions**: Number of extensions approved +/// - **Auto Extensions**: System-initiated extensions +/// - **User Extensions**: Community-requested extensions +/// +/// **Effectiveness Metrics:** +/// - **Participation Increase**: Additional votes/stakes after extension +/// - **Resolution Quality**: Impact on market resolution accuracy +/// - **User Satisfaction**: Community feedback on extensions +/// +/// **Financial Metrics:** +/// - **Total Fees Collected**: Revenue from extension fees +/// - **Average Fee**: Mean fee per extension request +/// - **Fee Effectiveness**: Correlation between fee and participation +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::types::ExtensionStats; +/// # let env = Env::default(); +/// +/// // Create extension statistics tracker +/// let mut stats = ExtensionStats::new(&env); +/// +/// // Record extension request +/// stats.record_extension_request( +/// "user_requested", +/// 48, // 48 hours +/// 2_000_000, // 2 XLM fee +/// true // Approved +/// ); +/// +/// // Record participation impact +/// stats.record_participation_change( +/// 10, // 10 additional votes +/// 5_000_000, // 5 XLM additional stakes +/// 25.0 // 25% participation increase +/// ); +/// +/// // Display statistics +/// println!("Total extensions: {}", stats.total_extensions); +/// println!("Approval rate: {:.1}%", stats.approval_rate()); +/// println!("Average participation increase: {:.1}%", stats.avg_participation_increase()); +/// println!("Total fees collected: {} stroops", stats.total_fees_collected); +/// ``` +/// +/// # Effectiveness Analysis +/// +/// Analyze extension effectiveness across different scenarios: +/// ```rust +/// # use predictify_hybrid::types::ExtensionStats; +/// # let stats = ExtensionStats::default(); // Placeholder +/// +/// // Calculate effectiveness metrics +/// let effectiveness_report = stats.generate_effectiveness_report(); +/// +/// println!("Extension Effectiveness Report:"); +/// println!("- Auto extensions success rate: {:.1}%", effectiveness_report.auto_success_rate); +/// println!("- User extensions success rate: {:.1}%", effectiveness_report.user_success_rate); +/// println!("- Average participation boost: {:.1}%", effectiveness_report.avg_participation_boost); +/// println!("- ROI on extension fees: {:.2}x", effectiveness_report.fee_roi); +/// +/// // Identify optimal extension patterns +/// if effectiveness_report.auto_success_rate > effectiveness_report.user_success_rate { +/// println!("Recommendation: Favor automatic extensions for low participation"); +/// } else { +/// println!("Recommendation: Community-driven extensions are more effective"); +/// } +/// ``` +/// +/// # Trend Analysis +/// +/// Track extension trends over time: +/// ```rust +/// # use predictify_hybrid::types::ExtensionStats; +/// # let stats = ExtensionStats::default(); // Placeholder +/// +/// // Analyze monthly trends +/// let monthly_trends = stats.get_monthly_trends(); +/// +/// for (month, trend_data) in monthly_trends { +/// println!("Month {}: {} extensions, {:.1}% approval rate", +/// month, trend_data.count, trend_data.approval_rate); +/// +/// if trend_data.count > trend_data.previous_month_count { +/// println!(" ↗ Extension requests increasing"); +/// } else { +/// println!(" ↘ Extension requests decreasing"); +/// } +/// } +/// +/// // Seasonal patterns +/// let seasonal_analysis = stats.analyze_seasonal_patterns(); +/// println!("Peak extension period: {}", seasonal_analysis.peak_period); +/// println!("Low extension period: {}", seasonal_analysis.low_period); +/// ``` +/// +/// # Fee Optimization Analysis +/// +/// Analyze fee structures and their impact: +/// ```rust +/// # use predictify_hybrid::types::ExtensionStats; +/// # let stats = ExtensionStats::default(); // Placeholder +/// +/// // Fee effectiveness analysis +/// let fee_analysis = stats.analyze_fee_effectiveness(); +/// +/// println!("Fee Analysis:"); +/// println!("- Optimal fee range: {} - {} stroops", +/// fee_analysis.optimal_min, fee_analysis.optimal_max); +/// println!("- Fee elasticity: {:.2}", fee_analysis.elasticity); +/// println!("- Revenue maximizing fee: {} stroops", fee_analysis.revenue_max_fee); +/// +/// // Fee recommendations +/// if fee_analysis.current_fee < fee_analysis.optimal_min { +/// println!("Recommendation: Increase extension fees to improve quality"); +/// } else if fee_analysis.current_fee > fee_analysis.optimal_max { +/// println!("Recommendation: Decrease extension fees to increase usage"); +/// } else { +/// println!("Current fee structure is optimal"); +/// } +/// ``` +/// +/// # Market Impact Assessment +/// +/// Evaluate how extensions affect market quality: +/// ```rust +/// # use predictify_hybrid::types::ExtensionStats; +/// # let stats = ExtensionStats::default(); // Placeholder +/// +/// // Market quality impact +/// let quality_impact = stats.assess_market_quality_impact(); +/// +/// println!("Market Quality Impact:"); +/// println!("- Resolution accuracy improvement: {:.1}%", quality_impact.accuracy_improvement); +/// println!("- Participation diversity increase: {:.1}%", quality_impact.diversity_increase); +/// println!("- Stake distribution improvement: {:.1}%", quality_impact.distribution_improvement); +/// +/// // Long-term effects +/// println!("\nLong-term Effects:"); +/// println!("- User retention rate: {:.1}%", quality_impact.retention_rate); +/// println!("- Market creation rate change: {:+.1}%", quality_impact.creation_rate_change); +/// println!("- Platform trust score: {:.1}/10", quality_impact.trust_score); +/// ``` +/// +/// # Performance Benchmarking +/// +/// Compare extension performance across different market types: +/// ```rust +/// # use predictify_hybrid::types::ExtensionStats; +/// # let stats = ExtensionStats::default(); // Placeholder +/// +/// // Benchmark by market category +/// let benchmarks = stats.benchmark_by_category(); +/// +/// for (category, benchmark) in benchmarks { +/// println!("{} Markets:", category); +/// println!(" Extension rate: {:.1}%", benchmark.extension_rate); +/// println!(" Success rate: {:.1}%", benchmark.success_rate); +/// println!(" Avg duration: {:.1} hours", benchmark.avg_duration_hours); +/// println!(" Participation boost: {:.1}%", benchmark.participation_boost); +/// } +/// +/// // Identify best practices +/// let best_practices = stats.identify_best_practices(); +/// println!("\nBest Practices:"); +/// for practice in best_practices { +/// println!("- {}", practice); +/// } +/// ``` +/// +/// # Integration Points +/// +/// Extension statistics integrate with: +/// - **Analytics Dashboard**: Real-time extension metrics +/// - **Admin Panel**: Extension approval and monitoring tools +/// - **Market Manager**: Extension policy optimization +/// - **Fee Manager**: Dynamic fee adjustment based on effectiveness +/// - **User Interface**: Extension request guidance and feedback +/// - **Reporting System**: Periodic extension effectiveness reports +/// +/// # Data Export and Reporting +/// +/// Generate comprehensive reports for stakeholders: +/// ```rust +/// # use predictify_hybrid::types::ExtensionStats; +/// # let stats = ExtensionStats::default(); // Placeholder +/// +/// // Generate monthly report +/// let monthly_report = stats.generate_monthly_report(); +/// println!("Extension Monthly Report:"); +/// println!("Total Requests: {}", monthly_report.total_requests); +/// println!("Approval Rate: {:.1}%", monthly_report.approval_rate); +/// println!("Revenue Generated: {} XLM", monthly_report.revenue_xlm); +/// println!("Participation Impact: +{:.1}%", monthly_report.participation_impact); +/// +/// // Export data for external analysis +/// let csv_data = stats.export_to_csv(); +/// println!("CSV export ready: {} records", csv_data.len()); +/// ``` +/// +/// # Error Handling +/// +/// Common statistics errors: +/// - **InvalidDataPoint**: Malformed or inconsistent data +/// - **InsufficientData**: Not enough data for meaningful analysis +/// - **CalculationError**: Mathematical operation failed +/// - **ExportError**: Data export operation failed #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct ExtensionStats { @@ -325,7 +1700,265 @@ pub struct ExtensionStats { // ===== MARKET CREATION TYPES ===== -/// Market creation parameters +/// Comprehensive parameters for creating new prediction markets. +/// +/// This structure contains all necessary information to create a new prediction +/// market, including administrative details, market configuration, oracle setup, +/// and financial requirements. It serves as the complete specification for +/// market initialization and validation. +/// +/// # Parameter Categories +/// +/// **Administrative Setup:** +/// - **Admin**: Market administrator with management privileges +/// - **Creation Fee**: Cost to create the market +/// +/// **Market Definition:** +/// - **Question**: The prediction question being resolved +/// - **Outcomes**: Available outcomes users can vote on +/// - **Duration**: How long the market remains active +/// +/// **Oracle Integration:** +/// - **Oracle Config**: Configuration for automated resolution +/// +/// # Market Creation Workflow +/// +/// The market creation process follows these steps: +/// ```text +/// Parameters → Validation → Fee Payment → Market Creation → Activation +/// ``` +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String, Vec}; +/// # use predictify_hybrid::types::{MarketCreationParams, OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// # let admin = Address::generate(&env); +/// +/// // Create parameters for a Bitcoin price prediction market +/// let btc_market_params = MarketCreationParams::new( +/// admin.clone(), +/// String::from_str(&env, "Will Bitcoin reach $100,000 by December 31, 2024?"), +/// Vec::from_array(&env, [ +/// String::from_str(&env, "yes"), +/// String::from_str(&env, "no") +/// ]), +/// 30, // 30 days duration +/// OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "BTC/USD"), +/// 100_000_00, // $100,000 threshold +/// String::from_str(&env, "gt") +/// ), +/// 5_000_000 // 5 XLM creation fee +/// ); +/// +/// // Validate parameters before market creation +/// btc_market_params.validate(&env)?; +/// +/// // Display market information +/// println!("Market Question: {}", btc_market_params.question); +/// println!("Duration: {} days", btc_market_params.duration_days); +/// println!("Creation Fee: {} stroops", btc_market_params.creation_fee); +/// println!("Oracle Provider: {}", btc_market_params.oracle_config.provider.name()); +/// +/// // Check if admin has sufficient balance +/// if admin_has_sufficient_balance(&admin, btc_market_params.creation_fee) { +/// println!("Admin can afford market creation"); +/// } else { +/// println!("Insufficient balance for market creation"); +/// } +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Parameter Validation +/// +/// Market creation parameters undergo comprehensive validation: +/// ```rust +/// # use predictify_hybrid::types::MarketCreationParams; +/// # let params = MarketCreationParams::default(); // Placeholder +/// +/// // Validation checks multiple aspects: +/// let validation_result = params.validate(&soroban_sdk::Env::default()); +/// match validation_result { +/// Ok(()) => { +/// println!("Market parameters are valid"); +/// // Proceed with market creation +/// }, +/// Err(e) => { +/// println!("Parameter validation failed: {:?}", e); +/// // Handle validation errors: +/// // - InvalidQuestion: Empty or inappropriate question +/// // - InvalidOutcomes: Less than 2 outcomes or duplicates +/// // - InvalidDuration: Duration too short or too long +/// // - InsufficientFee: Creation fee below minimum +/// // - InvalidOracleConfig: Oracle configuration errors +/// } +/// } +/// ``` +/// +/// # Question Guidelines +/// +/// Market questions should follow best practices: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # let env = Env::default(); +/// +/// // Good question examples: +/// let good_questions = vec![ +/// "Will Bitcoin reach $100,000 by December 31, 2024?", +/// "Will Ethereum's price exceed $5,000 before June 1, 2024?", +/// "Will XLM trade above $1.00 within the next 90 days?" +/// ]; +/// +/// // Question validation criteria: +/// // 1. Clear and unambiguous +/// // 2. Specific timeframe +/// // 3. Measurable outcome +/// // 4. Appropriate length (10-200 characters) +/// // 5. No offensive or inappropriate content +/// +/// for question in good_questions { +/// let question_str = String::from_str(&env, question); +/// if validate_question(&question_str) { +/// println!("✓ Valid question: {}", question); +/// } +/// } +/// ``` +/// +/// # Outcome Configuration +/// +/// Outcomes define the possible market results: +/// ```rust +/// # use soroban_sdk::{Env, String, Vec}; +/// # let env = Env::default(); +/// +/// // Binary outcomes (most common) +/// let binary_outcomes = Vec::from_array(&env, [ +/// String::from_str(&env, "yes"), +/// String::from_str(&env, "no") +/// ]); +/// +/// // Multiple choice outcomes +/// let multiple_outcomes = Vec::from_array(&env, [ +/// String::from_str(&env, "under_50k"), +/// String::from_str(&env, "50k_to_75k"), +/// String::from_str(&env, "75k_to_100k"), +/// String::from_str(&env, "over_100k") +/// ]); +/// +/// // Outcome validation rules: +/// // 1. Minimum 2 outcomes +/// // 2. Maximum 10 outcomes +/// // 3. No duplicate outcomes +/// // 4. Each outcome 1-50 characters +/// // 5. Clear and distinct options +/// ``` +/// +/// # Duration Planning +/// +/// Market duration affects participation and resolution: +/// ```rust +/// # use predictify_hybrid::types::MarketCreationParams; +/// +/// // Duration recommendations by market type: +/// let duration_guidelines = vec![ +/// ("Short-term price movements", 1..=7), // 1-7 days +/// ("Monthly predictions", 7..=30), // 1-4 weeks +/// ("Quarterly outcomes", 30..=90), // 1-3 months +/// ("Annual predictions", 90..=365), // 3-12 months +/// ]; +/// +/// for (market_type, duration_range) in duration_guidelines { +/// println!("{}: {} days", market_type, +/// format!("{}-{}", duration_range.start(), duration_range.end())); +/// } +/// +/// // Duration validation: +/// // - Minimum: 1 day +/// // - Maximum: 365 days (1 year) +/// // - Recommended: 7-90 days for most markets +/// ``` +/// +/// # Fee Structure +/// +/// Creation fees vary based on market characteristics: +/// ```rust +/// # use predictify_hybrid::types::MarketCreationParams; +/// +/// // Base fee calculation +/// let base_fee = 1_000_000; // 1 XLM base fee +/// +/// // Fee modifiers based on duration +/// let duration_multiplier = |days: u32| -> f64 { +/// match days { +/// 1..=7 => 1.0, // Short-term: no modifier +/// 8..=30 => 1.5, // Medium-term: 50% increase +/// 31..=90 => 2.0, // Long-term: 100% increase +/// 91..=365 => 3.0, // Very long-term: 200% increase +/// _ => 5.0, // Invalid duration: penalty +/// } +/// }; +/// +/// // Calculate total creation fee +/// let duration_days = 30; +/// let total_fee = (base_fee as f64 * duration_multiplier(duration_days)) as i128; +/// println!("Creation fee for {} days: {} stroops", duration_days, total_fee); +/// ``` +/// +/// # Common Market Templates +/// +/// Pre-configured templates for common market types: +/// ```rust +/// # use soroban_sdk::{Env, Address, String, Vec}; +/// # use predictify_hybrid::types::{MarketCreationParams, OracleConfig, OracleProvider}; +/// # let env = Env::default(); +/// # let admin = Address::generate(&env); +/// +/// // Bitcoin price threshold template +/// let btc_template = |threshold: i128, days: u32| -> MarketCreationParams { +/// MarketCreationParams::new( +/// admin.clone(), +/// String::from_str(&env, &format!("Will BTC reach ${}?", threshold / 100)), +/// Vec::from_array(&env, [ +/// String::from_str(&env, "yes"), +/// String::from_str(&env, "no") +/// ]), +/// days, +/// OracleConfig::new( +/// OracleProvider::Reflector, +/// String::from_str(&env, "BTC/USD"), +/// threshold, +/// String::from_str(&env, "gt") +/// ), +/// calculate_creation_fee(days) +/// ) +/// }; +/// +/// // Create BTC $100k market +/// let btc_100k_market = btc_template(100_000_00, 90); +/// ``` +/// +/// # Integration Points +/// +/// Market creation parameters integrate with: +/// - **Market Factory**: Creates markets from validated parameters +/// - **Fee Manager**: Processes creation fee payments +/// - **Oracle System**: Validates and configures oracle integration +/// - **Admin System**: Verifies administrator permissions +/// - **Event System**: Emits market creation events +/// - **Validation System**: Ensures parameter compliance +/// +/// # Error Handling +/// +/// Common parameter errors: +/// - **InvalidQuestion**: Question is empty, too long, or inappropriate +/// - **InvalidOutcomes**: Insufficient outcomes or duplicates +/// - **InvalidDuration**: Duration outside allowed range +/// - **InsufficientFee**: Creation fee below minimum requirement +/// - **InvalidAdmin**: Admin address is invalid or restricted +/// - **OracleConfigError**: Oracle configuration validation failed #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct MarketCreationParams { @@ -367,7 +2000,277 @@ impl MarketCreationParams { // ===== ADDITIONAL TYPES ===== -/// Community consensus data +/// Community consensus data structure for tracking collective market resolution. +/// +/// This structure captures the community's collective opinion on market outcomes, +/// providing an alternative or supplementary resolution method to oracle-based +/// resolution. It aggregates user votes, stakes, and participation to determine +/// the community's consensus on the correct market outcome. +/// +/// # Consensus Components +/// +/// **Outcome Data:** +/// - **Outcome**: The consensus outcome determined by the community +/// - **Votes**: Number of individual votes for this outcome +/// - **Total Votes**: Total number of votes across all outcomes +/// - **Percentage**: Percentage of votes for this outcome +/// +/// **Consensus Metrics:** +/// - **Confidence Level**: How confident the consensus is +/// - **Participation Rate**: Percentage of eligible users who voted +/// - **Stake Weight**: Financial weight behind the consensus +/// +/// # Consensus Calculation Methods +/// +/// **Simple Majority:** +/// - Outcome with >50% of votes wins +/// - Most straightforward method +/// - Used for clear-cut decisions +/// +/// **Stake-Weighted Consensus:** +/// - Votes weighted by stake amount +/// - Higher stakes have more influence +/// - Reduces impact of spam votes +/// +/// **Qualified Majority:** +/// - Requires >60% or >66% consensus +/// - Used for contentious decisions +/// - Higher threshold for confidence +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::types::CommunityConsensus; +/// # let env = Env::default(); +/// +/// // Create community consensus for a market outcome +/// let consensus = CommunityConsensus::new( +/// String::from_str(&env, "yes"), +/// 150, // 150 votes for "yes" +/// 200, // 200 total votes +/// 75 // 75% of votes for "yes" +/// ); +/// +/// // Display consensus information +/// println!("Community Consensus:"); +/// println!("Outcome: {}", consensus.outcome); +/// println!("Votes: {} out of {}", consensus.votes, consensus.total_votes); +/// println!("Percentage: {}%", consensus.percentage); +/// +/// // Check consensus strength +/// if consensus.is_strong_consensus() { +/// println!("Strong community consensus achieved"); +/// } else if consensus.is_majority_consensus() { +/// println!("Majority consensus reached"); +/// } else { +/// println!("No clear consensus - may need dispute resolution"); +/// } +/// +/// // Validate consensus quality +/// consensus.validate(&env)?; +/// # Ok::<(), predictify_hybrid::errors::Error>(()) +/// ``` +/// +/// # Consensus Validation +/// +/// Community consensus undergoes validation: +/// ```rust +/// # use predictify_hybrid::types::CommunityConsensus; +/// # let consensus = CommunityConsensus::default(); // Placeholder +/// +/// // Validation checks multiple aspects: +/// let validation_result = consensus.validate(&soroban_sdk::Env::default()); +/// match validation_result { +/// Ok(()) => { +/// println!("Consensus validation passed"); +/// // Consensus can be used for resolution +/// }, +/// Err(e) => { +/// println!("Consensus validation failed: {:?}", e); +/// // Handle validation errors: +/// // - InsufficientParticipation: Too few votes +/// // - InvalidPercentage: Percentage calculation error +/// // - NoMajority: No outcome has majority support +/// // - TiedOutcomes: Multiple outcomes with same vote count +/// } +/// } +/// ``` +/// +/// # Consensus Strength Analysis +/// +/// Analyze the strength and reliability of consensus: +/// ```rust +/// # use predictify_hybrid::types::CommunityConsensus; +/// # let consensus = CommunityConsensus::default(); // Placeholder +/// +/// // Consensus strength categories +/// let strength = match consensus.percentage { +/// 90..=100 => "Overwhelming Consensus", +/// 75..=89 => "Strong Consensus", +/// 60..=74 => "Clear Majority", +/// 51..=59 => "Simple Majority", +/// _ => "No Consensus" +/// }; +/// +/// println!("Consensus Strength: {}", strength); +/// +/// // Participation analysis +/// let participation_rate = consensus.calculate_participation_rate(); +/// if participation_rate >= 50 { +/// println!("High participation: {:.1}%", participation_rate); +/// } else if participation_rate >= 25 { +/// println!("Moderate participation: {:.1}%", participation_rate); +/// } else { +/// println!("Low participation: {:.1}% - consensus may be unreliable", participation_rate); +/// } +/// ``` +/// +/// # Stake-Weighted Consensus +/// +/// Calculate consensus based on financial stakes: +/// ```rust +/// # use predictify_hybrid::types::CommunityConsensus; +/// # let consensus = CommunityConsensus::default(); // Placeholder +/// +/// // Stake-weighted calculation +/// let stake_weighted_consensus = consensus.calculate_stake_weighted(); +/// +/// println!("Vote-based consensus: {}% for {}", +/// consensus.percentage, consensus.outcome); +/// println!("Stake-weighted consensus: {:.1}% for {}", +/// stake_weighted_consensus.percentage, stake_weighted_consensus.outcome); +/// +/// // Compare vote vs stake consensus +/// if consensus.outcome == stake_weighted_consensus.outcome { +/// println!("Vote and stake consensus align"); +/// } else { +/// println!("Vote and stake consensus differ - potential whale influence"); +/// } +/// ``` +/// +/// # Consensus Evolution Tracking +/// +/// Track how consensus changes over time: +/// ```rust +/// # use predictify_hybrid::types::CommunityConsensus; +/// # let consensus = CommunityConsensus::default(); // Placeholder +/// +/// // Historical consensus snapshots +/// let consensus_history = consensus.get_historical_snapshots(); +/// +/// for (timestamp, snapshot) in consensus_history { +/// println!("Time {}: {}% for {}", +/// timestamp, snapshot.percentage, snapshot.outcome); +/// } +/// +/// // Consensus stability analysis +/// let stability = consensus.analyze_stability(); +/// if stability.is_stable { +/// println!("Consensus has been stable for {} hours", stability.stable_duration_hours); +/// } else { +/// println!("Consensus is still evolving - {} changes in last 24h", stability.recent_changes); +/// } +/// ``` +/// +/// # Multi-Outcome Consensus +/// +/// Handle markets with multiple possible outcomes: +/// ```rust +/// # use predictify_hybrid::types::CommunityConsensus; +/// +/// // Calculate consensus for all outcomes +/// let all_outcomes_consensus = vec![ +/// ("outcome_a", 45, 22), // 45% of votes, 22% of stakes +/// ("outcome_b", 35, 38), // 35% of votes, 38% of stakes +/// ("outcome_c", 20, 40), // 20% of votes, 40% of stakes +/// ]; +/// +/// // Determine winner by different methods +/// let vote_winner = all_outcomes_consensus.iter() +/// .max_by_key(|(_, votes, _)| votes) +/// .map(|(outcome, _, _)| outcome); +/// +/// let stake_winner = all_outcomes_consensus.iter() +/// .max_by_key(|(_, _, stakes)| stakes) +/// .map(|(outcome, _, _)| outcome); +/// +/// println!("Vote winner: {:?}", vote_winner); +/// println!("Stake winner: {:?}", stake_winner); +/// +/// // Check for conflicts +/// if vote_winner != stake_winner { +/// println!("Conflict detected - may need hybrid resolution"); +/// } +/// ``` +/// +/// # Integration with Resolution System +/// +/// Community consensus integrates with market resolution: +/// ```rust +/// # use predictify_hybrid::types::CommunityConsensus; +/// # let consensus = CommunityConsensus::default(); // Placeholder +/// +/// // Use consensus for market resolution +/// if consensus.is_reliable() { +/// let resolution_outcome = consensus.outcome.clone(); +/// let confidence_score = consensus.calculate_confidence(); +/// +/// println!("Resolving market to: {}", resolution_outcome); +/// println!("Confidence: {:.1}%", confidence_score); +/// +/// // Apply resolution +/// apply_market_resolution(resolution_outcome, confidence_score); +/// } else { +/// println!("Consensus not reliable - using oracle or dispute resolution"); +/// } +/// ``` +/// +/// # Consensus Quality Metrics +/// +/// Evaluate the quality and reliability of consensus: +/// ```rust +/// # use predictify_hybrid::types::CommunityConsensus; +/// # let consensus = CommunityConsensus::default(); // Placeholder +/// +/// // Quality assessment +/// let quality_metrics = consensus.assess_quality(); +/// +/// println!("Consensus Quality Report:"); +/// println!("- Participation Rate: {:.1}%", quality_metrics.participation_rate); +/// println!("- Majority Strength: {:.1}%", quality_metrics.majority_strength); +/// println!("- Stake Alignment: {:.1}%", quality_metrics.stake_alignment); +/// println!("- Time Stability: {:.1}%", quality_metrics.time_stability); +/// println!("- Overall Quality: {:.1}/10", quality_metrics.overall_score); +/// +/// // Quality-based decision making +/// if quality_metrics.overall_score >= 8.0 { +/// println!("High quality consensus - safe to use for resolution"); +/// } else if quality_metrics.overall_score >= 6.0 { +/// println!("Moderate quality - consider supplementary validation"); +/// } else { +/// println!("Low quality consensus - use alternative resolution method"); +/// } +/// ``` +/// +/// # Integration Points +/// +/// Community consensus integrates with: +/// - **Resolution System**: Provides community-based resolution outcomes +/// - **Voting System**: Aggregates individual votes into collective consensus +/// - **Dispute System**: Offers alternative when oracle resolution is disputed +/// - **Analytics System**: Tracks consensus patterns and quality +/// - **Governance System**: Enables community-driven market resolution +/// - **Event System**: Emits consensus updates and final determinations +/// +/// # Error Handling +/// +/// Common consensus errors: +/// - **InsufficientVotes**: Too few votes to establish reliable consensus +/// - **TiedOutcomes**: Multiple outcomes with identical vote counts +/// - **InvalidPercentage**: Percentage calculations don't sum to 100% +/// - **LowParticipation**: Participation rate below minimum threshold +/// - **ConsensusInstability**: Consensus changes too frequently to be reliable #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct CommunityConsensus { diff --git a/contracts/predictify-hybrid/src/utils.rs b/contracts/predictify-hybrid/src/utils.rs index 35d00f68..7b6a25b6 100644 --- a/contracts/predictify-hybrid/src/utils.rs +++ b/contracts/predictify-hybrid/src/utils.rs @@ -20,7 +20,175 @@ use crate::errors::Error; // ===== TIME AND DATE UTILITIES ===== -/// Time and date utility functions +/// Comprehensive time and date utility functions for market lifecycle management. +/// +/// This utility class provides essential time-related operations for prediction markets, +/// including duration calculations, timestamp validation, deadline management, and +/// human-readable time formatting. All functions are designed to work with Stellar +/// blockchain timestamps and market timing requirements. +/// +/// # Core Functionality +/// +/// **Time Conversions:** +/// - Convert days, hours, minutes to seconds +/// - Calculate time differences between timestamps +/// - Format durations in human-readable format +/// +/// **Timestamp Validation:** +/// - Check if timestamps are in future or past +/// - Validate deadline status +/// - Ensure duration values are within acceptable ranges +/// +/// **Market Timing:** +/// - Calculate time until market deadlines +/// - Validate market duration parameters +/// - Support market extension calculations +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::utils::TimeUtils; +/// # let env = Env::default(); +/// +/// // Convert market duration to seconds +/// let market_duration_days = 30; +/// let duration_seconds = TimeUtils::days_to_seconds(market_duration_days); +/// println!("Market duration: {} seconds", duration_seconds); +/// +/// // Check if market has ended +/// let current_time = env.ledger().timestamp(); +/// let market_end_time = current_time + TimeUtils::days_to_seconds(7); // 7 days from now +/// +/// if TimeUtils::is_deadline_passed(current_time, market_end_time) { +/// println!("Market has ended"); +/// } else { +/// let time_remaining = TimeUtils::time_until_deadline(current_time, market_end_time); +/// let formatted_time = TimeUtils::format_duration(&env, time_remaining); +/// println!("Time remaining: {}", formatted_time); +/// } +/// +/// // Validate market duration +/// let proposed_duration = 45; // days +/// if TimeUtils::validate_duration(&proposed_duration) { +/// println!("Duration is valid"); +/// } else { +/// println!("Duration exceeds maximum allowed"); +/// } +/// ``` +/// +/// # Time Conversion Utilities +/// +/// Convert various time units to seconds for blockchain operations: +/// ```rust +/// # use predictify_hybrid::utils::TimeUtils; +/// +/// // Common time conversions +/// let one_day = TimeUtils::days_to_seconds(1); // 86,400 seconds +/// let one_hour = TimeUtils::hours_to_seconds(1); // 3,600 seconds +/// let one_minute = TimeUtils::minutes_to_seconds(1); // 60 seconds +/// +/// // Market duration examples +/// let short_market = TimeUtils::days_to_seconds(7); // 1 week +/// let medium_market = TimeUtils::days_to_seconds(30); // 1 month +/// let long_market = TimeUtils::days_to_seconds(90); // 3 months +/// +/// println!("Short market: {} seconds", short_market); +/// println!("Medium market: {} seconds", medium_market); +/// println!("Long market: {} seconds", long_market); +/// ``` +/// +/// # Timestamp Validation +/// +/// Validate timestamps for market operations: +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::utils::TimeUtils; +/// # let env = Env::default(); +/// +/// let current_time = env.ledger().timestamp(); +/// let future_time = current_time + TimeUtils::days_to_seconds(30); +/// let past_time = current_time - TimeUtils::days_to_seconds(30); +/// +/// // Timestamp validation +/// assert!(TimeUtils::is_future_timestamp(current_time, future_time)); +/// assert!(TimeUtils::is_past_timestamp(current_time, past_time)); +/// assert!(!TimeUtils::is_deadline_passed(current_time, future_time)); +/// assert!(TimeUtils::is_deadline_passed(current_time, past_time)); +/// +/// // Calculate time differences +/// let diff_future = TimeUtils::time_difference(current_time, future_time); +/// let diff_past = TimeUtils::time_difference(current_time, past_time); +/// +/// println!("Time to future: {} seconds", diff_future); +/// println!("Time from past: {} seconds", diff_past); +/// ``` +/// +/// # Duration Formatting +/// +/// Format time durations for user interfaces: +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::utils::TimeUtils; +/// # let env = Env::default(); +/// +/// // Format various durations +/// let durations = vec![ +/// TimeUtils::minutes_to_seconds(45), // "45m" +/// TimeUtils::hours_to_seconds(2), // "2h 0m" +/// TimeUtils::days_to_seconds(1), // "1d 0h 0m" +/// TimeUtils::days_to_seconds(7) + TimeUtils::hours_to_seconds(12), // "7d 12h 0m" +/// ]; +/// +/// for duration in durations { +/// let formatted = TimeUtils::format_duration(&env, duration); +/// println!("Duration: {}", formatted); +/// } +/// ``` +/// +/// # Market Deadline Management +/// +/// Manage market deadlines and extensions: +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::utils::TimeUtils; +/// # let env = Env::default(); +/// +/// let current_time = env.ledger().timestamp(); +/// let market_end = current_time + TimeUtils::days_to_seconds(7); +/// +/// // Check time until deadline +/// let time_remaining = TimeUtils::time_until_deadline(current_time, market_end); +/// if time_remaining > 0 { +/// let formatted_remaining = TimeUtils::format_duration(&env, time_remaining); +/// println!("Market ends in: {}", formatted_remaining); +/// +/// // Check if extension is needed (less than 24 hours remaining) +/// if time_remaining < TimeUtils::days_to_seconds(1) { +/// println!("Market may need extension for more participation"); +/// } +/// } else { +/// println!("Market has ended"); +/// } +/// ``` +/// +/// # Integration Points +/// +/// TimeUtils integrates with: +/// - **Market Manager**: Market duration and deadline validation +/// - **Extension System**: Calculate extension durations +/// - **Resolution System**: Timing for oracle resolution +/// - **Event System**: Timestamp formatting for events +/// - **Admin System**: Validate administrative timing operations +/// - **User Interface**: Human-readable time displays +/// +/// # Performance Considerations +/// +/// All time operations are optimized for blockchain execution: +/// - **Constant Time**: All calculations are O(1) operations +/// - **No External Calls**: Pure mathematical operations +/// - **Memory Efficient**: Minimal memory allocation +/// - **Gas Optimized**: Low computational overhead pub struct TimeUtils; impl TimeUtils { @@ -105,7 +273,244 @@ impl TimeUtils { // ===== STRING UTILITIES ===== -/// String manipulation and formatting utilities +/// Comprehensive string manipulation and formatting utilities for contract operations. +/// +/// This utility class provides essential string operations for prediction markets, +/// including validation, formatting, sanitization, and manipulation functions. +/// All operations are designed to work with Soroban SDK String types while +/// maintaining compatibility with blockchain constraints. +/// +/// # Core Functionality +/// +/// **String Transformation:** +/// - Case conversion (uppercase/lowercase) +/// - Trimming and truncation +/// - String splitting and joining +/// +/// **String Validation:** +/// - Length validation with min/max constraints +/// - Content validation and sanitization +/// - Format verification +/// +/// **String Analysis:** +/// - Substring searching and matching +/// - Prefix and suffix checking +/// - Content replacement operations +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, String, Vec}; +/// # use predictify_hybrid::utils::StringUtils; +/// # let env = Env::default(); +/// +/// // String validation for market questions +/// let market_question = String::from_str(&env, "Will Bitcoin reach $100,000?"); +/// +/// // Validate question length +/// match StringUtils::validate_string_length(&market_question, 10, 200) { +/// Ok(()) => println!("Question length is valid"), +/// Err(e) => println!("Question too short or too long: {:?}", e), +/// } +/// +/// // Sanitize user input +/// let sanitized_question = StringUtils::sanitize_string(&market_question); +/// println!("Sanitized question: {}", sanitized_question); +/// +/// // String manipulation +/// let trimmed = StringUtils::trim(&market_question); +/// let truncated = StringUtils::truncate(&market_question, 50); +/// +/// println!("Original: {}", market_question); +/// println!("Trimmed: {}", trimmed); +/// println!("Truncated: {}", truncated); +/// ``` +/// +/// # String Validation +/// +/// Validate strings for market operations: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::utils::StringUtils; +/// # let env = Env::default(); +/// +/// // Market question validation +/// let questions = vec![ +/// String::from_str(&env, "Will BTC hit $100k?"), // Valid +/// String::from_str(&env, "BTC?"), // Too short +/// String::from_str(&env, &"x".repeat(300)), // Too long +/// ]; +/// +/// for question in questions { +/// match StringUtils::validate_string_length(&question, 10, 200) { +/// Ok(()) => println!("✓ Valid question: {}", question), +/// Err(_) => println!("✗ Invalid question length"), +/// } +/// } +/// +/// // Outcome validation +/// let outcomes = vec![ +/// String::from_str(&env, "yes"), +/// String::from_str(&env, "no"), +/// String::from_str(&env, "maybe"), +/// ]; +/// +/// for outcome in outcomes { +/// if StringUtils::validate_string_length(&outcome, 1, 50).is_ok() { +/// println!("Valid outcome: {}", outcome); +/// } +/// } +/// ``` +/// +/// # String Manipulation +/// +/// Transform and manipulate strings: +/// ```rust +/// # use soroban_sdk::{Env, String, Vec}; +/// # use predictify_hybrid::utils::StringUtils; +/// # let env = Env::default(); +/// +/// let original = String::from_str(&env, " Bitcoin Price Prediction "); +/// +/// // Basic transformations +/// let uppercase = StringUtils::to_uppercase(&original); +/// let lowercase = StringUtils::to_lowercase(&original); +/// let trimmed = StringUtils::trim(&original); +/// let truncated = StringUtils::truncate(&original, 15); +/// +/// println!("Original: '{}'", original); +/// println!("Uppercase: '{}'", uppercase); +/// println!("Lowercase: '{}'", lowercase); +/// println!("Trimmed: '{}'", trimmed); +/// println!("Truncated: '{}'", truncated); +/// +/// // String replacement +/// let replaced = StringUtils::replace(&original, "Bitcoin", "BTC"); +/// println!("Replaced: '{}'", replaced); +/// ``` +/// +/// # String Analysis +/// +/// Analyze string content and structure: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::utils::StringUtils; +/// # let env = Env::default(); +/// +/// let text = String::from_str(&env, "Will Bitcoin reach $100,000 by 2024?"); +/// +/// // Content analysis +/// let contains_bitcoin = StringUtils::contains(&text, "Bitcoin"); +/// let starts_with_will = StringUtils::starts_with(&text, "Will"); +/// let ends_with_question = StringUtils::ends_with(&text, "?"); +/// +/// println!("Contains 'Bitcoin': {}", contains_bitcoin); +/// println!("Starts with 'Will': {}", starts_with_will); +/// println!("Ends with '?': {}", ends_with_question); +/// +/// // Pattern validation for market questions +/// if starts_with_will && ends_with_question { +/// println!("Question follows proper format"); +/// } else { +/// println!("Question format needs improvement"); +/// } +/// ``` +/// +/// # String Splitting and Joining +/// +/// Split and join strings for data processing: +/// ```rust +/// # use soroban_sdk::{Env, String, Vec}; +/// # use predictify_hybrid::utils::StringUtils; +/// # let env = Env::default(); +/// +/// // Split comma-separated outcomes +/// let outcomes_str = String::from_str(&env, "yes,no,maybe"); +/// let outcomes_vec = StringUtils::split(&outcomes_str, ","); +/// +/// println!("Split outcomes:"); +/// for outcome in outcomes_vec.iter() { +/// println!("- {}", outcome); +/// } +/// +/// // Join outcomes back together +/// let mut outcomes = Vec::new(&env); +/// outcomes.push_back(String::from_str(&env, "yes")); +/// outcomes.push_back(String::from_str(&env, "no")); +/// outcomes.push_back(String::from_str(&env, "uncertain")); +/// +/// let joined = StringUtils::join(&outcomes, " | "); +/// println!("Joined outcomes: {}", joined); +/// ``` +/// +/// # String Sanitization +/// +/// Sanitize user input for security: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::utils::StringUtils; +/// # let env = Env::default(); +/// +/// // Sanitize potentially unsafe input +/// let unsafe_inputs = vec![ +/// String::from_str(&env, "Will BTC reach $100k?"), +/// String::from_str(&env, "Question with special chars: @#$%^&*()"), +/// String::from_str(&env, "Normal question about Bitcoin price?"), +/// ]; +/// +/// for input in unsafe_inputs { +/// let sanitized = StringUtils::sanitize_string(&input); +/// println!("Original: {}", input); +/// println!("Sanitized: {}", sanitized); +/// println!(); +/// } +/// ``` +/// +/// # Random String Generation +/// +/// Generate random strings for testing and IDs: +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::utils::StringUtils; +/// # let env = Env::default(); +/// +/// // Generate random strings for testing +/// let random_id = StringUtils::generate_random_string(&env, 10); +/// let random_token = StringUtils::generate_random_string(&env, 32); +/// +/// println!("Random ID: {}", random_id); +/// println!("Random token: {}", random_token); +/// +/// // Use in market creation for unique identifiers +/// let market_id = StringUtils::generate_random_string(&env, 16); +/// println!("Generated market ID: {}", market_id); +/// ``` +/// +/// # Integration Points +/// +/// StringUtils integrates with: +/// - **Market Creation**: Validate questions and outcomes +/// - **User Input**: Sanitize and validate user-provided data +/// - **Event System**: Format event messages and descriptions +/// - **Admin System**: Validate administrative input +/// - **Oracle System**: Format and validate oracle feed IDs +/// - **Dispute System**: Process dispute reasons and evidence +/// +/// # Soroban SDK Limitations +/// +/// Note on current implementation limitations: +/// - Some string operations return placeholders due to Soroban SDK constraints +/// - Case conversion operations are simplified +/// - Complex string manipulations may need custom implementations +/// - Future SDK updates may provide enhanced string capabilities +/// +/// # Performance Considerations +/// +/// String operations are optimized for blockchain execution: +/// - **Memory Efficient**: Minimal string copying +/// - **Gas Optimized**: Simple operations preferred +/// - **Validation First**: Early validation prevents expensive operations +/// - **Immutable Operations**: Preserve original strings when possible pub struct StringUtils; impl StringUtils { @@ -228,7 +633,262 @@ impl StringUtils { // ===== NUMERIC UTILITIES ===== -/// Numeric calculation utilities +/// Comprehensive numeric calculation utilities for financial and mathematical operations. +/// +/// This utility class provides essential mathematical operations for prediction markets, +/// including percentage calculations, statistical functions, financial computations, +/// and numeric validation. All operations are optimized for blockchain execution +/// and handle large integer values common in cryptocurrency applications. +/// +/// # Core Functionality +/// +/// **Basic Mathematics:** +/// - Percentage calculations and conversions +/// - Rounding and clamping operations +/// - Range validation and boundary checking +/// +/// **Statistical Operations:** +/// - Weighted averages for stake calculations +/// - Square root approximations +/// - Absolute difference calculations +/// +/// **Financial Calculations:** +/// - Simple interest computations +/// - Fee calculations and distributions +/// - Stake and payout calculations +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Vec}; +/// # use predictify_hybrid::utils::NumericUtils; +/// # let env = Env::default(); +/// +/// // Calculate market participation percentage +/// let user_stake = 1_000_000; // 1 XLM in stroops +/// let total_stakes = 10_000_000; // 10 XLM total +/// let participation_pct = NumericUtils::calculate_percentage( +/// &user_stake, &100, &total_stakes +/// ); +/// println!("User participation: {}%", participation_pct); +/// +/// // Validate stake amount is within acceptable range +/// let min_stake = 100_000; // 0.1 XLM +/// let max_stake = 100_000_000; // 100 XLM +/// +/// if NumericUtils::is_within_range(&user_stake, &min_stake, &max_stake) { +/// println!("Stake amount is valid"); +/// } else { +/// let clamped_stake = NumericUtils::clamp(&user_stake, &min_stake, &max_stake); +/// println!("Stake clamped to: {} stroops", clamped_stake); +/// } +/// +/// // Calculate weighted consensus +/// let mut votes = Vec::new(&env); +/// votes.push_back(75); // 75% confidence +/// votes.push_back(80); // 80% confidence +/// votes.push_back(90); // 90% confidence +/// +/// let mut weights = Vec::new(&env); +/// weights.push_back(1_000_000); // 1 XLM stake +/// weights.push_back(2_000_000); // 2 XLM stake +/// weights.push_back(3_000_000); // 3 XLM stake +/// +/// let weighted_consensus = NumericUtils::weighted_average(&votes, &weights); +/// println!("Weighted consensus: {}%", weighted_consensus); +/// ``` +/// +/// # Percentage Calculations +/// +/// Calculate percentages for various market operations: +/// ```rust +/// # use predictify_hybrid::utils::NumericUtils; +/// +/// // Market fee calculations +/// let transaction_amount = 5_000_000; // 5 XLM +/// let fee_rate = 2; // 2% +/// let fee_amount = NumericUtils::calculate_percentage( +/// &fee_rate, &transaction_amount, &100 +/// ); +/// println!("Transaction fee: {} stroops", fee_amount); +/// +/// // Payout distribution calculations +/// let total_pool = 50_000_000; // 50 XLM prize pool +/// let winner_percentage = 80; // Winners get 80% +/// let winner_pool = NumericUtils::calculate_percentage( +/// &winner_percentage, &total_pool, &100 +/// ); +/// println!("Winner pool: {} stroops", winner_pool); +/// +/// // Participation rate calculations +/// let active_users = 150; +/// let total_users = 200; +/// let participation_rate = NumericUtils::calculate_percentage( +/// &active_users, &100, &total_users +/// ); +/// println!("Participation rate: {}%", participation_rate); +/// ``` +/// +/// # Range Operations +/// +/// Validate and constrain numeric values: +/// ```rust +/// # use predictify_hybrid::utils::NumericUtils; +/// +/// // Stake validation +/// let proposed_stakes = vec![50_000, 1_000_000, 150_000_000, 500_000]; +/// let min_stake = 100_000; // 0.1 XLM minimum +/// let max_stake = 100_000_000; // 100 XLM maximum +/// +/// for stake in proposed_stakes { +/// if NumericUtils::is_within_range(&stake, &min_stake, &max_stake) { +/// println!("✓ Valid stake: {} stroops", stake); +/// } else { +/// let clamped = NumericUtils::clamp(&stake, &min_stake, &max_stake); +/// println!("✗ Invalid stake {} clamped to {}", stake, clamped); +/// } +/// } +/// +/// // Price threshold validation +/// let price_thresholds = vec![0, 50_000_00, 1_000_000_00, -100]; +/// let min_price = 1_00; // $0.01 minimum +/// let max_price = 10_000_000_00; // $10M maximum +/// +/// for price in price_thresholds { +/// let valid_price = NumericUtils::clamp(&price, &min_price, &max_price); +/// println!("Price {} -> {}", price, valid_price); +/// } +/// ``` +/// +/// # Statistical Calculations +/// +/// Perform statistical operations for market analysis: +/// ```rust +/// # use soroban_sdk::{Env, Vec}; +/// # use predictify_hybrid::utils::NumericUtils; +/// # let env = Env::default(); +/// +/// // Calculate stake-weighted average confidence +/// let mut confidence_scores = Vec::new(&env); +/// confidence_scores.push_back(85); // User 1: 85% confidence +/// confidence_scores.push_back(92); // User 2: 92% confidence +/// confidence_scores.push_back(78); // User 3: 78% confidence +/// +/// let mut stake_weights = Vec::new(&env); +/// stake_weights.push_back(1_000_000); // User 1: 1 XLM +/// stake_weights.push_back(5_000_000); // User 2: 5 XLM (higher weight) +/// stake_weights.push_back(2_000_000); // User 3: 2 XLM +/// +/// let weighted_confidence = NumericUtils::weighted_average( +/// &confidence_scores, &stake_weights +/// ); +/// println!("Market confidence: {}%", weighted_confidence); +/// +/// // Calculate price volatility (using absolute differences) +/// let prices = vec![50_000_00, 52_000_00, 48_000_00, 51_000_00]; +/// let mut total_volatility = 0; +/// +/// for i in 1..prices.len() { +/// let diff = NumericUtils::abs_difference(&prices[i], &prices[i-1]); +/// total_volatility += diff; +/// } +/// +/// let avg_volatility = total_volatility / (prices.len() as i128 - 1); +/// println!("Average price volatility: {} cents", avg_volatility); +/// ``` +/// +/// # Financial Calculations +/// +/// Perform financial computations for market economics: +/// ```rust +/// # use predictify_hybrid::utils::NumericUtils; +/// +/// // Calculate interest on staked amounts +/// let principal = 10_000_000; // 10 XLM staked +/// let annual_rate = 5; // 5% annual interest +/// let periods = 12; // 12 months +/// +/// let interest_earned = NumericUtils::simple_interest( +/// &principal, &annual_rate, &periods +/// ); +/// println!("Interest earned: {} stroops", interest_earned); +/// +/// // Fee distribution calculations +/// let total_fees = 1_000_000; // 1 XLM in fees +/// let platform_share = 30; // 30% to platform +/// let oracle_share = 20; // 20% to oracle +/// let community_share = 50; // 50% to community +/// +/// let platform_fee = NumericUtils::calculate_percentage( +/// &platform_share, &total_fees, &100 +/// ); +/// let oracle_fee = NumericUtils::calculate_percentage( +/// &oracle_share, &total_fees, &100 +/// ); +/// let community_fee = NumericUtils::calculate_percentage( +/// &community_share, &total_fees, &100 +/// ); +/// +/// println!("Platform fee: {} stroops", platform_fee); +/// println!("Oracle fee: {} stroops", oracle_fee); +/// println!("Community fee: {} stroops", community_fee); +/// ``` +/// +/// # Rounding and Approximation +/// +/// Handle rounding for display and calculation purposes: +/// ```rust +/// # use predictify_hybrid::utils::NumericUtils; +/// +/// // Round stakes to nearest 0.1 XLM (100,000 stroops) +/// let raw_stakes = vec![1_234_567, 2_876_543, 999_999]; +/// let rounding_unit = 100_000; // 0.1 XLM +/// +/// for stake in raw_stakes { +/// let rounded = NumericUtils::round_to_nearest(&stake, &rounding_unit); +/// println!("Stake {} rounded to {}", stake, rounded); +/// } +/// +/// // Calculate square root for standard deviation approximations +/// let variance = 1_000_000; // Variance in price movements +/// let std_deviation = NumericUtils::sqrt(&variance); +/// println!("Standard deviation: {}", std_deviation); +/// +/// // Round prices to nearest cent +/// let raw_prices = vec![50_123_45, 75_678_90, 100_001_23]; +/// let cent_rounding = 1; // Round to nearest cent +/// +/// for price in raw_prices { +/// let rounded_price = NumericUtils::round_to_nearest(&price, ¢_rounding); +/// println!("Price {} rounded to {}", price, rounded_price); +/// } +/// ``` +/// +/// # Integration Points +/// +/// NumericUtils integrates with: +/// - **Market Manager**: Stake and fee calculations +/// - **Resolution System**: Confidence scoring and weighted averages +/// - **Fee Manager**: Fee distribution and percentage calculations +/// - **Oracle System**: Price validation and range checking +/// - **Analytics System**: Statistical calculations and trend analysis +/// - **Payout System**: Winner distribution calculations +/// +/// # Performance Considerations +/// +/// Numeric operations are optimized for blockchain execution: +/// - **Integer Arithmetic**: All operations use integer math for precision +/// - **Overflow Protection**: Safe arithmetic operations prevent overflow +/// - **Gas Efficient**: Minimal computational overhead +/// - **Memory Optimized**: No dynamic memory allocation in calculations +/// +/// # Precision and Accuracy +/// +/// All calculations maintain precision for financial operations: +/// - **Stroops Precision**: All amounts in smallest unit (stroops) +/// - **Percentage Precision**: Integer percentages for exact calculations +/// - **Rounding Control**: Explicit rounding behavior +/// - **Range Validation**: Prevent invalid or extreme values pub struct NumericUtils; impl NumericUtils { @@ -323,7 +983,338 @@ impl NumericUtils { // ===== VALIDATION UTILITIES ===== -/// Validation utility functions +/// Comprehensive validation utility functions for data integrity and security. +/// +/// This utility class provides essential validation operations for prediction markets, +/// including input validation, format checking, security validation, and data +/// integrity verification. All validations are designed to prevent invalid data +/// from entering the system and ensure contract security. +/// +/// # Core Functionality +/// +/// **Numeric Validation:** +/// - Positive number validation +/// - Range checking and boundary validation +/// - Timestamp and duration validation +/// +/// **Format Validation:** +/// - Address format verification +/// - String format validation +/// - URL and identifier validation +/// +/// **Security Validation:** +/// - Input sanitization checks +/// - Injection prevention +/// - Access control validation +/// +/// # Example Usage +/// +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::utils::ValidationUtils; +/// # let env = Env::default(); +/// +/// // Validate market creation parameters +/// let stake_amount = 1_000_000; // 1 XLM +/// let min_stake = 100_000; // 0.1 XLM minimum +/// let max_stake = 100_000_000; // 100 XLM maximum +/// +/// // Validate stake amount +/// if ValidationUtils::validate_positive_number(&stake_amount) { +/// println!("✓ Stake amount is positive"); +/// } +/// +/// if ValidationUtils::validate_number_range(&stake_amount, &min_stake, &max_stake) { +/// println!("✓ Stake amount is within valid range"); +/// } else { +/// println!("✗ Stake amount outside valid range"); +/// } +/// +/// // Validate market end time +/// let market_end_time = env.ledger().timestamp() + (30 * 24 * 60 * 60); // 30 days +/// if ValidationUtils::validate_future_timestamp(&env, &market_end_time) { +/// println!("✓ Market end time is in the future"); +/// } +/// +/// // Validate admin address +/// let admin_address = Address::generate(&env); +/// match ValidationUtils::validate_address(&admin_address) { +/// Ok(()) => println!("✓ Admin address is valid"), +/// Err(e) => println!("✗ Invalid admin address: {:?}", e), +/// } +/// ``` +/// +/// # Numeric Validation +/// +/// Validate numeric inputs for market operations: +/// ```rust +/// # use predictify_hybrid::utils::ValidationUtils; +/// +/// // Validate positive amounts +/// let amounts = vec![1_000_000, 0, -500_000, 50_000_000]; +/// +/// for amount in amounts { +/// if ValidationUtils::validate_positive_number(&amount) { +/// println!("✓ Amount {} is positive", amount); +/// } else { +/// println!("✗ Amount {} is not positive", amount); +/// } +/// } +/// +/// // Validate fee percentages +/// let fee_percentages = vec![0, 1, 5, 10, 50, 101, -5]; +/// let min_fee = 0; +/// let max_fee = 10; // Maximum 10% fee +/// +/// for fee in fee_percentages { +/// if ValidationUtils::validate_number_range(&fee, &min_fee, &max_fee) { +/// println!("✓ Fee {}% is valid", fee); +/// } else { +/// println!("✗ Fee {}% is outside valid range (0-10%)", fee); +/// } +/// } +/// +/// // Validate market duration +/// let durations = vec![0, 1, 7, 30, 90, 365, 400]; // days +/// let min_duration = 1; +/// let max_duration = 365; +/// +/// for duration in durations { +/// if ValidationUtils::validate_number_range(&duration, &min_duration, &max_duration) { +/// println!("✓ Duration {} days is valid", duration); +/// } else { +/// println!("✗ Duration {} days is invalid", duration); +/// } +/// } +/// ``` +/// +/// # Timestamp Validation +/// +/// Validate timestamps for market timing: +/// ```rust +/// # use soroban_sdk::Env; +/// # use predictify_hybrid::utils::{ValidationUtils, TimeUtils}; +/// # let env = Env::default(); +/// +/// let current_time = env.ledger().timestamp(); +/// +/// // Test various timestamps +/// let timestamps = vec![ +/// current_time - 3600, // 1 hour ago (invalid) +/// current_time, // Now (invalid) +/// current_time + 3600, // 1 hour from now (valid) +/// current_time + TimeUtils::days_to_seconds(30), // 30 days (valid) +/// current_time + TimeUtils::days_to_seconds(400), // 400 days (may be invalid) +/// ]; +/// +/// for timestamp in timestamps { +/// if ValidationUtils::validate_future_timestamp(&env, ×tamp) { +/// let time_diff = timestamp - current_time; +/// let formatted = TimeUtils::format_duration(&env, time_diff); +/// println!("✓ Timestamp is {} in the future", formatted); +/// } else { +/// println!("✗ Timestamp is not in the future"); +/// } +/// } +/// ``` +/// +/// # Address Validation +/// +/// Validate Stellar addresses for security: +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::utils::ValidationUtils; +/// # let env = Env::default(); +/// +/// // Generate test addresses +/// let valid_address = Address::generate(&env); +/// +/// // Validate addresses +/// let addresses = vec![valid_address]; +/// +/// for address in addresses { +/// match ValidationUtils::validate_address(&address) { +/// Ok(()) => { +/// println!("✓ Address is valid: {}", address); +/// }, +/// Err(e) => { +/// println!("✗ Address validation failed: {:?}", e); +/// } +/// } +/// } +/// +/// // Address validation in market operations +/// let market_admin = Address::generate(&env); +/// let market_participant = Address::generate(&env); +/// +/// // Validate admin address +/// if ValidationUtils::validate_address(&market_admin).is_ok() { +/// println!("Market admin address is valid"); +/// } +/// +/// // Validate participant address +/// if ValidationUtils::validate_address(&market_participant).is_ok() { +/// println!("Participant address is valid"); +/// } +/// ``` +/// +/// # String Format Validation +/// +/// Validate string formats for various inputs: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::utils::ValidationUtils; +/// # let env = Env::default(); +/// +/// // Validate email formats (basic validation) +/// let emails = vec![ +/// String::from_str(&env, "user@example.com"), +/// String::from_str(&env, "invalid-email"), +/// String::from_str(&env, "test@domain.org"), +/// String::from_str(&env, "@invalid.com"), +/// ]; +/// +/// for email in emails { +/// if ValidationUtils::validate_email(&email) { +/// println!("✓ Valid email: {}", email); +/// } else { +/// println!("✗ Invalid email: {}", email); +/// } +/// } +/// +/// // Validate URL formats (basic validation) +/// let urls = vec![ +/// String::from_str(&env, "https://example.com"), +/// String::from_str(&env, "http://test.org"), +/// String::from_str(&env, "invalid-url"), +/// String::from_str(&env, "ftp://files.com"), +/// ]; +/// +/// for url in urls { +/// if ValidationUtils::validate_url(&url) { +/// println!("✓ Valid URL: {}", url); +/// } else { +/// println!("✗ Invalid URL: {}", url); +/// } +/// } +/// ``` +/// +/// # Market-Specific Validation +/// +/// Validate market creation and operation parameters: +/// ```rust +/// # use soroban_sdk::{Env, Address, String}; +/// # use predictify_hybrid::utils::ValidationUtils; +/// # let env = Env::default(); +/// +/// // Validate market parameters +/// struct MarketParams { +/// admin: Address, +/// creation_fee: i128, +/// duration_days: i128, +/// min_stake: i128, +/// max_stake: i128, +/// } +/// +/// let params = MarketParams { +/// admin: Address::generate(&env), +/// creation_fee: 5_000_000, // 5 XLM +/// duration_days: 30, +/// min_stake: 100_000, // 0.1 XLM +/// max_stake: 100_000_000, // 100 XLM +/// }; +/// +/// // Comprehensive validation +/// let mut validation_errors = Vec::new(); +/// +/// // Validate admin address +/// if ValidationUtils::validate_address(¶ms.admin).is_err() { +/// validation_errors.push("Invalid admin address"); +/// } +/// +/// // Validate creation fee +/// if !ValidationUtils::validate_positive_number(¶ms.creation_fee) { +/// validation_errors.push("Creation fee must be positive"); +/// } +/// +/// // Validate duration +/// if !ValidationUtils::validate_number_range(¶ms.duration_days, &1, &365) { +/// validation_errors.push("Duration must be 1-365 days"); +/// } +/// +/// // Validate stake range +/// if !ValidationUtils::validate_positive_number(¶ms.min_stake) { +/// validation_errors.push("Minimum stake must be positive"); +/// } +/// +/// if params.min_stake >= params.max_stake { +/// validation_errors.push("Minimum stake must be less than maximum stake"); +/// } +/// +/// if validation_errors.is_empty() { +/// println!("✓ All market parameters are valid"); +/// } else { +/// println!("✗ Validation errors:"); +/// for error in validation_errors { +/// println!(" - {}", error); +/// } +/// } +/// ``` +/// +/// # Security Validation +/// +/// Perform security-focused validation: +/// ```rust +/// # use soroban_sdk::{Env, String}; +/// # use predictify_hybrid::utils::ValidationUtils; +/// # let env = Env::default(); +/// +/// // Validate user input for potential security issues +/// let user_inputs = vec![ +/// String::from_str(&env, "Normal market question?"), +/// String::from_str(&env, ""), +/// String::from_str(&env, "'; DROP TABLE markets; --"), +/// String::from_str(&env, "Will Bitcoin reach $100,000?"), +/// ]; +/// +/// for input in user_inputs { +/// // Basic security validation (simplified) +/// let contains_script = input.to_string().contains("