switchboard
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSwitchboard 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
核心原则
| Principle | Description |
|---|---|
| Speed | 2-5ms with Surge, 400ms standard - industry-leading for DeFi |
| Cost Efficiency | Pull-based feeds eliminate constant streaming costs |
| Permissionless | Deploy feeds instantly without approvals |
| Security | TEE (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
| Program | Mainnet | Devnet |
|---|---|---|
| Oracle Program | | |
| Quote Program | | - |
| 程序 | 主网 | 测试网 |
|---|---|---|
| Oracle Program | | |
| Quote Program | | - |
Default Queues
默认队列
| Network | Queue Address |
|---|---|
| Mainnet | |
| Devnet | |
| 网络 | 队列地址 |
|---|---|
| 主网 | |
| 测试网 | |
Quick Start
快速开始
Installation
安装
bash
undefinedbash
undefinedTypeScript 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"
undefinedundefinedBasic 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界面
- Visit ondemand.switchboard.xyz
- Click "Create Feed"
- Configure data sources and aggregation
- Deploy to mainnet/devnet
- Copy feed hash for integration
- 访问 ondemand.switchboard.xyz
- 点击“Create Feed”
- 配置数据源和聚合规则
- 部署到主网/测试网
- 复制馈送哈希用于集成
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
框架对比
| Aspect | Anchor (Basic) | Pinocchio (Advanced) |
|---|---|---|
| Learning Curve | Beginner-friendly | Advanced only |
| Compute Units | ~2,000 CU | ~190 CU |
| Safety Model | Full validation | Trusted cranker |
| Use Cases | Standard DeFi | Oracle 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
官方链接
- Documentation: https://docs.switchboard.xyz -- Feed Builder: https://ondemand.switchboard.xyz
- 文档: https://docs.switchboard.xyz -- Feed Builder: https://ondemand.switchboard.xyz
GitHub Repositories
GitHub仓库
| Repository | Description |
|---|---|
| switchboard | Main SDK repository |
| sb-on-demand-examples | Integration examples |
| solana-sdk | Rust SDK |
| on-demand | TypeScript SDK |
| 仓库 | 描述 |
|---|---|
| switchboard | 主SDK仓库 |
| sb-on-demand-examples | 集成示例 |
| solana-sdk | Rust SDK |
| on-demand | TypeScript SDK |
Community
社区
- Discord: https://discord.gg/TJAv6ZYvPC
- Twitter: @switchboardxyz
- Discord: https://discord.gg/TJAv6ZYvPC
- Twitter: @switchboardxyz
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 issuesswitchboard/
├── 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 # 常见问题