Complete guide for Pyth Network - decentralized oracle providing real-time price feeds for DeFi. Covers price feed integration, confidence intervals, EMA prices, on-chain CPI, off-chain fetching, and streaming updates for Solana applications.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: pyth creator: raunit-dev description: Complete guide for Pyth Network - decentralized oracle providing real-time price feeds for DeFi. Covers price feed integration, confidence intervals, EMA prices, on-chain CPI, off-chain fetching, and streaming updates for Solana applications.
Pyth Network Development Guide
Pyth Network is a decentralized oracle providing real-time price feeds for cryptocurrencies, equities, forex, and commodities. This guide covers integrating Pyth price feeds into Solana applications.
Overview
Pyth Network provides:
- Real-Time Price Feeds - 400ms update frequency with pull oracle model
- Confidence Intervals - Statistical uncertainty bounds for each price
- EMA Prices - Exponential moving average prices (~1 hour window)
- Multi-Asset Support - Crypto, equities, FX, commodities, indices
- On-Chain Integration - CPI for Solana programs
- Off-Chain Integration - HTTP and WebSocket APIs via Hermes
Program IDs
| Program | Address | Description |
|---|---|---|
| Solana Receiver | rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ | Posts price updates to Solana |
| Price Feed | pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT | Stores price feed data |
Deployed on: Solana Mainnet, Devnet, Eclipse Mainnet/Testnet, Sonic networks
Popular Price Feed IDs
| Asset | Hex Feed ID |
|---|---|
| BTC/USD | 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43 |
| ETH/USD | 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace |
| SOL/USD | 0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d |
| USDC/USD | 0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a |
| USDT/USD | 0x2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b |
Full list: https://pyth.network/developers/price-feed-ids
Quick Start
Installation
# TypeScript/JavaScript
npm install @pythnetwork/hermes-client @pythnetwork/pyth-solana-receiver
# Rust (add to Cargo.toml)
# pyth-solana-receiver-sdk = "0.3.0"
Fetch Price (Off-Chain)
import { HermesClient } from "@pythnetwork/hermes-client";
const client = new HermesClient("https://hermes.pyth.network");
const priceIds = [
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", // BTC/USD
];
const priceUpdates = await client.getLatestPriceUpdates(priceIds);
for (const update of priceUpdates.parsed) {
const price = update.price;
const displayPrice = Number(price.price) * Math.pow(10, price.expo);
console.log(`Price: $${displayPrice.toFixed(2)}`);
console.log(`Confidence: Β±${Number(price.conf) * Math.pow(10, price.expo)}`);
}
Use Price On-Chain (Rust/Anchor)
use anchor_lang::prelude::*;
use pyth_solana_receiver_sdk::price_update::PriceUpdateV2;
#[derive(Accounts)]
pub struct UsePrice<'info> {
pub price_update: Account<'info, PriceUpdateV2>,
}
pub fn use_price(ctx: Context<UsePrice>) -> Result<()> {
let price_update = &ctx.accounts.price_update;
let clock = Clock::get()?;
// Get price no older than 60 seconds
let price = price_update.get_price_no_older_than(
&clock,
60, // max age in seconds
)?;
msg!("Price: {} Γ 10^{}", price.price, price.exponent);
msg!("Confidence: Β±{}", price.conf);
Ok(())
}
Core Concepts
Price Structure
Each Pyth price contains:
| Field | Type | Description |
|---|---|---|
price | i64 | Price value in fixed-point format |
conf | u64 | Confidence interval (standard deviation) |
expo | i32 | Exponent for scaling (e.g., -8 means divide by 10^8) |
publish_time | i64 | Unix timestamp of price |
Converting to display price:
const displayPrice = price * Math.pow(10, expo);
// Example: price=19405100, expo=-2 β $194,051.00
Confidence Intervals
Confidence intervals represent the uncertainty in the reported price:
// Price is $50,000 Β± $50 means:
// - 68% chance true price is between $49,950 - $50,050
// - Use confidence for risk management
const price = 50000;
const confidence = 50;
// Safe lower bound (conservative)
const safeLowerBound = price - confidence;
// Safe upper bound (conservative)
const safeUpperBound = price + confidence;
Best Practice: Reject prices with confidence > 2% of price:
const maxConfidenceRatio = 0.02; // 2%
const confidenceRatio = confidence / Math.abs(price);
if (confidenceRatio > maxConfidenceRatio) {
throw new Error("Price confidence too wide");
}
EMA Prices
Exponential Moving Average prices smooth out short-term volatility:
- ~1 hour averaging window (5921 Solana slots)
- Weighted by inverse confidence (tight confidence = more weight)
- Good for: liquidations, collateral valuation
- Available as
ema_priceandema_conf
// Use EMA for less volatile applications
const emaPrice = priceUpdate.emaPrice;
const emaConf = priceUpdate.emaConf;
Off-Chain Integration
Hermes Client
Hermes is the recommended way to fetch Pyth prices off-chain.
Public Endpoint: https://hermes.pyth.network
For production, get a dedicated endpoint from a Pyth data provider.
Fetching Latest Prices
import { HermesClient } from "@pythnetwork/hermes-client";
const client = new HermesClient("https://hermes.pyth.network");
// Single price
const btcPrice = await client.getLatestPriceUpdates([
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
]);
// Multiple prices in one request
const prices = await client.getLatestPriceUpdates([
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", // BTC
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", // ETH
"0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d", // SOL
]);
Streaming Real-Time Updates
import { HermesClient } from "@pythnetwork/hermes-client";
const client = new HermesClient("https://hermes.pyth.network");
const priceIds = [
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
];
// Subscribe to real-time updates via SSE
const eventSource = await client.getPriceUpdatesStream(priceIds, {
parsed: true,
});
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Price update:", data);
};
eventSource.onerror = (error) => {
console.error("Stream error:", error);
eventSource.close();
};
// Close when done
// eventSource.close();
Posting Prices to Solana
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
import { HermesClient } from "@pythnetwork/hermes-client";
import { Connection, Keypair } from "@solana/web3.js";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const wallet = Keypair.fromSecretKey(/* your key */);
const hermesClient = new HermesClient("https://hermes.pyth.network");
const pythReceiver = new PythSolanaReceiver({ connection, wallet });
// Fetch price update data
const priceUpdateData = await hermesClient.getLatestPriceUpdates([
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
]);
// Build transaction to post price
const transactionBuilder = pythReceiver.newTransactionBuilder();
await transactionBuilder.addPostPriceUpdates(priceUpdateData.binary.data);
// Add your program instruction that uses the price
// transactionBuilder.addInstruction(yourInstruction);
// Send transaction
const transactions = await transactionBuilder.buildVersionedTransactions({
computeUnitPriceMicroLamports: 50000,
});
for (const tx of transactions) {
const sig = await connection.sendTransaction(tx);
console.log("Transaction:", sig);
}
On-Chain Integration (Rust)
Setup
Add to Cargo.toml:
[dependencies]
pyth-solana-receiver-sdk = "0.3.0"
anchor-lang = "0.30.1"
Reading Price in Anchor Program
use anchor_lang::prelude::*;
use pyth_solana_receiver_sdk::price_update::{PriceUpdateV2, get_feed_id_from_hex};
declare_id!("YourProgramId...");
// BTC/USD price feed ID
const BTC_USD_FEED_ID: &str = "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43";
#[program]
pub mod my_program {
use super::*;
pub fn check_price(ctx: Context<CheckPrice>) -> Result<()> {
let price_update = &ctx.accounts.price_update;
let clock = Clock::get()?;
// Verify this is the correct feed
let feed_id = get_feed_id_from_hex(BTC_USD_FEED_ID)?;
// Get price no older than 60 seconds
let price = price_update.get_price_no_older_than_with_custom_verification(
&clock,
60,
&feed_id,
ctx.accounts.price_update.to_account_info().owner,
)?;
msg!("BTC/USD Price: {} Γ 10^{}", price.price, price.exponent);
msg!("Confidence: Β±{}", price.conf);
Ok(())
}
}
#[derive(Accounts)]
pub struct CheckPrice<'info> {
#[account(
constraint = price_update.to_account_info().owner == &pyth_solana_receiver_sdk::ID
)]
pub price_update: Account<'info, PriceUpdateV2>,
}
Using Price for Calculations
pub fn swap_with_oracle(
ctx: Context<SwapWithOracle>,
amount_in: u64,
) -> Result<()> {
let price_update = &ctx.accounts.price_update;
let clock = Clock::get()?;
// Get price with staleness check
let price = price_update.get_price_no_older_than(&clock, 30)?;
// Validate confidence (max 1% of price)
let conf_ratio = (price.conf as u128 * 10000) / (price.price.unsigned_abs() as u128);
require!(conf_ratio <= 100, ErrorCode::ConfidenceTooWide);
// Convert price to usable format
// price.price is in fixed-point with price.exponent
let price_scaled = if price.exponent >= 0 {
(price.price as u128) * 10_u128.pow(price.exponent as u32)
} else {
(price.price as u128) / 10_u128.pow((-price.exponent) as u32)
};
// Calculate output amount using oracle price
let amount_out = (amount_in as u128)
.checked_mul(price_scaled)
.ok_or(ErrorCode::MathOverflow)?
/ 1_000_000; // Adjust for decimals
msg!("Swap {} -> {} using price {}", amount_in, amount_out, price_scaled);
Ok(())
}
#[error_code]
pub enum ErrorCode {
#[msg("Price confidence interval too wide")]
ConfidenceTooWide,
#[msg("Math overflow")]
MathOverflow,
}
Multiple Price Feeds
#[derive(Accounts)]
pub struct Liquidation<'info> {
#[account(
constraint = collateral_price.to_account_info().owner == &pyth_solana_receiver_sdk::ID
)]
pub collateral_price: Account<'info, PriceUpdateV2>,
#[account(
constraint = debt_price.to_account_info().owner == &pyth_solana_receiver_sdk::ID
)]
pub debt_price: Account<'info, PriceUpdateV2>,
}
pub fn check_liquidation(ctx: Context<Liquidation>) -> Result<bool> {
let clock = Clock::get()?;
let collateral = ctx.accounts.collateral_price
.get_price_no_older_than(&clock, 60)?;
let debt = ctx.accounts.debt_price
.get_price_no_older_than(&clock, 60)?;
// Normalize to same exponent for comparison
let collateral_value = normalize_price(collateral.price, collateral.exponent);
let debt_value = normalize_price(debt.price, debt.exponent);
// Check if undercollateralized
let is_liquidatable = collateral_value < debt_value * 150 / 100; // 150% ratio
Ok(is_liquidatable)
}
fn normalize_price(price: i64, expo: i32) -> i128 {
let target_expo = -8; // Normalize to 8 decimals
let adjustment = expo - target_expo;
if adjustment >= 0 {
(price as i128) * 10_i128.pow(adjustment as u32)
} else {
(price as i128) / 10_i128.pow((-adjustment) as u32)
}
}
Best Practices
1. Always Check Staleness
// Don't use old prices - set appropriate max age
let max_age_seconds = 60;
let price = price_update.get_price_no_older_than(&clock, max_age_seconds)?;
2. Validate Confidence Intervals
// Reject prices with wide confidence (high uncertainty)
const MAX_CONF_BPS: u64 = 200; // 2%
let conf_bps = (price.conf as u128 * 10000) / (price.price.unsigned_abs() as u128);
require!(conf_bps <= MAX_CONF_BPS as u128, ErrorCode::ConfidenceTooWide);
3. Verify Account Ownership
// Always verify the price account is owned by Pyth
#[account(
constraint = price_update.to_account_info().owner == &pyth_solana_receiver_sdk::ID
)]
pub price_update: Account<'info, PriceUpdateV2>,
4. Use EMA for Sensitive Operations
// For liquidations, use EMA to avoid manipulation
let ema_price = price_update.get_ema_price_no_older_than(&clock, 60)?;
5. Handle Price Unavailability
try {
const price = await client.getLatestPriceUpdates([feedId]);
// Use price
} catch (error) {
// Fallback behavior or reject transaction
console.error("Price unavailable:", error);
}
6. Consider Frontrunning
- Adversaries may see price updates before your transaction
- Don't design logic that races against price updates
- Use appropriate slippage tolerances
Price Feed Types
Fixed Price Feed Accounts
- Maintained continuously by Pyth
- Fixed address per feed
- Always has most recent price
- Shared by all users (potential congestion)
Ephemeral Price Update Accounts
- Created per transaction
- Can specify shard ID for parallelization
- Rent can be recovered after use
- Better for high-throughput applications
// Use shard ID to avoid congestion
const transactionBuilder = pythReceiver.newTransactionBuilder({
shardId: Math.floor(Math.random() * 65536), // Random shard
});
Resources
Official Documentation
GitHub Repositories
NPM Packages
Rust Crates
Skill Structure
pyth/
βββ SKILL.md # This file
βββ resources/
β βββ program-addresses.md # All program IDs and feed IDs
β βββ api-reference.md # SDK API reference
βββ examples/
β βββ price-feeds/
β β βββ fetch-price.ts # Basic price fetching
β β βββ multiple-prices.ts # Multiple price feeds
β βββ on-chain/
β β βββ anchor-integration.rs # Anchor program example
β β βββ price-validation.rs # Price validation patterns
β βββ streaming/
β βββ real-time-updates.ts # WebSocket streaming
βββ templates/
β βββ pyth-client.ts # TypeScript client template
β βββ anchor-oracle.rs # Anchor program template
βββ docs/
βββ troubleshooting.md # Common issues and solutions
More by sendaifun
View allComplete Metaplex Protocol guide for Solana NFTs and digital assets. Covers Core (next-gen NFTs), Token Metadata, Bubblegum (compressed NFTs), Candy Machine, Genesis (token launches), MPL-Hybrid, Inscriptions, DAS API, and the Umi framework. The single source of truth for all Metaplex integrations.
Complete PumpFun Protocol guide for building token launches, bonding curves, and AMM integrations on Solana. Covers Pump Program (token creation, buy/sell on bonding curves), PumpSwap AMM (liquidity pools, swaps), fee structures, creator fees, and SDK integration.
Complete DFlow trading protocol SDK - the single source of truth for integrating DFlow on Solana. Covers spot trading, prediction markets, Swap API, Metadata API, WebSocket streaming, and all DFlow tools.
Complete Drift Protocol SDK for building perpetual futures, spot trading, and DeFi applications on Solana. Use when building trading bots, integrating Drift markets, managing positions, or working with vaults.
