Most AI agents that need market prices do the same thing: call one API, trust the number, move on.
That works until it doesn't.
A single source going stale, returning a wrong price during a flash crash, or simply being down — and your agent acts on bad data with no way to know.
I spent several months building MAXIA Oracle to fix this. Here's the architecture and what I learned.
The core idea: confidence over precision
The insight that drove the design: an agent doesn't need the "perfect" price. It needs to know how much to trust the price it got.
Every response from MAXIA Oracle returns three things:
• The median price (cross-validated across sources)
• A confidence score (0–100)
• An inter-source divergence percentage
If Pyth says BTC is $83,000 and CoinPaprika says $83,150, confidence is high (95), divergence is low (0.18%). The agent can act.
If one source returns $80,000 and another $86,000, divergence spikes. The agent should pause and flag the discrepancy before executing anything.
The 5 sources and why each one matters
1. Pyth Network (Solana)
Pyth is the backbone. A single batch call to the Hermes HTTP API returns prices for up to 79 symbols in one round-trip — crypto majors, Solana ecosystem, US equities (AAPL, TSLA, NVDA), forex pairs, stablecoins.
Each Pyth response includes a confidence interval and an expo field for precise decimal handling. The freshness check is critical: Pyth updates every 400ms on-chain, but if you're calling the REST API, you can get a cached value. I enforce a max staleness of 10 seconds.
Pyth batch call — 79 symbols in one HTTP round-trip
ids = [PYTH_IDS[sym] for sym in symbols if sym in PYTH_IDS] resp = await client.get( "https://hermes.pyth.network/v2/updates/price/latest", params={"ids[]": ids, "parsed": "true"} )
1. Chainlink (Base mainnet)
Chainlink is the independent verifier. It runs on a completely different infrastructure (EVM on-chain vs Solana), so a Pyth anomaly won't affect it.
I call Chainlink via a direct RPC call to Base mainnet, reading the latestRoundData() function from each price feed contract. No intermediary, no API key — pure on-chain data.
Direct on-chain read — no API key needed
result = contract.functions.latestRoundData().call() price = result[1] / 10**decimals updated_at = result[3] # Unix timestamp of last update
The downside: Chainlink covers ~30 symbols on Base, so it can't verify everything. But for the major assets it covers, it's the most trustworthy cross-check available.
1. CoinPaprika
CoinPaprika covers altcoins and memecoins that Pyth and Chainlink don't list. It's also useful as a CeFi reference — it aggregates exchange data, so it reflects what centralized markets are trading at.
1. RedStone
RedStone fills the gaps between Pyth and CoinPaprika for DeFi-native assets. It also provides an alternative data path for some Pyth symbols, which is useful for divergence detection.
1. Uniswap v3 TWAP (Ethereum mainnet)
The TWAP (Time-Weighted Average Price) from Uniswap v3 pools is manipulation-resistant by design — it's computed over a time window, so flash loan attacks can't spike it artificially. For high-value DeFi assets where on-chain trading volume matters, this is a strong signal.
I use a 10-minute TWAP window and only include pools with at least $500k liquidity. Out of 8 pools I tested, 3 met this threshold with acceptable spread vs reference prices.
The aggregation cascade
The logic runs in priority order:
1. Pyth batch call → covers ~79 symbols
2. For each symbol NOT in Pyth → try Chainlink on-chain
3. For remaining gaps → CoinPaprika / RedStone
4. Uniswap v3 TWAP → parallel call, used as verification layer
For each symbol with multiple sources, I compute:
prices = [p for p in source_prices if p is not None] median_price = statistics.median(prices) divergence_pct = (max(prices) - min(prices)) / median_price * 100 confidence = compute_confidence(prices, divergence_pct, freshness)
Confidence is penalized by: high divergence, stale data, single-source results, known circuit breaker trips.
What surprised me
1. Pyth's confidence interval is underused. Every Pyth price comes with a ±conf value in the same units as the price. Most projects ignore it. I use it to weight Pyth's contribution in the aggregation — a tight confidence interval increases Pyth's weight.
2. On-chain is not always fresher. Chainlink updates on deviation threshold + heartbeat. For low-volatility assets, the on-chain price can be hours old. I always check updatedAt and reject stale answers.
3. Uniswap pool selection is the hard part. Finding pools where the TWAP is reliable took more work than the aggregation itself. Many pools have low liquidity, wide spreads, or are dominated by one LP. I ended up with only 3 pools I trust.
Integration
The MCP server runs at https://oracle.maxiaworld.app/mcp/sse — drop it into Claude Desktop, Cursor, or any MCP client and your agent can call get_price("BTC") natively.
Python
pip install maxia-oracle
TypeScript
npm install @maxia-marketplace/oracle
Free tier: 100 req/day, no signup
curl -X POST https://oracle.maxiaworld.app/api/register
91 symbols. Price history (24h/7d/30d). Alerts with webhooks. SSE streaming. Pay-per-call via x402 micropayments ($0.001 USDC on Base) for agents without API keys.
Happy to answer questions about the aggregation logic, the on-chain read setup, or the x402 payment flow.
Source: https://github.com/majorelalexis-stack/oracleforge
Top comments (0)