switchboard について
switchboard は、Switchboard の Solana 向けオラクルプロトコルの統合スキルです。SDK を使った価格フィード、オラクルクオート、ストリーミングデータ、検証可能な乱数の利用方法を開発者向けに案内します。
主な機能
- 01Solana オラクル統合ガイド
- 02プル型価格フィード更新
- 03オラクルクオート統合
- 04Surge WebSocket ストリーミング
- 05VRF 乱数統合
活用シーン
- 01Solana プログラムへの価格データ追加
- 02低レイテンシ価格ストリームの利用
- 03フィード保存なしでのオラクルデータ取得
- 04検証可能なオンチェーン乱数の要求
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ sendaifun/ skills --skill switchboardインストール後、Claude Code で/switchboardを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
docs/troubleshooting.mdexamples/feeds/oracle-quote.tspull-feed.tsread-feed.tsexamples/randomness/vrf-example.tsexamples/setup/example.tsexamples/surge/streaming.tsresources/github-repos.mdprogram-ids.mdrust-reference.mdsdk-reference.mdtemplates/setup.ts詳細
Switchboard Oracle Protocol - 完全統合ガイド
Switchboard を統合するための決定版ガイドです。Switchboard は、Solana 上で最速かつ最もカスタマイズ性に優れた、唯一のパーミッションレスなオラクルプロトコルです。
Switchboard とは?
Switchboard は、業界をリードするパフォーマンスで、開発者が独自のデータをオンチェーンに取り込めるようにする、パーミッションレスなオラクルプロトコルです。
- 価格フィード - プル型の効率性を備えたリアルタイムの資産価格
- オラクルクォート - オンチェーンストレージを使わず、1 秒未満のレイテンシを実現(コストを 90% 削減)
- Surge - 100 ミリ秒未満のレイテンシを実現する WebSocket ストリーミング
- VRF ランダム性 - 暗号学的に安全で検証可能なランダム関数
- 予測市場 - 市場ベースの予測データ
主な統計情報
- オンチェーン取引高 10 億ドル以上 を保護
- Kamino、Jito、MarginFi、Drift Protocol で利用
- Surge の価格フィードで 2〜5 ミリ秒のレイテンシ
- 従来型のオラクルと比較して コストを 90% 削減
基本原則
| 原則 | 説明 |
|---|---|
| 速度 | Surge では 2〜5 ミリ秒、標準では 400 ミリ秒。DeFi 業界をリードする速度です |
| コスト効率 | プル型フィードにより、継続的なストリーミングコストを削減します |
| パーミッションレス | 承認を受けずに、フィードをすぐにデプロイできます |
| セキュリティ | TEE(信頼実行環境)により、データの改ざんを防ぎます |
統合方法
1. オラクルクォート(推奨)
オンチェーンストレージを介さず、オラクルからプログラムにデータを直接渡します。
- 1 秒未満のレイテンシ
- コストを 90% 削減
- 書き込みロックなし(並列読み取り)
- ステートレス設計
2. 従来型フィード
従来のプル型フィード更新方式です。
- フィードアカウントの維持
- クランキング処理
- シンプルなユースケースに適しています
3. Surge(リアルタイム)
高頻度アプリケーション向けの WebSocket ストリーミングです。
- 100 ミリ秒未満のレイテンシ
- 永続的な接続
- トレーディングインターフェースに最適
プログラム ID
| プログラム | Mainnet | Devnet |
|---|---|---|
| オラクルプログラム | SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f | Aio4gaXjXzJNVLtzwtNVmSqGKpANtXhybbkhtAC94ji2 |
| クォートプログラム | orac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz | - |
デフォルトキュー
| ネットワーク | キューアドレス |
|---|---|
| Mainnet | A43DyUGA7s8eXPxqEjJY6EBu1KKbNgfxF8h17VAHn13w |
| Devnet | EYiAmGSdsQTuCw413V5BzaruWuCCSDgTPtBGvLkXHbe7 |
クイックスタート
インストール
# 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(())
}
カスタムフィードの作成
フィードビルダー UI の使用
- ondemand.switchboard.xyz にアクセスします
- 「Create Feed」をクリックします
- データソースと集約方法を設定します
- Mainnet/devnet にデプロイします
- 統合用にフィードハッシュをコピーします
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 |
| 安全性モデル | 完全な検証 | 信頼されたクランカー |
| ユースケース | 標準的な 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);
リソース
公式リンク
- ドキュメント: https://docs.switchboard.xyz -- フィードビルダー: https://ondemand.switchboard.xyz
GitHub リポジトリ
| リポジトリ | 説明 |
|---|---|
| switchboard-sdk | Switchboard SDK の公開ミラー |
| sb-on-demand-examples | 統合例 |
| solana-sdk | Rust SDK |
| on-demand | TypeScript SDK |
コミュニティ
- Discord:https://discord.gg/TJAv6ZYvPC
- Twitter:@switchboardxyz
スキルの構成
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 対応