Oracle Integration#
Seesaw uses Pyth Network as its exclusive oracle for price data. This document explains how prices are sampled, validated, and used for resolution.
Why Pyth?#
Pyth provides:
- Sub-second updates - Fresh prices every ~400ms
- High fidelity - Aggregated from top exchanges
- Confidence intervals - Know the uncertainty
- On-chain verification - Cryptographically signed
Price Feed Structure#
Each Pyth price update contains:
struct PriceUpdate {
price: i64, // Price in base units
conf: u64, // Confidence interval (±)
expo: i32, // Exponent (10^expo)
publish_time: i64, // Unix timestamp
ema_price: i64, // Exponential moving average
ema_conf: u64, // EMA confidence
}
Example#
Sampling Rules#
Start Price Capture#
The start price is captured atomically during create_market. The crank calls create_market with the Pyth price feed, and the instruction reads the current price directly from the oracle account.
Requirements:
price > 0- Valid Pyth price feed account
- Market account must not already exist
End Price Capture#
Identical process, but:
publish_time >= t_end- Start price must exist
Timing Diagram#
Time ─────────────────────────────────────────────────►
│ │ │
▼ ▼ ▼
t_start P_start t_end P_end
│ captured │ captured
│ │ │ │
├───────────┼────────────────────┼──────────┤
│ CREATED │ TRADING │ SETTLING │
Confidence Validation (Optional)#
Markets can enforce confidence ratio limits:
valid = (conf / |price|) <= max_confidence_ratio
Example#
This prevents resolution during extreme volatility or oracle degradation.
Resolution Logic#
Resolution Rules#
| Condition | Outcome |
|---|---|
P_end > P_start | UP |
P_end = P_start | UP |
P_end < P_start | DOWN |
Key point: Equality resolves as UP. This eliminates ambiguity and slightly favors YES holders.
Supported Price Feeds#
| Asset | Pyth Feed ID | Update Frequency |
|---|---|---|
| SOL/USD | H6ARHf6Y... | ~400ms |
| BTC/USD | GVXRSBjF... | ~400ms |
| ETH/USD | JBu1AL4o... | ~400ms |
| BONK/USD | 8ihFLu5F... | ~400ms |
Immutability Guarantees#
Once captured, oracle snapshots cannot be changed:
// Start price captured atomically during create_market
pub fn create_market(ctx: Context<CreateMarket>) -> Result<()> {
let market = &mut ctx.accounts.market;
// Market account is freshly initialized — start_price is 0
// Capture start price from Pyth feed immutably
market.start_price = pyth_feed.price;
market.start_price_timestamp = pyth_feed.publish_time;
Ok(())
}
This ensures:
- No retroactive price manipulation
- Deterministic resolution
- Auditability
Error Handling#
| Error | Cause | Resolution |
|---|---|---|
PriceNotAvailable | Pyth feed stale | Wait for update |
InvalidTimestamp | publish_time < boundary | Wait for valid price |
NegativePrice | price <= 0 | Wait for valid price |
ConfidenceTooHigh | Exceeds threshold | Wait for stable price |
SnapshotAlreadyCaptured | Already captured | No action needed |
Oracle Security#
Potential Attacks#
Protections#
- Aggregation - Price from 70+ sources resists manipulation
- Signatures - Updates cryptographically verified
- Immutable Feed - Feed address set at market creation
- Confidence Bounds - Reject uncertain prices
- Timestamp Validation - Prevents stale/future prices
Operational Considerations#
Pyth Maintenance Windows#
Pyth may have brief maintenance. Markets handle this by:
- Allowing snapshots within grace period
- Crank operators retry until successful
- No trades affected (only lifecycle operations)
Feed Deprecation#
If Pyth deprecates a feed:
- New markets use new feed
- Existing markets continue with old feed
- Old feed remains available for settlement
Latency#
For most market durations (60s+), this latency is negligible.