switchboard

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Switchboard Oracle Protocol - Complete Integration Guide

Switchboard预言机协议——完整集成指南

The definitive guide for integrating Switchboard - the fastest, most customizable, and only permissionless oracle protocol on Solana.
本指南是集成Switchboard的权威参考,Switchboard是Solana上速度最快、可定制性最强且唯一的无需许可预言机协议。

What is Switchboard?

什么是Switchboard?

Switchboard is a permissionless oracle protocol enabling developers to bring custom data on-chain with industry-leading performance:
  • Price Feeds - Real-time asset pricing with pull-based efficiency
  • Oracle Quotes - Sub-second latency without on-chain storage (90% cost reduction)
  • Surge - WebSocket streaming with sub-100ms latency
  • VRF Randomness - Cryptographically secure verifiable random functions
  • Prediction Markets - Market-based forecasting data
Switchboard是一款无需许可的预言机协议,能让开发者将自定义数据上链,具备行业领先的性能:
  • 价格馈送 - 基于拉取模式的高效实时资产定价
  • Oracle Quotes - 亚秒级延迟,无需链上存储(成本降低90%)
  • Surge - 延迟低于100毫秒的WebSocket流传输
  • VRF随机数 - 加密安全的可验证随机函数
  • 预测市场 - 基于市场的预测数据

Key Statistics

核心统计数据

  • Secures $1B+ in on-chain volume
  • Used by Kamino, Jito, MarginFi, Drift Protocol
  • 2-5ms latency with Surge pricing
  • 90% cost reduction vs traditional oracles
  • 保障链上交易量超10亿美元
  • 被Kamino、Jito、MarginFi、Drift Protocol等项目采用
  • Surge定价模式下延迟2-5毫秒
  • 相比传统预言机成本降低90%

Core Principles

核心原则

PrincipleDescription
Speed2-5ms with Surge, 400ms standard - industry-leading for DeFi
Cost EfficiencyPull-based feeds eliminate constant streaming costs
PermissionlessDeploy feeds instantly without approvals
SecurityTEE (Trusted Execution Environments) prevent data manipulation
原则描述
速度Surge模式下延迟2-5毫秒,标准模式下400毫秒——DeFi领域行业领先
成本效益拉取式馈送消除了持续流传输的成本
无需许可无需审批即可即时部署馈送
安全性TEE(可信执行环境)防止数据篡改

Integration Approaches

集成方式

1. Oracle Quotes (Recommended)

1. Oracle Quotes(推荐)

Direct oracle-to-program data flow without on-chain storage:
  • Sub-second latency
  • 90% cost reduction
  • No write locks (parallel reads)
  • Stateless design
预言机到程序的直接数据流,无需链上存储:
  • 亚秒级延迟
  • 成本降低90%
  • 无写入锁(支持并行读取)
  • 无状态设计

2. Traditional Feeds

2. 传统馈送

Classic pull-based feed updates:
  • Feed account maintenance
  • Cranking operations
  • Good for simple use cases
经典的拉取式馈送更新:
  • 馈送账户维护
  • 触发操作
  • 适用于简单使用场景

3. Surge (Real-Time)

3. Surge(实时)

WebSocket streaming for high-frequency applications:
  • Sub-100ms latency
  • Persistent connections
  • Ideal for trading interfaces
适用于高频应用的WebSocket流传输:
  • 延迟低于100毫秒
  • 持久化连接
  • 理想的交易界面解决方案

Program IDs

程序ID

ProgramMainnetDevnet
Oracle Program
SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f
Aio4gaXjXzJNVLtzwtNVmSqGKpANtXhybbkhtAC94ji2
Quote Program
orac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz
-
程序主网测试网
Oracle Program
SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f
Aio4gaXjXzJNVLtzwtNVmSqGKpANtXhybbkhtAC94ji2
Quote Program
orac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz
-

Default Queues

默认队列

NetworkQueue Address
Mainnet
A43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w
Devnet
EYiAmGSdsQTuCw413V5BzaruWuCCSDgTPtBGvLkXHbe7
网络队列地址
主网
A43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w
测试网
EYiAmGSdsQTuCw413V5BzaruWuCCSDgTPtBGvLkXHbe7

Quick Start

快速开始

Installation

安装

bash
undefined
bash
undefined

TypeScript SDK

TypeScript SDK

npm install @switchboard-xyz/on-demand @switchboard-xyz/common
npm install @switchboard-xyz/on-demand @switchboard-xyz/common

Rust (Cargo.toml)

Rust (Cargo.toml)

switchboard-on-demand = "0.8.0"

switchboard-on-demand = "0.8.0"

undefined
undefined

Basic Setup

基础配置

typescript
import { web3, AnchorProvider, Program } from "@coral-xyz/anchor";
import {
  PullFeed,
  CrossbarClient,
  ON_DEMAND_MAINNET_PID,
  ON_DEMAND_DEVNET_PID
} from "@switchboard-xyz/on-demand";

// Setup connection and provider
const connection = new web3.Connection("https://api.mainnet-beta.solana.com");
const wallet = useWallet(); // or Keypair
const provider = new AnchorProvider(connection, wallet);

// Load Switchboard program
const sbProgram = await Program.at(ON_DEMAND_MAINNET_PID, provider);

// Initialize Crossbar client for oracle communication
const crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");
typescript
import { web3, AnchorProvider, Program } from "@coral-xyz/anchor";
import {
  PullFeed,
  CrossbarClient,
  ON_DEMAND_MAINNET_PID,
  ON_DEMAND_DEVNET_PID
} from "@switchboard-xyz/on-demand";

// 配置连接和提供者
const connection = new web3.Connection("https://api.mainnet-beta.solana.com");
const wallet = useWallet(); // 或 Keypair
const provider = new AnchorProvider(connection, wallet);

// 加载Switchboard程序
const sbProgram = await Program.at(ON_DEMAND_MAINNET_PID, provider);

// 初始化Crossbar客户端用于预言机通信
const crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");

Price Feeds

价格馈送

Fetch and Update Feed

获取并更新馈送

typescript
import { PullFeed, asV0Tx } from "@switchboard-xyz/on-demand";

// Create feed account reference
const feedPubkey = new web3.PublicKey("YOUR_FEED_PUBKEY");
const feedAccount = new PullFeed(sbProgram, feedPubkey);

// Fetch update instruction with oracle signatures
const { pullIx, responses, numSuccess, luts } = await feedAccount.fetchUpdateIx({
  crossbarClient: crossbar,
  chain: "solana",
  network: "mainnet", // or "devnet"
});

// Build and send transaction
const tx = await asV0Tx({
  connection,
  ixs: [pullIx],
  signers: [payer],
  computeUnitPrice: 200_000,
  computeUnitLimitMultiple: 1.3,
  lookupTables: luts,
});

const signature = await connection.sendTransaction(tx);
console.log("Feed updated:", signature);
typescript
import { PullFeed, asV0Tx } from "@switchboard-xyz/on-demand";

// 创建馈送账户引用
const feedPubkey = new web3.PublicKey("YOUR_FEED_PUBKEY");
const feedAccount = new PullFeed(sbProgram, feedPubkey);

// 获取带预言机签名的更新指令
const { pullIx, responses, numSuccess, luts } = await feedAccount.fetchUpdateIx({
  crossbarClient: crossbar,
  chain: "solana",
  network: "mainnet", // 或 "devnet"
});

// 构建并发送交易
const tx = await asV0Tx({
  connection,
  ixs: [pullIx],
  signers: [payer],
  computeUnitPrice: 200_000,
  computeUnitLimitMultiple: 1.3,
  lookupTables: luts,
});

const signature = await connection.sendTransaction(tx);
console.log("馈送已更新:", signature);

Read Feed Value

读取馈送值

typescript
// Get current feed value
const feedData = await feedAccount.loadData();
const value = feedData.value.toNumber();
const lastUpdated = feedData.lastUpdatedSlot;

console.log(`Price: ${value}, Last Updated: ${lastUpdated}`);
typescript
// 获取当前馈送值
const feedData = await feedAccount.loadData();
const value = feedData.value.toNumber();
const lastUpdated = feedData.lastUpdatedSlot;

console.log(`价格: ${value}, 最后更新插槽: ${lastUpdated}`);

Oracle Quotes (Recommended)

Oracle Quotes(推荐)

Oracle Quotes provide the most efficient way to consume oracle data:
typescript
import { OracleQuote } from "@switchboard-xyz/on-demand";

// Feed hashes (64-char hex strings)
const feedHashes = [
  "0x...", // SOL/USD
  "0x...", // BTC/USD
];

// Derive canonical quote account
const queueKey = new web3.PublicKey("A43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w");
const quotePubkey = OracleQuote.getCanonicalPubkey(queueKey, feedHashes);

// Fetch quote instruction
const sigVerifyIx = await queue.fetchQuoteIx(crossbar, feedHashes, {
  numSignatures: 1,
  variableOverrides: {},
});
Oracle Quotes是消费预言机数据最高效的方式:
typescript
import { OracleQuote } from "@switchboard-xyz/on-demand";

// 馈送哈希(64字符十六进制字符串)
const feedHashes = [
  "0x...", // SOL/USD
  "0x...", // BTC/USD
];

// 派生标准报价账户
const queueKey = new web3.PublicKey("A43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w");
const quotePubkey = OracleQuote.getCanonicalPubkey(queueKey, feedHashes);

// 获取报价指令
const sigVerifyIx = await queue.fetchQuoteIx(crossbar, feedHashes, {
  numSignatures: 1,
  variableOverrides: {},
});

Rust Integration (Oracle Quotes)

Rust集成(Oracle Quotes)

rust
use anchor_lang::prelude::*;
use switchboard_on_demand::{default_queue, SwitchboardQuoteExt, SwitchboardQuote};

#[program]
pub mod my_program {
    use super::*;

    pub fn read_oracle_data(ctx: Context<ReadOracleData>) -> Result<()> {
        let feeds = &ctx.accounts.quote_account.feeds;
        let current_slot = ctx.accounts.sysvars.clock.slot;
        let quote_slot = ctx.accounts.quote_account.slot;

        // Check staleness
        let staleness = current_slot.saturating_sub(quote_slot);
        require!(staleness < 100, ErrorCode::StaleFeed);

        for feed in feeds.iter() {
            msg!("Feed {}: Value = {}", feed.hex_id(), feed.value());
        }

        Ok(())
    }
}

#[derive(Accounts)]
pub struct ReadOracleData<'info> {
    #[account(address = quote_account.canonical_key(&default_queue()))]
    pub quote_account: Box<Account<'info, SwitchboardQuote>>,
    pub sysvars: Sysvars<'info>,
}

#[derive(Accounts)]
pub struct Sysvars<'info> {
    pub clock: Sysvar<'info, Clock>,
}
rust
use anchor_lang::prelude::*;
use switchboard_on_demand::{default_queue, SwitchboardQuoteExt, SwitchboardQuote};

#[program]
pub mod my_program {
    use super::*;

    pub fn read_oracle_data(ctx: Context<ReadOracleData>) -> Result<()> {
        let feeds = &ctx.accounts.quote_account.feeds;
        let current_slot = ctx.accounts.sysvars.clock.slot;
        let quote_slot = ctx.accounts.quote_account.slot;

        // 检查数据新鲜度
        let staleness = current_slot.saturating_sub(quote_slot);
        require!(staleness < 100, ErrorCode::StaleFeed);

        for feed in feeds.iter() {
            msg!("馈送 {}: 值 = {}", feed.hex_id(), feed.value());
        }

        Ok(())
    }
}

#[derive(Accounts)]
pub struct ReadOracleData<'info> {
    #[account(address = quote_account.canonical_key(&default_queue()))]
    pub quote_account: Box<Account<'info, SwitchboardQuote>>,
    pub sysvars: Sysvars<'info>,
}

#[derive(Accounts)]
pub struct Sysvars<'info> {
    pub clock: Sysvar<'info, Clock>,
}

Surge (Real-Time Streaming)

Surge(实时流传输)

For applications requiring real-time price updates:
typescript
import { SwitchboardSurge } from "@switchboard-xyz/on-demand";

// Initialize Surge client
const surge = new SwitchboardSurge({
  apiKey: "YOUR_API_KEY", // Optional
  gatewayUrl: "wss://surge.switchboard.xyz",
  autoReconnect: true,
  maxReconnectAttempts: 5,
  reconnectDelay: 1000,
});

// Subscribe to feeds
surge.subscribe(["SOL/USD", "BTC/USD"]);

// Handle events
surge.on("connected", () => {
  console.log("Connected to Surge");
});

surge.on("data", (data) => {
  console.log(`${data.symbol}: ${data.price}`);
});

surge.on("error", (error) => {
  console.error("Surge error:", error);
});

surge.on("disconnected", () => {
  console.log("Disconnected from Surge");
});
适用于需要实时价格更新的应用:
typescript
import { SwitchboardSurge } from "@switchboard-xyz/on-demand";

// 初始化Surge客户端
const surge = new SwitchboardSurge({
  apiKey: "YOUR_API_KEY", // 可选
  gatewayUrl: "wss://surge.switchboard.xyz",
  autoReconnect: true,
  maxReconnectAttempts: 5,
  reconnectDelay: 1000,
});

// 订阅馈送
surge.subscribe(["SOL/USD", "BTC/USD"]);

// 处理事件
surge.on("connected", () => {
  console.log("已连接到Surge");
});

surge.on("data", (data) => {
  console.log(`${data.symbol}: ${data.price}`);
});

surge.on("error", (error) => {
  console.error("Surge错误:", error);
});

surge.on("disconnected", () => {
  console.log("已断开与Surge的连接");
});

VRF Randomness

VRF随机数

Cryptographically secure on-chain randomness:
加密安全的链上随机数:

TypeScript Client

TypeScript客户端

typescript
import { RandomnessService } from "@switchboard-xyz/on-demand";

// Request randomness
const randomnessAccount = await RandomnessService.create(sbProgram, {
  queue: queuePubkey,
  callback: {
    programId: myProgramId,
    accounts: [...],
    ixData: Buffer.from([...]),
  },
});

// Reveal randomness (after oracle fulfillment)
const randomValue = await randomnessAccount.reveal();
console.log("Random value:", randomValue);
typescript
import { RandomnessService } from "@switchboard-xyz/on-demand";

// 请求随机数
const randomnessAccount = await RandomnessService.create(sbProgram, {
  queue: queuePubkey,
  callback: {
    programId: myProgramId,
    accounts: [...],
    ixData: Buffer.from([...]),
  },
});

// 揭示随机数(预言机完成后)
const randomValue = await randomnessAccount.reveal();
console.log("随机值:", randomValue);

Rust Integration

Rust集成

rust
use switchboard_on_demand::RandomnessAccountData;

pub fn consume_randomness(ctx: Context<ConsumeRandomness>) -> Result<()> {
    let randomness_data = RandomnessAccountData::parse(
        ctx.accounts.randomness_account.to_account_info()
    )?;

    // Use the random value
    let random_value = randomness_data.get_value(&ctx.accounts.clock)?;

    // Example: coin flip
    let is_heads = random_value[0] % 2 == 0;

    Ok(())
}
rust
use switchboard_on_demand::RandomnessAccountData;

pub fn consume_randomness(ctx: Context<ConsumeRandomness>) -> Result<()> {
    let randomness_data = RandomnessAccountData::parse(
        ctx.accounts.randomness_account.to_account_info()
    )?;

    // 使用随机值
    let random_value = randomness_data.get_value(&ctx.accounts.clock)?;

    // 示例:抛硬币
    let is_heads = random_value[0] % 2 == 0;

    Ok(())
}

Creating Custom Feeds

创建自定义馈送

Using Feed Builder UI

使用Feed Builder界面

  1. Visit ondemand.switchboard.xyz
  2. Click "Create Feed"
  3. Configure data sources and aggregation
  4. Deploy to mainnet/devnet
  5. Copy feed hash for integration
  1. 访问 ondemand.switchboard.xyz
  2. 点击“Create Feed”
  3. 配置数据源和聚合规则
  4. 部署到主网/测试网
  5. 复制馈送哈希用于集成

Using TypeScript SDK

使用TypeScript SDK

typescript
import { FeedBuilder } from "@switchboard-xyz/on-demand";

const feedConfig = new FeedBuilder()
  .addJob({
    tasks: [
      {
        httpTask: {
          url: "https://api.example.com/price",
        },
      },
      {
        jsonParseTask: {
          path: "$.price",
        },
      },
    ],
  })
  .setMinResponses(3)
  .setMaxVariance(0.1);

const feedHash = await feedConfig.build();
typescript
import { FeedBuilder } from "@switchboard-xyz/on-demand";

const feedConfig = new FeedBuilder()
  .addJob({
    tasks: [
      {
        httpTask: {
          url: "https://api.example.com/price",
        },
      },
      {
        jsonParseTask: {
          path: "$.price",
        },
      },
    ],
  })
  .setMinResponses(3)
  .setMaxVariance(0.1);

const feedHash = await feedConfig.build();

Framework Comparison

框架对比

AspectAnchor (Basic)Pinocchio (Advanced)
Learning CurveBeginner-friendlyAdvanced only
Compute Units~2,000 CU~190 CU
Safety ModelFull validationTrusted cranker
Use CasesStandard DeFiOracle AMMs, HFT
维度Anchor(基础)Pinocchio(进阶)
学习曲线新手友好仅适用于进阶开发者
计算单元~2,000 CU~190 CU
安全模型完整验证可信触发者
使用场景标准DeFi预言机AMM、高频交易

Best Practices

最佳实践

1. Staleness Checks

1. 新鲜度检查

Always verify feed freshness:
rust
let staleness = current_slot.saturating_sub(feed_slot);
require!(staleness < MAX_STALENESS_SLOTS, ErrorCode::StaleFeed);
始终验证馈送的新鲜度:
rust
let staleness = current_slot.saturating_sub(feed_slot);
require!(staleness < MAX_STALENESS_SLOTS, ErrorCode::StaleFeed);

2. Multiple Signatures

2. 多签名

Request multiple oracle signatures for critical operations:
typescript
const { pullIx } = await feedAccount.fetchUpdateIx({
  numSignatures: 3, // Increase for higher security
});
对于关键操作,请求多个预言机签名:
typescript
const { pullIx } = await feedAccount.fetchUpdateIx({
  numSignatures: 3, // 增加数量以提升安全性
});

3. Error Handling

3. 错误处理

typescript
try {
  const { pullIx, numSuccess } = await feedAccount.fetchUpdateIx({...});

  if (numSuccess < minRequired) {
    throw new Error(`Insufficient oracle responses: ${numSuccess}`);
  }
} catch (error) {
  if (error.message.includes("timeout")) {
    // Retry with different oracles
  }
  throw error;
}
typescript
try {
  const { pullIx, numSuccess } = await feedAccount.fetchUpdateIx({...});

  if (numSuccess < minRequired) {
    throw new Error(`预言机响应不足: ${numSuccess}`);
  }
} catch (error) {
  if (error.message.includes("timeout")) {
    // 使用其他预言机重试
  }
  throw error;
}

4. Compute Budget

4. 计算预算

For complex operations, increase compute budget:
typescript
import { ComputeBudgetProgram } from "@solana/web3.js";

const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
  units: 400_000,
});

const tx = new Transaction()
  .add(modifyComputeUnits)
  .add(pullIx)
  .add(yourInstruction);
对于复杂操作,增加计算预算:
typescript
import { ComputeBudgetProgram } from "@solana/web3.js";

const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
  units: 400_000,
});

const tx = new Transaction()
  .add(modifyComputeUnits)
  .add(pullIx)
  .add(yourInstruction);

Resources

资源

Official Links

官方链接

GitHub Repositories

GitHub仓库

RepositoryDescription
switchboardMain SDK repository
sb-on-demand-examplesIntegration examples
solana-sdkRust SDK
on-demandTypeScript SDK
仓库描述
switchboard主SDK仓库
sb-on-demand-examples集成示例
solana-sdkRust SDK
on-demandTypeScript SDK

Community

社区

Skill Structure

技能结构

switchboard/
├── SKILL.md                    # This file
├── resources/
│   ├── program-ids.md          # All program addresses and queues
│   ├── sdk-reference.md        # TypeScript SDK API reference
│   ├── rust-reference.md       # Rust SDK reference
│   └── github-repos.md         # Repository links
├── examples/
│   ├── setup/
│   │   └── example.ts          # Basic setup
│   ├── feeds/
│   │   ├── pull-feed.ts        # Pull feed updates
│   │   ├── oracle-quote.ts     # Oracle quote integration
│   │   └── read-feed.ts        # Read feed values
│   ├── randomness/
│   │   └── vrf-example.ts      # VRF randomness
│   └── surge/
│       └── streaming.ts        # Real-time streaming
├── templates/
│   └── setup.ts                # Complete starter template
└── docs/
    └── troubleshooting.md      # Common issues
switchboard/
├── SKILL.md                    # 本文档
├── resources/
│   ├── program-ids.md          # 所有程序地址和队列
│   ├── sdk-reference.md        # TypeScript SDK API参考
│   ├── rust-reference.md       # Rust SDK参考
│   └── github-repos.md         # 仓库链接
├── examples/
│   ├── setup/
│   │   └── example.ts          # 基础配置
│   ├── feeds/
│   │   ├── pull-feed.ts        # 拉取馈送更新
│   │   ├── oracle-quote.ts     # Oracle Quotes集成
│   │   └── read-feed.ts        # 读取馈送值
│   ├── randomness/
│   │   └── vrf-example.ts      # VRF随机数
│   └── surge/
│       └── streaming.ts        # 实时流传输
├── templates/
│   └── setup.ts                # 完整启动模板
└── docs/
    └── troubleshooting.md      # 常见问题