synor/docs/PLAN/PHASE12-EconomicsBilling/01-Milestone-01-PricingOracle.md
Gulshan Yadav 3c9470abba a
2026-01-11 19:05:44 +05:30

6.6 KiB

Milestone 1: Pricing Oracle

Build decentralized price feeds for SYNOR/USD conversion, enabling stable pricing for L2 services.


Overview

The Pricing Oracle aggregates price data from multiple sources to provide reliable SYNOR/USD rates for service pricing. This ensures users can estimate costs in familiar fiat terms while paying in SYNOR tokens.


Components

1.1 Price Feed Aggregator

// crates/synor-economics/src/oracle/price_feed.rs

/// Price source for SYNOR/USD rates
pub enum PriceSource {
    /// On-chain DEX (Synor DEX, Uniswap, etc.)
    Dex { pool_address: Address, pair: TradingPair },
    /// Centralized exchange API
    Cex { exchange: String, api_endpoint: String },
    /// Chainlink-style oracle
    Chainlink { feed_address: Address },
    /// Off-chain oracle (signed by trusted nodes)
    OffChain { oracle_id: OracleId },
}

/// Aggregated price with metadata
pub struct AggregatedPrice {
    /// SYNOR/USD price (6 decimal places)
    pub price: u64,
    /// Unix timestamp
    pub timestamp: u64,
    /// Sources used
    pub sources: Vec<PriceSource>,
    /// Confidence (0-100)
    pub confidence: u8,
    /// 24h high
    pub high_24h: u64,
    /// 24h low
    pub low_24h: u64,
    /// 24h volume
    pub volume_24h: u64,
}

pub struct PriceFeedAggregator {
    sources: Vec<PriceSource>,
    cache: LruCache<TradingPair, AggregatedPrice>,
    update_interval_ms: u64,
}

impl PriceFeedAggregator {
    /// Get current price with aggregation across sources
    pub async fn get_price(&self, pair: &TradingPair) -> Result<AggregatedPrice, OracleError> {
        // Fetch from all sources in parallel
        let prices = futures::future::join_all(
            self.sources.iter().map(|s| self.fetch_from_source(s, pair))
        ).await;

        // Filter out failures and outliers
        let valid_prices = self.filter_outliers(prices);

        // Calculate median price
        let median = self.calculate_median(&valid_prices);

        // Calculate confidence based on source agreement
        let confidence = self.calculate_confidence(&valid_prices, median);

        Ok(AggregatedPrice {
            price: median,
            timestamp: current_timestamp(),
            sources: self.sources.clone(),
            confidence,
            ..Default::default()
        })
    }
}

1.2 Time-Weighted Average Price (TWAP)

// crates/synor-economics/src/oracle/twap.rs

/// TWAP calculator for stable pricing
pub struct TwapCalculator {
    /// Price observations
    observations: VecDeque<PriceObservation>,
    /// TWAP window (e.g., 1 hour)
    window_seconds: u64,
    /// Minimum observations required
    min_observations: usize,
}

pub struct PriceObservation {
    pub price: u64,
    pub timestamp: u64,
    pub cumulative_price: u128,
}

impl TwapCalculator {
    /// Calculate TWAP over the configured window
    pub fn calculate_twap(&self) -> Option<u64> {
        if self.observations.len() < self.min_observations {
            return None;
        }

        let oldest = self.observations.front()?;
        let newest = self.observations.back()?;

        let time_elapsed = newest.timestamp - oldest.timestamp;
        if time_elapsed == 0 {
            return None;
        }

        let cumulative_diff = newest.cumulative_price - oldest.cumulative_price;
        Some((cumulative_diff / time_elapsed as u128) as u64)
    }

    /// Add new price observation
    pub fn observe(&mut self, price: u64) {
        let timestamp = current_timestamp();
        let cumulative = self.observations
            .back()
            .map(|o| o.cumulative_price + (price as u128 * (timestamp - o.timestamp) as u128))
            .unwrap_or(0);

        self.observations.push_back(PriceObservation {
            price,
            timestamp,
            cumulative_price: cumulative,
        });

        // Remove old observations outside window
        let cutoff = timestamp - self.window_seconds;
        while self.observations.front().map(|o| o.timestamp < cutoff).unwrap_or(false) {
            self.observations.pop_front();
        }
    }
}

1.3 Oracle Smart Contract

// crates/synor-economics/src/oracle/contract.rs

/// On-chain oracle contract for price storage
pub struct OracleContract {
    /// Current price (6 decimals)
    pub price: u64,
    /// Last update timestamp
    pub updated_at: u64,
    /// Authorized updaters
    pub updaters: HashSet<Address>,
    /// TWAP values
    pub twap_1h: u64,
    pub twap_24h: u64,
    /// Deviation threshold for updates (basis points)
    pub deviation_threshold_bps: u16,
}

impl OracleContract {
    /// Update price (only authorized updaters)
    pub fn update_price(
        &mut self,
        caller: Address,
        new_price: u64,
        sources: Vec<SignedPriceAttestation>,
    ) -> Result<(), OracleError> {
        // Verify caller is authorized
        if !self.updaters.contains(&caller) {
            return Err(OracleError::Unauthorized);
        }

        // Verify attestations
        let verified_prices = self.verify_attestations(&sources)?;

        // Check consensus among sources
        let median = self.calculate_median(&verified_prices);

        // Check deviation from current price
        let deviation = self.calculate_deviation(self.price, median);
        if deviation < self.deviation_threshold_bps {
            return Ok(()); // No significant change
        }

        // Update price
        self.price = median;
        self.updated_at = current_timestamp();

        // Emit event
        emit_event(PriceUpdatedEvent { price: median, timestamp: self.updated_at });

        Ok(())
    }
}

Tasks

  • Implement PriceFeedAggregator with multiple source support
  • Implement TWAP calculator with configurable windows
  • Deploy oracle smart contract to testnet
  • Set up price updater nodes
  • Integrate with DEX liquidity pools
  • Add CEX price feed support (optional)
  • Implement price staleness detection
  • Add circuit breaker for extreme volatility

Validation Commands

# Run oracle tests
cargo test --package synor-economics --lib oracle

# Check price feed connectivity
synor oracle status

# Get current SYNOR/USD price
synor oracle price SYNOR/USD

# Check TWAP values
synor oracle twap SYNOR/USD --window 1h

Security Considerations

  • Manipulation Resistance: TWAP smooths out flash loan attacks
  • Source Diversity: Multiple independent sources prevent single point of failure
  • Deviation Limits: Large price swings require multiple confirmations
  • Staleness Detection: Alert when prices haven't updated recently