sendaifun

pyth

38
6
# Install this skill:
npx skills add sendaifun/skills --skill "pyth"

Install specific skill from multi-skill repository

# 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.

# SKILL.md


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

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_price and ema_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

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.