Version: v1.0.0
Platform: Stellar Soroban
Audience: Developers integrating with Predictify Hybrid smart contracts
- API Overview
- API Versioning
- Core API Reference
- Data Structures
- ReflectorAsset Coverage Matrix
- Token and Asset Management
- Error Codes
- Integration Examples
- Troubleshooting Guide
- Support and Resources
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.
- 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
- Asset Management: Multi-asset support with comprehensive ReflectorAsset coverage
- Fee Management: Automated fee collection and distribution
- Admin Governance: Administrative functions for contract management
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.
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
All exported contract entrypoints in contracts/predictify-hybrid/src/lib.rs are documented with
Rust doc comments (///) and include explicit # Errors and # Events sections.
This is intended to make API behavior auditable without reading all internals:
- Errors: Each entrypoint documents how
Errorvalues are surfaced. Functions returningResult<_, Error>propagate errors directly. Non-Resultentrypoints surface contract failures via panic. - Events: Each entrypoint documents event behavior.
State-changing flows may emit events through internal managers (for example via
EventEmitter), while read-only query flows emit no events.
For exact runtime behavior and error variants, also reference:
contracts/predictify-hybrid/src/err.rscontracts/predictify-hybrid/src/events.rs
Creates a new prediction market with specified parameters.
Signature:
pub fn create_market(
env: Env,
admin: Address,
question: String,
outcomes: Vec<String>,
duration_days: u32,
oracle_config: OracleConfig,
) -> Result<Symbol, Error>Parameters:
admin: Market administrator addressquestion: 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:
const marketId = await contract.create_market(
adminAddress,
"Will Bitcoin reach $100,000 by end of 2025?",
["Yes", "No"],
90, // 90 days
oracleConfig
);Comprehensive asset enumeration for Reflector oracle integration with full testing matrix coverage.
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ReflectorAsset {
/// Stellar Lumens (XLM)
Stellar,
/// Bitcoin (BTC)
BTC,
/// Ethereum (ETH)
ETH,
/// Other asset identified by symbol
Other(Symbol),
}| Asset | Symbol | Decimals | Feed ID | Supported |
|---|---|---|---|---|
| Stellar Lumens | XLM | 7 | XLM/USD | ✅ |
| Bitcoin | BTC | 8 | BTC/USD | ✅ |
| Ethereum | ETH | 18 | ETH/USD | ✅ |
| Custom Assets | * | 7 | CUSTOM/USD | ❌ |
impl ReflectorAsset {
/// Check if this asset is Stellar Lumens (XLM)
pub fn is_xlm(&self) -> bool;
/// Returns symbol string for this asset
pub fn symbol(&self) -> String;
/// Returns human-readable name for this asset
pub fn name(&self) -> String;
/// Returns number of decimal places for this asset
pub fn decimals(&self) -> u8;
/// Returns Reflector feed ID for this asset (e.g., "BTC/USD")
pub fn feed_id(&self) -> String;
/// Checks if this asset is supported by Reflector oracle
pub fn is_supported(&self) -> bool;
/// Checks if this asset is a known asset (including custom ones)
pub fn is_known(&self) -> bool;
/// Validates asset for use in market creation
pub fn validate_for_market(&self, env: &Env) -> Result<(), Error>;
/// Creates a ReflectorAsset from a symbol string
pub fn from_symbol(symbol: String) -> Self;
/// Returns all supported assets for testing purposes
pub fn all_supported() -> Vec<Self>;
/// Returns all known assets (including unsupported) for testing purposes
pub fn all_known() -> Vec<Self>;
}// 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"Represents a Stellar asset/token with contract address and metadata.
#[soroban_sdk::contracttype]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Asset {
pub contract: Address,
pub symbol: Symbol,
pub decimals: u8,
}impl Asset {
/// Create a new Asset instance
pub fn new(contract: Address, symbol: Symbol, decimals: u8) -> Self;
/// Create an Asset from a ReflectorAsset
pub fn from_reflector_asset(env: &Env, reflector_asset: &ReflectorAsset, contract_address: Address) -> Self;
/// Check if this asset matches a ReflectorAsset
pub fn matches_reflector_asset(&self, env: &Env, reflector_asset: &ReflectorAsset) -> bool;
/// Get human-readable asset name
pub fn name(&self, env: &Env) -> String;
/// Check if this is a native XLM asset
pub fn is_native_xlm(&self, env: &Env) -> bool;
/// Validate asset for market creation
pub fn validate_for_market(&self, env: &Env) -> Result<(), Error>;
/// Validate token contract and decimals
pub fn validate(&self, env: &Env) -> bool;
}Global registry for managing allowed assets with per-event and global support.
impl TokenRegistry {
/// Checks if asset is allowed globally or for a specific event
pub fn is_allowed(env: &Env, asset: &Asset, market_id: Option<&Symbol>) -> bool;
/// Adds asset to global registry
pub fn add_global(env: &Env, asset: &Asset);
/// Adds asset to per-event registry
pub fn add_event(env: &Env, market_id: &Symbol, asset: &Asset);
/// Initialize registry with default supported assets
pub fn initialize_with_defaults(env: &Env);
/// Get all globally allowed assets
pub fn get_global_assets(env: &Env) -> Vec<Asset>;
/// Get assets allowed for a specific event
pub fn get_event_assets(env: &Env, market_id: &Symbol) -> Vec<Asset>;
/// Remove asset from global registry
pub fn remove_global(env: &Env, asset: &Asset) -> Result<(), Error>;
/// Validate asset against registry rules
pub fn validate_asset(env: &Env, asset: &Asset, market_id: Option<&Symbol>) -> Result<(), Error>;
}The ReflectorAsset system provides comprehensive end-to-end testing coverage for all representative assets used in production:
| Asset | Symbol | Decimals | Feed ID | Validation | Market Creation | Oracle Integration |
|---|---|---|---|---|---|---|
| Stellar Lumens | XLM | 7 | XLM/USD | ✅ | ✅ | ✅ |
| Bitcoin | BTC | 8 | BTC/USD | ✅ | ✅ | ✅ |
| Ethereum | ETH | 18 | ETH/USD | ✅ | ✅ | ✅ |
- Property Validation: All asset properties (symbol, name, decimals, feed_id)
- Support Status: is_supported() and is_known() method validation
- Market Validation: validate_for_market() comprehensive testing
- Round-trip Conversion: from_symbol() and back conversion testing
- Feed ID Format: Consistent "/USD" suffix validation
- Asset-specific Properties: XLM-specific behavior testing
- Integration Testing: End-to-end market creation with all assets
- Registry Integration: TokenRegistry compatibility testing
- Total Test Cases: 25+ comprehensive tests
- Coverage Target: ≥95% line coverage on ReflectorAsset modules
- Asset Variants: All supported and custom asset variants
- Error Paths: All validation error scenarios tested
- Edge Cases: Boundary conditions and invalid inputs tested
- Asset Validation: All assets undergo rigorous validation before market creation
- Feed ID Verification: Oracle feed IDs follow strict format requirements
- Decimal Precision: Asset decimals are validated within acceptable ranges (1-18)
- Support Status: Only supported assets can be used for live markets
- Registry Authorization: Asset registry enforces authorization controls
| Threat | Mitigation | Coverage |
|---|---|---|
| Invalid Asset Symbols | Symbol validation and whitelisting | ✅ |
| Oracle Feed Manipulation | Feed ID format validation | ✅ |
| Decimal Precision Attacks | Decimal range validation (1-18) | ✅ |
| Unsupported Asset Usage | Support status validation | ✅ |
| Registry Unauthorized Access | Authorization controls | ✅ |
Predictify Hybrid supports multiple asset types for betting and payouts:
- Native XLM: Stellar's native asset with 7 decimal places
- Custom Tokens: Soroban token contracts with configurable decimals
- Reflector Assets: Pre-configured assets with oracle integration
- Registration: Assets registered in TokenRegistry (global or per-event)
- Validation: Assets validated before use in markets
- Usage: Assets used for betting, staking, and payouts
- Tracking: Asset balances and transfers tracked securely
// Create market with BTC price feed
let btc_asset = ReflectorAsset::BTC;
let oracle_config = OracleConfig::new(
OracleProvider::Reflector,
String::from_str(&env, &btc_asset.feed_id()),
100_000_00, // $100,000 in cents
String::from_str(&env, "gt")
);
let market_id = create_market(
env,
admin,
String::from_str(&env, "Will BTC reach $100k?"),
outcomes,
30, // 30 days
oracle_config
);// Initialize with default assets
TokenRegistry::initialize_with_defaults(&env);
// Add custom asset
let usdc_asset = Asset::new(
token_contract_address,
Symbol::new(&env, "USDC"),
7
);
TokenRegistry::add_global(&env, &usdc_asset);
// Validate asset usage
TokenRegistry::validate_asset(&env, &usdc_asset, None)?;Predictify Hybrid provides high-level operations for interacting with Stellar Asset Contracts (SAC) through the standard Soroban token interface.
Transfers tokens from one address to another (requires sender's authorization).
pub fn transfer_token(env: &Env, asset: &Asset, from: &Address, to: &Address, amount: i128);Approves a spender to use a specified amount of tokens from the owner.
pub fn approve_token(env: &Env, asset: &Asset, from: &Address, spender: &Address, amount: i128, expiration_ledger: u32);Transfers tokens using a previously granted allowance (requires spender's authorization).
pub fn transfer_from_token(env: &Env, asset: &Asset, spender: &Address, from: &Address, to: &Address, amount: i128);Retrieves the token balance for a specified address.
pub fn get_token_balance(env: &Env, asset: &Asset, address: &Address) -> i128;Retrieves the allowance granted by an owner to a spender.
pub fn get_token_allowance(env: &Env, asset: &Asset, owner: &Address, spender: &Address) -> i128;Validates a token operation by checking asset validity and user balance.
pub fn validate_token_operation(env: &Env, asset: &Asset, user: &Address, amount: i128) -> Result<(), Error>;- 500:
InvalidAsset- Asset validation failed - 501:
UnsupportedAsset- Asset not supported by Reflector - 502:
InvalidFeedId- Malformed feed identifier - 503:
AssetNotRegistered- Asset not found in registry - 504:
InvalidDecimals- Asset decimals out of range - 505:
UnauthorizedAsset- Asset not authorized for use
- 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
- 200:
OracleUnavailable- Oracle service unavailable - 201:
InvalidOracleConfig- Oracle configuration invalid - 202:
OracleTimeout- Oracle response timeout - 203:
OracleDataInvalid- Oracle data format invalid
import { Contract, Keypair, Networks } from '@stellar/stellar-sdk';
// Initialize contract
const contract = new Contract(contractId);
// Create market with BTC price feed
const btcAsset = "BTC"; // ReflectorAsset::BTC
const marketId = await contract.create_market(
adminKeypair.publicKey(),
"Will Bitcoin reach $100,000 by Q2 2025?",
["Yes", "No"],
90, // 90 days
{
provider: "Reflector",
feed_id: "BTC/USD",
threshold: 100000000, // $100,000 in cents
timeout_seconds: 3600
}
);
// Vote with XLM (native asset)
await contract.vote(
userKeypair.publicKey(),
marketId,
"Yes",
10000000 // 1 XLM in stroops
);// Create market with ETH price feed
const ethMarketId = await contract.create_market(
adminKeypair.publicKey(),
"Will Ethereum reach $5,000?",
["Yes", "No"],
60,
{
provider: "Reflector",
feed_id: "ETH/USD",
threshold: 500000000, // $5,000 in cents
timeout_seconds: 3600
}
);
// Vote with custom token (USDC)
const usdcAsset = {
contract: usdcTokenAddress,
symbol: "USDC",
decimals: 7
};
await contract.vote_with_asset(
userKeypair.publicKey(),
ethMarketId,
"Yes",
50000000, // 50 USDC
usdcAsset
);Error: InvalidAsset (500)Solution:
- Verify asset decimals are within range (1-18)
- Check contract address is valid (not default for non-XLM)
- Ensure asset symbol matches expected format
- Confirm asset is registered in TokenRegistry
Error: UnsupportedAsset (501)Solution:
- Use supported assets: XLM, BTC, ETH
- For custom assets, register them in TokenRegistry first
- Check asset.is_supported() returns true before use
Error: InvalidFeedId (502)Solution:
- Use standard feed ID format: "ASSET/USD"
- Verify asset symbol is valid
- Use ReflectorAsset.feed_id() for correct format
Problem: Asset not found in registry
Error: AssetNotRegistered (503)Solution:
# Check global assets
soroban contract invoke \
--id $CONTRACT_ID \
--fn get_global_assets \
--network mainnet
# Add asset if missing
soroban contract invoke \
--id $CONTRACT_ID \
--fn add_global_asset \
--arg asset_contract=$TOKEN_ADDRESS \
--arg symbol=USDC \
--arg decimals=7 \
--network mainnetProblem: Reflector feed not working
Error: OracleUnavailable (200)Solution:
- Verify feed ID format: "BTC/USD", "ETH/USD", "XLM/USD"
- Check Reflector oracle service status
- Ensure asset is supported by Reflector
- Use fallback oracle if configured
Problem: Asset not authorized for voting
Error: UnauthorizedAsset (505)Solution:
- Check asset is in global or event-specific registry
- Verify asset validation passes
- Ensure user has sufficient asset balance
- Confirm asset is supported for market type
# Check asset properties
soroban contract invoke \
--id $CONTRACT_ID \
--fn get_asset_info \
--arg asset_contract=$TOKEN_ADDRESS \
--network mainnet
# Validate asset
soroban contract invoke \
--id $CONTRACT_ID \
--fn validate_asset \
--arg asset_contract=$TOKEN_ADDRESS \
--arg symbol=USDC \
--arg decimals=7 \
--network mainnet# List all global assets
soroban contract invoke \
--id $CONTRACT_ID \
--fn get_global_assets \
--network mainnet
# Check event-specific assets
soroban contract invoke \
--id $CONTRACT_ID \
--fn get_event_assets \
--arg market_id="BTC_100K" \
--network mainnet- 500-599: Asset-related errors - Check asset validation and registration
- 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
- GitHub Issues: Report asset integration bugs
- Discord Support: #asset-integration channel
- Developer Forum: Asset integration discussions
- Email Support: assets@predictify.io
- Check this troubleshooting guide
- Search existing GitHub issues for asset-related problems
- Verify your asset configuration matches documentation
- Collect relevant error messages and transaction hashes
- Note your contract version and network
- Stellar Soroban Documentation
- Stellar SDK Documentation
- Predictify GitHub Repository
- Reflector Oracle Documentation
- Asset Integration Examples
- Validation: All assets undergo comprehensive validation before use
- Authorization: Asset registry enforces strict authorization controls
- Precision: Decimal precision is validated to prevent overflow attacks
- Feeds: Oracle feed IDs follow strict format requirements
- Testing: Comprehensive test coverage ensures asset reliability
| Asset Category | Threat Level | Mitigation |
|---|---|---|
| Native XLM | Low | Built-in Stellar security |
| Supported Tokens | Medium | Contract validation and registry |
| Custom Tokens | High | Full validation and authorization |
| Oracle Feeds | Medium | Feed ID validation and fallbacks |
- Always validate assets before use in markets
- Use supported Reflector assets for reliable price feeds
- Register custom assets in the TokenRegistry before use
- Test asset integration thoroughly before production deployment
- Monitor asset balances and transfers for security
Last Updated: 2026-03-27
API Version: v1.0.0
Documentation Version: 1.2
ReflectorAsset Coverage: Production Ready with ≥95% Test Coverage