mcpField
S
switchboard

switchboard

github.com/sendaifun数据与数据库130189 次安装13 周前更新
代码仓库

关于 switchboard

switchboard 是面向 Switchboard Solana 预言机协议的集成技能,供开发者参考。内容涵盖通过 SDK 接入价格源、预言机报价、实时数据流和可验证随机数。

主要功能

  1. 01Solana 预言机集成指南
  2. 02拉取式价格源更新
  3. 03预言机报价集成
  4. 04Surge WebSocket 实时数据流
  5. 05VRF 随机数集成

适用场景

  1. 01为 Solana 程序添加价格数据
  2. 02使用低延迟价格流
  3. 03无需存储 Feed 即可读取预言机数据
  4. 04请求可验证的链上随机数

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sendaifun/skills --skill switchboard

安装后在 Claude Code 中输入/switchboard确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

docs/
troubleshooting.md
examples/feeds/
oracle-quote.ts
pull-feed.ts
read-feed.ts
examples/randomness/
vrf-example.ts
examples/setup/
example.ts
examples/surge/
streaming.ts
resources/
github-repos.md
program-ids.md
rust-reference.md
sdk-reference.md
templates/
setup.ts

详细介绍

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

这是集成 Switchboard 的权威指南。Switchboard 是 Solana 上速度最快、最灵活、唯一无需许可的预言机协议。

什么是 Switchboard?

Switchboard 是一种无需许可的预言机协议,可让开发者以业界领先的性能将自定义数据引入链上:

  • 价格馈送 - 采用拉取式机制,高效提供实时资产定价
  • 预言机报价 - 亚秒级延迟,无需链上存储(成本降低 90%)
  • Surge - 通过 WebSocket 进行流式传输,延迟低于 100 ms
  • VRF 随机性 - 采用密码学安全的可验证随机函数
  • 预测市场 - 基于市场的预测数据
关键数据
  • 保障链上交易量 10 亿美元以上
  • Kamino、Jito、MarginFi、Drift Protocol 均在使用
  • Surge 定价模式下延迟为 2–5 ms
  • 与传统预言机相比,成本降低 90%

核心原则

原则说明
速度Surge 延迟为 2–5 ms,标准模式为 400 ms,在 DeFi 领域处于业界领先水平
成本效益拉取式数据馈送无需承担持续流式传输成本
无需许可无需审批即可立即部署数据馈送
安全性TEE(可信执行环境)可防止数据被篡改

集成方式

1. 预言机报价(推荐)

无需链上存储,直接将数据从预言机传输到程序:

  • 亚秒级延迟
  • 成本降低 90%
  • 无写入锁(支持并行读取)
  • 无状态设计
2. 传统数据馈送

经典的拉取式数据馈送更新:

  • 维护数据馈送账户
  • 执行 Cranking 操作
  • 适用于简单场景
3. Surge(实时)

通过 WebSocket 流式传输,适用于高频应用:

  • 延迟低于 100 ms
  • 持久连接
  • 非常适合交易界面

程序 ID

程序MainnetDevnet
Oracle ProgramSW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64fAio4gaXjXzJNVLtzwtNVmSqGKpANtXhybbkhtAC94ji2
Quote Programorac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz-
默认队列
网络队列地址
MainnetA43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w
DevnetEYiAmGSdsQTuCw413V5BzaruWuCCSDgTPtBGvLkXHbe7

快速开始

安装
# TypeScript SDK
npm install @switchboard-xyz/on-demand @switchboard-xyz/common

# Rust (Cargo.toml)
# switchboard-on-demand = "0.8.0"
基本设置
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");

价格馈送

获取并更新数据馈送
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);
读取数据馈送值
// 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}`);

预言机报价(推荐)

预言机报价提供了最高效的预言机数据使用方式:

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: {},
});
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>,
}

Surge(实时流式传输)

适用于需要实时价格更新的应用:

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");
});

VRF 随机性

采用密码学安全的链上随机性:

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);
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(())
}

创建自定义数据馈送

使用数据馈送构建器界面
  1. 访问 ondemand.switchboard.xyz
  2. 点击“Create Feed”
  3. 配置数据源和聚合方式
  4. 部署到 mainnet/devnet
  5. 复制数据馈送哈希以进行集成
使用 TypeScript SDK
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();

框架对比

方面Anchor(基础)Pinocchio(高级)
学习曲线适合初学者仅适合高级用户
计算单元~2,000 CU~190 CU
安全模型完整验证信任 Cranker
使用场景标准 DeFi预言机 AMM、HFT

最佳实践

1. 检查数据是否过时

始终验证数据馈送的新鲜度:

let staleness = current_slot.saturating_sub(feed_slot);
require!(staleness < MAX_STALENESS_SLOTS, ErrorCode::StaleFeed);
2. 多重签名

对于关键操作,请求多个预言机签名:

const { pullIx } = await feedAccount.fetchUpdateIx({
  numSignatures: 3, // Increase for higher security
});
3. 错误处理
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;
}
4. 计算预算

对于复杂操作,请提高计算预算:

import { ComputeBudgetProgram } from "@solana/web3.js";

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

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

资源

官方链接
GitHub 仓库
仓库描述
switchboard-sdkSwitchboard SDK 的公开镜像
sb-on-demand-examples集成示例
solana-sdkRust SDK
on-demandTypeScript SDK
社区

技能结构

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

评论

支持 Markdown