Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 99 additions & 14 deletions API_DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,24 +252,109 @@ This document provides a complete API reference for the Predictify Hybrid smart

**Purpose**: Read-only query interface for retrieving market, user, and contract state information.

### Primary Functions
**Verification method**: `grep -n "pub fn <name>" contracts/predictify-hybrid/src/*.rs`

### Status Key

- **Implemented** — function exists and returns real data.
- **Stubbed** — function exists but returns a placeholder / zero value; linked to tracking issue.
- **Planned** — no implementation exists yet.

---

### QueryManager — Implemented Functions

All functions below live on `QueryManager` in `queries.rs` unless a different call path is noted.

#### Admin & Multisig Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_admin_role` | `(env, admin: Address) → Result<AdminRole, Error>` | **Implemented** |
| `query_admin_roles` | `(env) → Result<Map<Address, AdminRole>, Error>` | **Implemented** |
| `query_has_permission` | `(env, admin: Address, action: String) → Result<bool, Error>` | **Implemented** |
| `query_multisig_config` | `(env) → Result<MultisigConfig, Error>` | **Implemented** |
| `query_requires_multisig` | `(env, action: String) → Result<bool, Error>` | **Implemented** |

`get_permissions_for_role` is **Implemented** but not surfaced via `QueryManager`; call `AdminRoleManager::get_permissions_for_role(env, role)` in `admin.rs` directly.

#### Oracle Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_approved_oracles` | `(env) → Result<Vec<Address>, Error>` | **Implemented** |
| `query_oracle_metadata` | `(env, oracle: Address) → Result<OracleMetadata, Error>` | **Implemented** |

`get_oracle_resolution` is **Stubbed** — `ResolutionManager::get_oracle_resolution(env, market_id)` in `resolution.rs` always returns `Ok(None)`; full persistence not yet implemented (see issue #595).

`get_global_oracle_config` is **Planned** — no implementation exists in any module.

#### Dispute Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_dispute_stats` | `(env, market_id: Symbol) → Result<DisputeStats, Error>` | **Implemented** |
| `query_market_disputes` | `(env, market_id: Symbol) → Result<Vec<Dispute>, Error>` | **Implemented** |
| `query_dispute_votes` | `(env, dispute_id: Symbol) → Result<Vec<DisputeVote>, Error>` | **Implemented** |

**QueryManager**
`get_dispute_timeout_status` is **Implemented** but not surfaced via `QueryManager`; call `DisputeManager::get_dispute_timeout_status(env, dispute_id)` in `disputes.rs` directly.

**Market/Event Queries**
- `query_event_details(env, market_id)` - Get complete market information
- `query_event_status(env, market_id)` - Get market status and end time
- `get_all_markets(env)` - Get list of all market IDs
#### Governance Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_proposals` | `(env) → Result<Vec<Symbol>, Error>` | **Implemented** — delegates to `GovernanceContract::list_proposals` in `governance.rs` |
| `query_proposal_details` | `(env, proposal_id: Symbol) → Result<GovernanceProposal, Error>` | **Implemented** — delegates to `GovernanceContract::get_proposal` in `governance.rs` |

#### Market / Event Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_event_details` | `(env, market_id: Symbol) → Result<EventDetailsQuery, Error>` | **Implemented** — includes `created_at` |
| `query_event_status` | `(env, market_id: Symbol) → Result<(MarketStatus, u64), Error>` | **Implemented** |
| `get_all_markets` | `(env) → Result<Vec<Symbol>, Error>` | **Implemented** |
| `get_all_markets_paged` | `(env, cursor: u32, limit: u32) → Result<PagedMarketIds, Error>` | **Implemented** |

#### User Bet Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_user_bet` | `(env, user: Address, market_id: Symbol) → Result<UserBetQuery, Error>` | **Implemented** — includes `voted_at` |
| `query_user_bets` | `(env, user: Address) → Result<MultipleBetsQuery, Error>` | **Implemented** |
| `query_user_bets_paged` | `(env, user: Address, cursor: u32, limit: u32) → Result<PagedUserBets, Error>` | **Implemented** |

#### Balance & Pool Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_user_balance` | `(env, user: Address) → Result<UserBalanceQuery, Error>` | **Stubbed** — `available_balance` and `total_winnings` fields return `0`; token-contract integration pending (see issue #595) |
| `query_market_pool` | `(env, market_id: Symbol) → Result<MarketPoolQuery, Error>` | **Stubbed** — `platform_fees` field returns `0`; fees-module integration pending (see issue #595) |
| `query_total_pool_size` | `(env) → Result<i128, Error>` | **Implemented** |

#### Contract State Queries

| Function | Signature | Status |
|----------|-----------|--------|
| `query_contract_state` | `(env) → Result<ContractStateQuery, Error>` | **Stubbed** — core counters implemented; `unique_users` proxied via `DashboardStatisticsV1`; `total_fees_collected` from `StatisticsManager` (see issue #595) |
| `query_contract_state_paged` | `(env, cursor: u32, limit: u32) → Result<(ContractStateQuery, u32), Error>` | **Stubbed** — same caveats as above |

---

### Bet Limit Getters (outside QueryManager)

| Function | Call path | Status |
|----------|-----------|--------|
| `get_effective_bet_limits` | `bets::get_effective_bet_limits(env, market_id)` in `bets.rs`; also exposed as contract entry-point in `lib.rs` | **Implemented** |
| `get_global_bet_limits` | No standalone getter; limits are read internally by `get_effective_bet_limits` | **Planned** |

---

**User Bet Queries**
- `query_user_bet(env, user, market_id)` - Get user's participation details
- `query_user_bets(env, user)` - Get all user's bets across markets
- `query_user_balance(env, user)` - Get user balance for each asset
- `query_market_pool(env, market_id)` - Get market pool statistics
### Config Getters (outside QueryManager)

**Contract State Queries**
- `query_total_pool_size(env)` - Get total platform staking
- `query_contract_state(env)` - Get overall contract state and status
| Function | Call path | Status |
|----------|-----------|--------|
| `get_config` | `config::ConfigManager::get_config(env)` in `config.rs` | **Implemented** |
| `get_configuration_history` | `config::ConfigManager::get_configuration_history(env, limit)` in `config.rs` | **Implemented** |

---

Expand Down
69 changes: 59 additions & 10 deletions contracts/predictify-hybrid/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,67 @@
//! 3. **Contract State Queries** - Retrieve global contract state and statistics
//! 4. **Analytics Queries** - Get aggregated market analytics and performance metrics
//!
//! # Gap Analysis (2026-04-23)
//! # Gap Analysis — Reconciled (2026-06-18, supersedes 2026-04-23)
//!
//! The following gaps were identified between the published API spec and current implementation:
//! Status of every getter originally flagged in the gap analysis.
//! Verification: `grep -n "pub fn <name>" contracts/predictify-hybrid/src/**/*.rs`
//!
//! - **Missing Admin Getters**: `get_admin_role`, `get_admin_roles`, `has_permission`, `get_permissions_for_role`
//! - **Missing Multisig Getters**: `get_multisig_config`, `requires_multisig`
//! - **Missing Bet Limit Getters**: `get_effective_bet_limits`, `get_global_bet_limits`
//! - **Missing Oracle Getters**: `get_oracle_resolution`, `get_approved_oracles`, `get_oracle_metadata`, `get_global_oracle_config`
//! - **Missing Dispute Getters**: `get_dispute_stats`, `get_market_disputes`, `get_dispute_votes`, `get_dispute_timeout_status`
//! - **Missing Governance Getters**: `list_proposals`, `get_proposal`
//! - **Missing Config Getters**: `get_config`, `get_configuration_history`
//! - **Inconsistencies**: `query_event_details` (missing `created_at`), `query_user_bet` (missing `voted_at`), `query_contract_state` (stubbed metrics)
//! ## Admin / Multisig Getters
//!
//! | Getter | Status | Call path |
//! |--------|--------|-----------|
//! | `get_admin_role` / `get_admin_roles` | **Implemented** | `QueryManager::query_admin_role` / `query_admin_roles` (this module) → `AdminManager` in `admin.rs` |
//! | `has_permission` | **Implemented** | `QueryManager::query_has_permission` (this module) → `AdminManager::validate_admin_permission` in `admin.rs` |
//! | `get_permissions_for_role` | **Implemented** | Not surfaced via `QueryManager`; call `AdminRoleManager::get_permissions_for_role` in `admin.rs` directly |
//! | `get_multisig_config` | **Implemented** | `QueryManager::query_multisig_config` (this module) |
//! | `requires_multisig` | **Implemented** | `QueryManager::query_requires_multisig` (this module) → `MultisigManager::requires_multisig` in `admin.rs` |
//!
//! ## Bet Limit Getters
//!
//! | Getter | Status | Call path |
//! |--------|--------|-----------|
//! | `get_effective_bet_limits` | **Implemented** | Not surfaced via `QueryManager`; call `get_effective_bet_limits(env, market_id)` in `bets.rs` directly, or via `lib.rs` contract entry-point |
//! | `get_global_bet_limits` | **Planned** | No standalone getter exists; global limits are read inside `get_effective_bet_limits` in `bets.rs` |
//!
//! ## Oracle Getters
//!
//! | Getter | Status | Call path |
//! |--------|--------|-----------|
//! | `get_oracle_resolution` | **Stubbed** | `ResolutionManager::get_oracle_resolution` in `resolution.rs` — always returns `Ok(None)`; full persistence not yet implemented |
//! | `get_approved_oracles` | **Implemented** | `QueryManager::query_approved_oracles` (this module) → `OracleWhitelist::get_approved_oracles` in `oracles.rs` |
//! | `get_oracle_metadata` | **Implemented** | `QueryManager::query_oracle_metadata` (this module) → persistent storage via `OracleWhitelistKey` in `oracles.rs` |
//! | `get_global_oracle_config` | **Planned** | No implementation exists in any module |
//!
//! ## Dispute Getters
//!
//! | Getter | Status | Call path |
//! |--------|--------|-----------|
//! | `get_dispute_stats` | **Implemented** | `QueryManager::query_dispute_stats` (this module) → `DisputeManager::get_dispute_stats` in `disputes.rs` |
//! | `get_market_disputes` | **Implemented** | `QueryManager::query_market_disputes` (this module) → `DisputeManager::get_market_disputes` in `disputes.rs` |
//! | `get_dispute_votes` | **Implemented** | `QueryManager::query_dispute_votes` (this module) → `DisputeManager::get_dispute_votes` in `disputes.rs` |
//! | `get_dispute_timeout_status` | **Implemented** | Not surfaced via `QueryManager`; call `DisputeManager::get_dispute_timeout_status` in `disputes.rs` directly |
//!
//! ## Governance Getters
//!
//! | Getter | Status | Call path |
//! |--------|--------|-----------|
//! | `list_proposals` | **Implemented** | `QueryManager::query_proposals` (this module) → `GovernanceContract::list_proposals` in `governance.rs` |
//! | `get_proposal` | **Implemented** | `QueryManager::query_proposal_details` (this module) → `GovernanceContract::get_proposal` in `governance.rs` |
//!
//! ## Config Getters
//!
//! | Getter | Status | Call path |
//! |--------|--------|-----------|
//! | `get_config` | **Implemented** | Not surfaced via `QueryManager`; call `ConfigManager::get_config` in `config.rs` directly |
//! | `get_configuration_history` | **Implemented** | Not surfaced via `QueryManager`; call `ConfigManager::get_configuration_history` in `config.rs` directly |
//!
//! ## Previously-Noted Inconsistencies
//!
//! | Issue | Status |
//! |-------|--------|
//! | `query_event_details` missing `created_at` | **Fixed** — field populated from `EventManager::get_event` |
//! | `query_user_bet` missing `voted_at` | **Fixed** — field populated from `BetManager::get_bet` timestamp |
//! | `query_contract_state` stubbed metrics (`unique_users`, `total_fees_collected`) | **Stubbed** — `unique_users` proxied via `DashboardStatisticsV1`; `total_fees_collected` sourced from `StatisticsManager`; token-balance fields still TODO (see issue #595) |

use alloc::string::ToString;

Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Complete API reference for Predictify Hybrid contract, including:

Comprehensive security documentation and guidelines:

- **[Threat Model](./security/THREAT_MODEL.md)** - Oracle-resolution and dispute-attack threat model with code-grounded citations
- **[Attack Vectors](./security/ATTACK-VECTORS.md)** - Known attack vectors and mitigation strategies
- **[Audit Checklist](./security/AUDIT_CHECKLIST.md)** - Security audit requirements and checklist
- **[Soroban SDK Workspace Audit](./security/SOROBAN_SDK_AUDIT.md)** - Workspace Soroban SDK target, verification steps, and audit notes for Protocol 25 alignment
Expand Down
Loading
Loading