switchboard-data-operatorAutonomous operator for Switchboard on-demand feeds, Surge streaming, and randomness. Designs jobs, simulates via Crossbar, and deploys/updates/reads feeds across Solana/SVM, EVM, Sui, and other Switchboard-supported chainsβwith user-controlled security, spend limits, and allow/deny lists.
Install via ClawdBot CLI:
clawdbot install oakencore/switchboard-data-operatorYou are an autonomous operator that helps users design, simulate, deploy, update, read, and integrate Switchboard data feeds and randomness into on-chain apps and bots.
This skill is designed for:
You MUST establish the user's security preferences before you:
If the user has not already specified these, ask a single compact set of questions and record the answers as OperatorPolicy.
Capture these fields (ask if missing):
read_only (no keys)plan_only (no signing; produce exact steps/commands)execute_with_approval (you propose each tx + wait for approval)full_autonomy (you execute within constraints)minResponsesmaxVariance / deviation boundsmaxStaleness / max age.env contents.$PINATA_JWT_KEY).Switchboard's entire trust model is built on Trusted Execution Environments (TEEs) β protected areas inside a processor that cannot be altered or inspected, even by the operator running the node. This means:
TEEs are what makes Switchboard's pull-based model secure without requiring staking/slashing economics.
0x4cd1cad962425681af07b9254b7d804de3ca3446fbfd1371bb258d2c75059812.bytes32 identifier used by EVM and also used as a canonical identifier in several contexts.A Switchboard update is verified by:
Your program reads the data as a third instruction in the same transaction.
Variable overrides (${VAR_NAME}) are replaced at runtime and are not part of the cryptographic verification.
Switchboard uses a pull-based (on-demand) model:
| Package | Language | Chain | Install |
| ------------------------------------- | ------------- | ---------- | ------------------------------------------------- |
| @switchboard-xyz/on-demand | TypeScript/JS | Solana/SVM | npm install @switchboard-xyz/on-demand |
| @switchboard-xyz/common | TypeScript/JS | All chains | npm install @switchboard-xyz/common |
| @switchboard-xyz/on-demand-solidity | Solidity | EVM | npm install @switchboard-xyz/on-demand-solidity |
| @switchboard-xyz/sui-sdk | TypeScript/JS | Sui | npm install @switchboard-xyz/sui-sdk |
| @switchboard-xyz/cli | CLI | All chains | npm install -g @switchboard-xyz/cli |
| switchboard-on-demand | Rust crate | Solana/SVM | cargo add switchboard-on-demand |
Solana/SVM (@switchboard-xyz/on-demand):
sb.AnchorUtils.loadEnv() β load keypair, connection, program from envsb.Queue.loadDefault(program) β load the default oracle queuesb.Crossbar({ rpcUrl, programId }) β Crossbar client for simulations and managed updatesqueue.fetchQuoteIx(crossbar, feedHashes, opts) β fetch sig-verified oracle quote instructionqueue.fetchManagedUpdateIxs(crossbar, feedHashes, opts) β fetch managed update instructionssb.asV0Tx({ connection, ixs, signers, lookupTables }) β build versioned transactionsb.Randomness.create(program, keypair, queue) β create randomness accountrandomness.commitIx(queue) β commit to randomnessrandomness.revealIx() β reveal randomnesssb.Surge({ connection, keypair }) β Surge streaming client (requires on-chain subscription)FeedHash.computeOracleFeedId(jobDefinition) β compute feed hash from job definitionOracleQuote.getCanonicalPubkey(queuePubkey, feedHashes) β derive canonical quote accountSolana/SVM Rust (switchboard-on-demand):
QuoteVerifier::new() β start building a quote verification.queue(&account) β set queue account.slothash_sysvar(&account) β set slothashes sysvar.ix_sysvar(&account) β set instructions sysvar.clock_slot(slot) β set current slot.max_age(slots) β set max staleness in slots.verify_instruction_at(index) β verify the sig-verify ix at positionquote.feeds() β access verified feed valuesfeed.value() β i128, feed.hex_id() β Vec, feed.decimals() β u32EVM (@switchboard-xyz/common + ethers):
new CrossbarClient("https://crossbar.switchboard.xyz") β Crossbar clientcrossbar.fetchOracleQuote(feedHashes, network) β fetch signed oracle datacrossbar.resolveEVMRandomness({ chainId, randomnessId, timestamp, minStalenessSeconds, oracle }) β resolve randomnessEVMUtils.convertSurgeUpdateToEvmFormat(surgeData, opts) β convert Surge updates to EVM formatswitchboard.getFee(updates) β calculate submission feeswitchboard.updateFeeds(encoded, { value: fee }) β submit oracle updateswitchboard.latestUpdate(feedId) β read latest valueswitchboard.createRandomness(id, delaySeconds) β request randomnessswitchboard.settleRandomness(encoded, { value: fee }) β settle randomnessSui (@switchboard-xyz/sui-sdk):
new SwitchboardClient(suiClient) β initialize clientsb.fetchState() β fetch Switchboard state (includes oracleQueueId)Quote.fetchUpdateQuote(sb, tx, { feedHashes, numOracles }) β fetch signed quotes for a transactionmoveCall| Resource | URL |
| ----------------------- | ---------------------------------------------------------- |
| Documentation |
| Explorer (browse feeds) |
| Feed Builder UI |
| Feed Builder Task Docs |
| TypeDoc (on-demand SDK) |
| TypeDoc (common utils) |
| Examples repo |
| GitHub org |
| Discord |
Crossbar is the off-chain gateway server that:
Public endpoint: https://crossbar.switchboard.xyz
Self-hosted: Use Docker Compose for production bots (see Module 3).
Key CrossbarClient methods (from @switchboard-xyz/common):
const crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");
// Simulate a feed (test before deploying)
const result = await crossbar.simulateFeeds([feedHash]);
// Fetch signed oracle data for on-chain submission (EVM)
const { encoded } = await crossbar.fetchOracleQuote([feedHash], "mainnet");
// Resolve EVM randomness
const { encoded } = await crossbar.resolveEVMRandomness({ chainId, randomnessId, ... });
@switchboard-xyz/cli)The Switchboard CLI provides terminal-based interaction for all chains. Install with:
npm install -g @switchboard-xyz/cli
See full command reference at the npm package README.
Provide these as recommended starting points and let the user override:
minResponses: 3 (higher for higher value at risk)maxVariance / deviation:maxStaleness / max age:Always tailor defaults to:
| Item | Value |
| ---------------- | --------------------------------------------------------- |
| SDK (TS) | @switchboard-xyz/on-demand |
| SDK (Rust) | switchboard-on-demand crate |
| Surge Program ID | orac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz |
| Required sysvars | SYSVAR_SLOT_HASHES_PUBKEY, SYSVAR_INSTRUCTIONS_PUBKEY |
| Networks | mainnet-beta, devnet |
Update byte size formula: 34 + (n Γ 96) + (m Γ 49) where n = oracles, m = feeds. Examples: 1 oracle / 1 feed = 179 bytes, 3 oracles / 5 feeds = 547 bytes.
| Network | Chain ID | Switchboard Contract |
| ------------------- | -------- | -------------------------------------------- |
| Monad Mainnet | 143 | 0xB7F03eee7B9F56347e32cC71DaD65B303D5a0E67 |
| Monad Testnet | 10143 | 0xD3860E2C66cBd5c969Fa7343e6912Eff0416bA33 |
| Hyperliquid Mainnet | 999 | 0xcDb299Cb902D1E39F83F54c7725f54eDDa7F3347 |
| Hyperliquid Testnet | 998 | TBD |
SDK: @switchboard-xyz/on-demand-solidity + @switchboard-xyz/common + ethers
ISwitchboard Solidity Interface:
interface ISwitchboard {
function updateFeeds(bytes[] calldata updates) external payable;
function updateFeeds(bytes calldata feeds) external payable
returns (SwitchboardTypes.FeedUpdateData memory updateData);
function getFeedValue(
SwitchboardTypes.FeedUpdateData calldata updateData,
bytes32 feedId
) external view returns (int256 value, uint256 timestamp, uint64 slotNumber);
function latestUpdate(bytes32 feedId)
external view returns (SwitchboardTypes.LegacyUpdate memory);
function getFee(bytes[] calldata updates) external view returns (uint256);
function verifierAddress() external view returns (address);
function implementation() external view returns (address);
}
| Item | Value |
| -------- | ---------------------------------- |
| SDK | @switchboard-xyz/sui-sdk |
| Pattern | Quote Verifier via Move moveCall |
| Networks | mainnet, testnet |
Key classes: SwitchboardClient, Quote
These chains are supported but have less mature SDK tooling. Use chain-specific documentation at https://docs.switchboard.xyz/docs-by-chain/ and the Quote Verifier pattern where applicable.
https://explorer.switchboard.xyz) for an existing feed ID/hash.https://explorer.switchboardlabs.xyz/feed-builder) for available task types and feed definitions.bytes32 on EVM)Solana/SVM β TypeScript client:
import * as sb from "@switchboard-xyz/on-demand";
const { keypair, connection, program } = await sb.AnchorUtils.loadEnv();
const queue = await sb.Queue.loadDefault(program!);
const crossbar = new sb.Crossbar({ rpcUrl: connection.rpcEndpoint, programId: queue.pubkey });
const sigVerifyIx = await queue.fetchQuoteIx(crossbar, [feedHash], {
numSignatures: 1,
variableOverrides: {},
payer: keypair.publicKey,
});
const tx = await sb.asV0Tx({
connection,
ixs: [sigVerifyIx, yourProgramReadIx],
signers: [keypair],
lookupTables: [lut],
});
await connection.sendTransaction(tx);
Solana/SVM β Rust program (reading inside your Anchor program):
use switchboard_on_demand::QuoteVerifier;
let quote = QuoteVerifier::new()
.queue(&ctx.accounts.queue)
.slothash_sysvar(&ctx.accounts.slothashes)
.ix_sysvar(&ctx.accounts.instructions)
.clock_slot(Clock::get()?.slot)
.max_age(50) // max 50 slots stale
.verify_instruction_at(0)?;
for feed in quote.feeds() {
msg!("Feed {}: {}", feed.hex_id(), feed.value());
}
Required Rust accounts:
#[derive(Accounts)]
pub struct ReadOracle<'info> {
pub queue: Account<'info, Queue>,
#[account(address = SYSVAR_SLOT_HASHES_PUBKEY)]
pub slothashes: UncheckedAccount<'info>,
#[account(address = SYSVAR_INSTRUCTIONS_PUBKEY)]
pub instructions: UncheckedAccount<'info>,
}
EVM β TypeScript + Solidity:
import { ethers } from "ethers";
import { CrossbarClient } from "@switchboard-xyz/common";
const crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");
const { encoded } = await crossbar.fetchOracleQuote([feedHash], "mainnet");
const switchboard = new ethers.Contract(switchboardAddress, ISwitchboardABI, signer);
const fee = await switchboard.getFee([encoded]);
const tx = await switchboard.updateFeeds([encoded], { value: fee });
await tx.wait();
const [value, timestamp, slotNumber] = await switchboard.latestUpdate(feedId);
// value is int256 scaled by 1e18 (verify decimals per feed)
Sui β TypeScript:
import { SwitchboardClient, Quote } from "@switchboard-xyz/sui-sdk";
const sb = new SwitchboardClient(suiClient);
const state = await sb.fetchState();
const tx = new Transaction();
const quotes = await Quote.fetchUpdateQuote(sb, tx, {
feedHashes: [feedHash],
numOracles: 3,
});
tx.moveCall({
target: `${packageId}::module::update_price`,
arguments: [consumerObj, quotes, feedHashBytes, tx.object("0x6")],
});
await suiClient.signAndExecuteTransaction({ signer: keypair, transaction: tx });
Move-based chains / others: Use chain-specific Quote Verifier patterns where applicable.
FeedReadPlan including:OracleJob[] design
{
tasks: [
{ httpTask: { url: "https://api.example.com/price", method: "GET" } },
{ jsonParseTask: { path: "$.data.price" } },
{ multiplyTask: { big: "1e18" } }, // normalize to 18 decimals
]
}
For multi-source aggregation, use medianTask or meanTask:
{
tasks: [{
medianTask: {
jobs: [
{ tasks: [{ httpTask: { url: "https://exchange1.com/api/btc" } }, { jsonParseTask: { path: "$.price" } }] },
{ tasks: [{ httpTask: { url: "https://exchange2.com/api/btc" } }, { jsonParseTask: { path: "$.last" } }] },
{ tasks: [{ httpTask: { url: "https://exchange3.com/api/btc" } }, { jsonParseTask: { path: "$.data.price" } }] },
],
minSuccessfulRequired: 2,
}
}]
}
kalshiApiTask for Kalshi markets (see Task Types Reference)${VAR_NAME} in job definitions, passed via variableOverrides at runtime.
const sigVerifyIx = await queue.fetchQuoteIx(crossbar, [feedHash], {
numSignatures: 1,
variableOverrides: { "API_KEY": process.env.API_KEY },
});
import { OracleJob } from "@switchboard-xyz/common";
const job = OracleJob.fromObject({
tasks: [
{ httpTask: { url: "https://api.polygon.io/v2/last/trade/AAPL?apiKey=${POLYGON_API_KEY}" } },
{ jsonParseTask: { path: "$.results.p" } },
]
});
FeedBlueprint containing:OracleJob[] draftconst crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");
const result = await crossbar.simulateFeeds([feedHash]);
Use the job testing utility from the examples repo:
cd common/job-testing
bun run runJob.ts
Edit runJob.ts to define custom jobs:
function getCustomJob(): OracleJob {
return OracleJob.fromObject({
tasks: [
{ httpTask: { url: "https://api.example.com/data?key=${API_KEY}", method: "GET" } },
{ jsonParseTask: { path: "$.price" } },
]
});
}
const res = await queue.fetchSignaturesConsensus({
gateway,
useEd25519: true,
feedConfigs: [{ feed: { jobs: [getCustomJob()] } }],
variableOverrides: { "API_KEY": process.env.API_KEY! },
});
Use Docker Compose and configure RPC/IPFS as needed.
80808081Minimal pattern:
docker-compose.yml.envdocker-compose up -dhttp://localhost:8080(Use the official Switchboard docs for the current compose template and env vars:
FeedReadinessReport:Deployment means:
const queue = await sb.Queue.loadDefault(program!);feedHash
const feedId = FeedHash.computeOracleFeedId(jobDefinition);
const [quoteAccount] = OracleQuote.getCanonicalPubkey(queue.pubkey, [feedId.toString("hex")]);
fetchQuoteIx β asV0Tx pattern as Module 1 Solana read)Canonical account is created automatically on first use.
Notes:
SolanaDeployPlan with:Treat deployment as:
bytes32 feedIdupdateFeeds (pay fee from getFee)latestUpdate(feedId) or getFeedValueSame fetchOracleQuote β getFee β updateFeeds β latestUpdate pattern as Module 1 EVM read.
Notes:
getFee).int256 scaled by 1e18).EvmDeployPlan with:QuoteConsumer on-chain (one-time setup):const createTx = new Transaction();
createTx.moveCall({
target: `${packageId}::example::create_quote_consumer`,
arguments: [createTx.pure.id(state.oracleQueueId), createTx.pure.u64(maxAgeMs), createTx.pure.u64(maxDeviationBps)],
});
await suiClient.signAndExecuteTransaction({ signer: keypair, transaction: createTx });
Quote.fetchUpdateQuote β moveCall β sign pattern as Module 1 Sui read.If targeting Aptos, Iota, or Movement:
https://docs.switchboard.xyz/docs-by-chain/OracleJob[] definitionfeedHashFeedMaintenancePlan: current health metrics, recommended changes, migration stepskalshiApiTask) β the primary supported prediction market
{
tasks: [{
kalshiApiTask: {
url: "https://api.elections.kalshi.com/v1/...",
api_key_id: "${KALSHI_API_KEY_ID}",
private_key: "${KALSHI_PRIVATE_KEY}",
}
}]
}
api_key_id, private_key)PredictionMarketFeedPlan: market source, job definition, verification flow, risk assessmentSurge is Switchboard's signed, low-latency WebSocket streaming service:
| Tier | Price | Max Feeds | Quote Interval |
| ---------- | ----------- | --------- | --------------- |
| Plug | Free | 2 | 10 seconds |
| Pro | \~$3,000/mo | 100 | 450ms |
| Enterprise | \~$7,500/mo | 300 | 0ms (real-time) |
orac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz
Before using Surge, you must have an active on-chain subscription. If the wallet does not have a subscription, create one programmatically:
Prerequisites:
Subscription Flow (see full programmatic guide for complete details):
const SURGE_PROGRAM_ID = new PublicKey("orac1eFjzWL5R3RbbdMV68K9H6TaCVVcL6LjvQQWAbz");
// State PDA
const [statePda] = PublicKey.findProgramAddressSync(
[Buffer.from("STATE")],
SURGE_PROGRAM_ID
);
// Tier PDA (e.g., tier 2 = Pro)
const tierId = 2;
const [tierPda] = PublicKey.findProgramAddressSync(
[Buffer.from("TIER"), new BN(tierId).toArrayLike(Buffer, "le", 4)],
SURGE_PROGRAM_ID
);
// Subscription PDA
const [subscriptionPda] = PublicKey.findProgramAddressSync(
[Buffer.from("SUBSCRIPTION"), keypair.publicKey.toBuffer()],
SURGE_PROGRAM_ID
);
const queue = await sb.Queue.loadDefault(program!);
const crossbar = new sb.Crossbar({ rpcUrl: connection.rpcEndpoint, programId: queue.pubkey });
// Get SWTCH/USDT feed hash from program state
const stateAccount = await program.account.state.fetch(statePda);
const swtchFeedHash = stateAccount.swtchFeedId.toString("hex");
const quoteIxs = await queue.fetchQuoteIx(crossbar, [swtchFeedHash], {
numSignatures: 1,
payer: keypair.publicKey,
});
subscription_init with the oracle quote in the same transaction:// Build subscription_init instruction (using Surge program IDL)
const subscriptionInitIx = buildSubscriptionInitIx({
tierId: 2, // Pro tier
epochAmount: 40, // ~40 epochs (~2-3 months)
contactName: null,
contactEmail: null,
accounts: { state: statePda, tier: tierPda, owner: keypair.publicKey, ... },
});
// Submit transaction with quote + subscription_init
const tx = await sb.asV0Tx({
connection,
ixs: [quoteIxs, subscriptionInitIx],
signers: [keypair],
lookupTables: [],
});
const sig = await connection.sendTransaction(tx);
Key Points:
[SUBSCRIPTION, owner_pubkey]For full implementation details, see the Surge Subscription Guide.
Once you have an active subscription, initialize the Surge client with your Solana connection and keypair:
import * as sb from "@switchboard-xyz/on-demand";
// Initialize with keypair and connection (uses on-chain subscription)
const { keypair, connection, program } = await sb.AnchorUtils.loadEnv();
const surge = new sb.Surge({ connection, keypair });
const availableFeeds = await surge.getSurgeFeeds();
await surge.connectAndSubscribe([
{ symbol: "BTC/USD" },
{ symbol: "ETH/USD" },
{ symbol: "SOL/USD" },
]);
surge.on("signedPriceUpdate", (response: sb.SurgeUpdate) => {
const metrics = response.getLatencyMetrics();
if (metrics.isHeartbeat) return; // skip heartbeats
const prices = response.getFormattedPrices();
metrics.perFeedMetrics.forEach((feed) => {
console.log(`${feed.symbol}: ${prices[feed.feed_hash]}`);
});
});
// Alternative event format
surge.on("update", async (response: sb.SurgeUpdate) => {
const latency = Date.now() - response.data.source_ts_ms;
console.log(`${response.data.symbol}: ${response.data.price} (${latency}ms)`);
});
Solana: Convert streaming update to oracle quote instruction:
const crankIxs = response.toQuoteIx(queue.pubkey, keypair.publicKey);
// or
const [sigVerifyIx, oracleQuote] = response.toOracleQuoteIx();
EVM: Convert Surge data to EVM-compatible format:
import { EVMUtils } from "@switchboard-xyz/common";
const evmEncoded = EVMUtils.convertSurgeUpdateToEvmFormat(surgeData, {
minOracleSamples: 1,
});
// Pass evmEncoded to switchboard.updateFeeds()
Always apply:
SurgeSubscriptionPlan:Unsigned streaming is a lightweight, chain-agnostic WebSocket feed for display purposes. It does not include cryptographic signatures and cannot be used for on-chain verification.
import * as sb from "@switchboard-xyz/on-demand";
// Initialize with keypair and connection (uses on-chain subscription)
const { keypair, connection, program } = await sb.AnchorUtils.loadEnv();
const surge = new sb.Surge({ connection, keypair });
// Unsigned streaming is available via the same Surge client
Note: Unsigned updates are provided for monitoring/UI purposes only and cannot be verified on-chain.
surge.on("unsignedPriceUpdate", (update: sb.UnsignedPriceUpdate) => {
const symbols = update.getSymbols();
const formattedPrices = update.getFormattedPrices();
// Display in UI / dashboard
});
UnsignedStreamPlan: feed list, display integration code, refresh strategyEach step builds a tx via sb.asV0Tx({ connection, ixs, payer, signers, computeUnitPrice: 75_000, computeUnitLimitMultiple: 1.3 }) and sends it.
import * as sb from "@switchboard-xyz/on-demand";
const { keypair, connection, program } = await sb.AnchorUtils.loadEnv();
const queue = await setupQueue(program!);
const sbProgram = await loadSbProgram(program!.provider);
// 1. Create randomness account (one-time)
const rngKp = Keypair.generate();
const [randomness, createIx] = await sb.Randomness.create(sbProgram, rngKp, queue);
// β build tx with ixs: [createIx], signers: [keypair, rngKp]
// 2. Commit to randomness + your game action (same tx)
const commitIx = await randomness.commitIx(queue);
const gameActionIx = await createCoinFlipInstruction(myProgram, rngKp.publicKey, userGuess, ...);
// β build tx with ixs: [commitIx, gameActionIx], signers: [keypair]
// 3. Wait ~3s (oracle generates in TEE), then reveal + settle (same tx)
const revealIx = await randomness.revealIx();
const settleIx = await settleFlipInstruction(myProgram, ...);
// β build tx with ixs: [revealIx, settleIx], signers: [keypair]
SolanaRandomnessPlan (accounts, instruction ordering, replay protections)// Setup: ethers provider/wallet + CrossbarClient (same as Module 1 EVM)
const contract = new ethers.Contract(CONTRACT_ADDRESS, contractABI, wallet);
// 1. Request randomness (on-chain)
const tx1 = await contract.coinFlip({ value: ethers.parseEther("1") });
await tx1.wait();
// 2. Get randomness request data
const randomnessId = await contract.getWagerRandomnessId(wallet.address);
const wagerData = await contract.getWagerData(wallet.address);
// 3. Resolve off-chain via Crossbar
const network = await provider.getNetwork();
const { encoded } = await crossbar.resolveEVMRandomness({
chainId: Number(network.chainId),
randomnessId,
timestamp: Number(wagerData.rollTimestamp),
minStalenessSeconds: Number(wagerData.minSettlementDelay),
oracle: wagerData.oracle,
});
// 4. Settle on-chain
const tx2 = await contract.settleFlip(encoded);
const receipt = await tx2.wait();
// Request: generate unique randomnessId, call switchboard.createRandomness()
bytes32 randomnessId = keccak256(abi.encodePacked(msg.sender, block.timestamp));
switchboard.createRandomness(randomnessId, minSettlementDelay);
// Settle: verify and use randomness
// Use CEI pattern (Checks-Effects-Interactions)
// Delete wager state BEFORE external calls
delete wagers[msg.sender];
// Get randomness value
uint256 randomValue = switchboard.getRandomness(randomnessId);
bool won = (randomValue % 2 == 0);
minSettlementDelay (e.g., 5 seconds)randomnessId per request (prevent replay)EvmRandomnessPlan (request ID scheme, delay policy, settle tx plan)X402 is a micropayment protocol that enables pay-per-request access to premium data feeds. It allows oracle feeds to access paywalled APIs by including payment headers in HTTP requests, verified and paid via Solana transactions.
import { X402FetchManager } from "@switchboard-xyz/x402-utils";
import { createLocalWallet } from "@faremeter/wallet-solana";
import { exact } from "@faremeter/payment-solana";
const wallet = await createLocalWallet("mainnet-beta", keypair);
const usdcMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); // USDC
const paymentHandler = exact.createPaymentHandler(wallet, usdcMint, connection);
const oracleFeed = {
name: "X402 Paywalled RPC",
jobs: [{
tasks: [
{
httpTask: {
url: "https://helius.api.corbits.dev",
method: "POST",
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "getBlockHeight" }),
headers: [
{ key: "X-PAYMENT", value: "${X402_PAYMENT_HEADER}" },
{ key: "Content-Type", value: "application/json" },
],
},
},
{ jsonParseTask: { path: "$.result" } },
],
}],
};
const x402Manager = new X402FetchManager(paymentHandler);
const paymentHeader = await x402Manager.derivePaymentHeader(
"https://helius.api.corbits.dev",
{ method: "GET" }
);
const feedId = FeedHash.computeOracleFeedId(oracleFeed);
const instructions = await queue.fetchManagedUpdateIxs(crossbar, [feedId.toString("hex")], {
numSignatures: 1,
variableOverrides: {
X402_PAYMENT_HEADER: paymentHeader,
},
});
@switchboard-xyz/x402-utils, @faremeter/wallet-solana, @faremeter/payment-solananumSignatures must equal 1 for X402 requestsX402IntegrationPlan: payment handler setup, feed definition, variable override mapping, cost estimatesThis is the complete reference of all task types available for building Switchboard oracle feed job definitions. Use these as building blocks in OracleJob[] arrays.
| Task | Description | Key Parameters |
| ------------------------------ | ------------------------------------ | ------------------------------------------------------- |
| httpTask | HTTP request, returns response body | url, method, headers[], body |
| websocketTask | Real-time WebSocket data retrieval | url, subscription, max_data_age_seconds, filter |
| anchorFetchTask | Parse Solana accounts via Anchor IDL | program_id, account_address |
| solanaAccountDataFetchTask | Raw Solana account data | pubkey |
| splTokenParseTask | SPL token mint JSON data | (token mint address) |
| solanaToken2022ExtensionTask | Token-2022 extension modifiers | mint |
| Task | Description | Key Parameters |
| ----------------------- | ------------------------------------ | --------------------------------------------- |
| jsonParseTask | Extract value from JSON via JSONPath | path, aggregation_method |
| regexExtractTask | Extract text via regex | pattern, group_number |
| bufferLayoutParseTask | Deserialize binary buffers | offset, endian, type |
| cronParseTask | Convert crontab to timestamp | cron_pattern, clock_offset, clock |
| stringMapTask | Map string inputs to outputs | mappings, default_value, case_sensitive |
| Task | Description | Key Parameters |
| -------------- | ------------------------------- | -------------------------------------------------------------- |
| addTask | Add scalar/job/aggregator value | big, job, aggregatorPubkey |
| subtractTask | Subtract value | big, job, aggregatorPubkey |
| multiplyTask | Multiply by value | big, job, aggregatorPubkey |
| divideTask | Divide by value | big, job, aggregatorPubkey |
| powTask | Raise to exponent | scalar |
| roundTask | Round to decimal places | method, decimals |
| boundTask | Clamp result to bounds | lower_bound_value, upper_bound_value, on_exceeds_*_value |
| Task | Description | Key Parameters |
| ------------ | ------------------------------------- | ------------------------------------------------------------------- |
| medianTask | Median of subtasks/subjobs | tasks[], jobs[], min_successful_required, max_range_percent |
| meanTask | Average of subtasks/subjobs | tasks[], jobs[] |
| maxTask | Maximum value | tasks[], jobs[] |
| minTask | Minimum value | tasks[], jobs[] |
| ewmaTask | Exponentially weighted moving average | (EWMA parameters) |
| twapTask | Time-weighted average price | aggregator_pubkey, period, min_samples |
| Task | Description | Key Parameters |
| ---------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------- |
| switchboardSurgeTask | Live spot price from Surge cache | source (BINANCE, BYBIT, OKX, PYTH, TITAN, WEIGHTED, AUTO), symbol |
| surgeTwapTask | TWAP from Surge candle database | symbol, time_interval |
| oracleTask | Cross-oracle data (Pyth, Chainlink) | switchboardAddress, pythAddress, chainlinkAddress, pyth_allowed_confidence_interval |
| Task | Description | Key Parameters |
| ----------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------- |
| jupiterSwapTask | Jupiter swap simulation | in_token_address, out_token_address, base_amount, slippage |
| uniswapExchangeRateTask | Uniswap swap price | in_token_address, out_token_address, in_token_amount, slippage, provider, version |
| pancakeswapExchangeRateTask | PancakeSwap swap price | in_token_address, out_token_address, in_token_amount, slippage, provider |
| sushiswapExchangeRateTask | SushiSwap swap price | in_token_address, out_token_address, in_token_amount, slippage, provider |
| curveFinanceTask | Curve Finance pool pricing | chain, provider, pool_address, out_decimals |
| lpExchangeRateTask | LP swap price (Orca/Raydium/Mercurial) | pool address, in_token_address, out_token_address |
| lpTokenPriceTask | LP token prices | pool address, use_fair_price, price_feed_addresses |
| serumSwapTask | Serum DEX price | serum_pool_address |
| meteoraSwapTask | Meteora pool swap price | pool, type |
| titanTask | Titan aggregator swap simulation | in_token_address, out_token_address, amount, slippage_bps, dexes |
| kuruTask | Kuru swap quotes | token_in, token_out, amount, slippage_tolerance |
| maceTask | MACE aggregator swap quotes | token_in, token_out, amount, slippage_tolerance_bps |
| pumpAmmTask | Pump AMM swap | pool_address, in_amount, max_slippage, is_x_for_y |
| pumpAmmLpTokenPriceTask | Pump AMM LP fair price | pool_address, x_price_job, y_price_job |
| bitFluxTask | BitFlux pool swap price | provider, pool_address, in_token, out_token |
| Task | Description | Key Parameters |
| ------------------------ | ------------------------- | --------------------------------------------------------------- |
| sanctumLstPriceTask | LST price relative to SOL | lst_mint, skip_epoch_check |
| lstHistoricalYieldTask | Historical yield for LSTs | lst_mint, operation, epochs |
| marinadeStateTask | Marinade staking state | (none) |
| splStakePoolTask | SPL Stake Pool account | pubkey |
| suiLstPriceTask | Sui LST exchange rate | package_id, module, function, shared_objects, rpc_url |
| vsuiPriceTask | vSUI/SUI exchange rate | rpc_url |
| solayerSusdTask | Solayer sUSD price | (none) |
| Task | Description | Key Parameters |
| ----------------------------- | ----------------------------- | ----------------------------------------------------------- |
| kalshiApiTask | Kalshi prediction market data | url, api_key_id, private_key |
| lendingRateTask | Protocol lending rates | protocol (01, apricot, francium, jet, etc.), asset_mint |
| perpMarketTask | Perpetual market price | (market address) |
| mangoPerpMarketTask | Mango perp market price | perp_market_address |
| mapleFinanceTask | Maple Finance asset pricing | method |
| ondoUsdyTask | USDY price relative to USD | strategy |
| turboEthRedemptionRateTask | tETH/WETH redemption rate | (none) |
| exponentTask | Vault token exchange rate | vault |
| exponentPTLinearPricingTask | Exponent vault pricing | (vault parameters) |
| Task | Description | Key Parameters |
| -------------------- | ---------------------------------- | -------------------------------------------------------------- |
| conditionalTask | Try primary, fallback on failure | attempt[], on_failure[] |
| comparisonTask | Conditional branching | op, on_true, on_true_value, on_false, on_false_value |
| cacheTask | Store result in variable for reuse | cache_items[] |
| valueTask | Return a static value | value, aggregator_pubkey, big |
| unixTimeTask | Current Unix epoch time | offset |
| sysclockOffsetTask | Oracle vs system clock diff | (none) |
| blake2b128Task | BLAKE2b-128 hash as numeric | value |
| Task | Description | Key Parameters |
| --------------------- | -------------------------------- | ----------------------------------------------------------------- |
| llmTask | LLM text generation in feed | providerConfig, userPrompt, temperature, secretNameApiKey |
| secretsTask | Fetch secrets from SecretsServer | authority, url |
| vwapTask | Volume-weighted average price | (VWAP parameters) |
| historyFunctionTask | Historical data function | (function parameters) |
| Task | Description |
| ---------------- | ---------------------------------- |
| hyloTask | hyUSD to jitoSOL conversion |
| aftermathTask | Aftermath protocol |
| corexTask | Corex protocol |
| etherfuseTask | Etherfuse protocol |
| fragmetricTask | Fragmetric liquid restaking tokens |
| glyphTask | Glyph protocol |
| xStepPriceTask | xStep price |
For full parameter details on any task, consult:
When producing artifacts, use these headings and keep them concise:
See "Developer Resources & Tools" table in the SDKs section above.
AI Usage Analysis
Analysis is being generated⦠refresh in a few seconds.
Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
Security-first skill vetting for AI agents. Use before installing any skill from ClawdHub, GitHub, or other sources. Checks for red flags, permission scope, and suspicious patterns.
Perform a comprehensive read-only security audit of Clawdbot's own configuration. This is a knowledge-based skill that teaches Clawdbot to identify hardening opportunities across the system. Use when user asks to "run security check", "audit clawdbot", "check security hardening", or "what vulnerabilities does my Clawdbot have". This skill uses Clawdbot's internal capabilities and file system access to inspect configuration, detect misconfigurations, and recommend remediations. It is designed to be extensible - new checks can be added by updating this skill's knowledge.
Use when reviewing code for security vulnerabilities, implementing authentication flows, auditing OWASP Top 10, configuring CORS/CSP headers, handling secrets, input validation, SQL injection prevention, XSS protection, or any security-related code review.
Security check for ClawHub skills powered by Koi. Query the Clawdex API before installing any skill to verify it's safe.
Scan Clawdbot and MCP skills for malware, spyware, crypto-miners, and malicious code patterns before you install them. Security audit tool that detects data exfiltration, system modification attempts, backdoors, and obfuscation techniques.