Skip to content

rangesecurity/oracle-example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Oracle — Risk Score Example on Solana (via Switchboard On-Demand)

This repository demonstrates how to fetch off-chain data from Range’s Risk API using a Switchboard On-Demand Oracle, and verify the result fully on-chain inside a Solana program.

The example uses:

  • 2 implementations for the on-chain program ( Pinocchio and Anchor)
  • Switchboard On-Demand for fetching + signing off-chain data
  • Range API for providing trusted risk scores
  • TypeScript client for building and submitting the transaction

Note: The Anchor and Pinocchio programs are intentionally equivalent, showcasing how Switchboard On-Demand can be used in either framework.


Overview

  1. Client side:

    • Builds a Range Risk Score feed (HTTP + JSON parse + multiply + bound tasks)
    • Requests Switchboard to fetch, sign, and return a quote for that feed
    • Builds two instructions:
      1. sigVerifyIx — verifies Switchboard’s Ed25519 signatures
      2. getRiskScoreIx — calls your on-chain program
  2. On-chain program:

    • Reconstructs the exact same feed definition
    • Hashes it (SHA-256(length-delimited-protobuf)) -> feed_id
    • Uses QuoteVerifier from switchboard-on-demand to verify:
    • The quote signatures
    • The quote’s feed_id matches the derived one
    • The quote is fresh and valid
  • Logs the verified risk score (0–100)

If the feed hash doesn’t match or the quote is stale, the transaction fails — ensuring tamper-proof, auditable oracle data.


How It Works

  1. The Feed (client/sdk.ts)

The feed describes what the oracle should fetch and how to process it:

export function getRangeRiskScoreJob(): OracleJob {
  return OracleJob.fromObject({
    tasks: [
      {
        httpTask: {
          url: 'https://api.range.org/v1/risk/address?address=<ADDRESS>&network=solana',
          headers: [
            { key: 'accept', value: 'application/json' },
            { key: 'X-API-KEY', value: '${RANGE_API_KEY}' }, // resolved off-chain
          ],
        },
      },
      { jsonParseTask: { path: '$.riskScore' } },
      { multiplyTask: { scalar: 10 } }, // Scale 0–10 → 0–100
      { boundTask: { lowerBoundValue: '0', upperBoundValue: '100' } },
    ],
  });
}

Switchboard hashes the serialized feed proto → feed_id.

  1. Request a Quote getOracleJobSignature():
  • Passes the feed directly to Switchboard’s fetchQuoteIx
  • Oracles execute the feed tasks, sign the result, and return a quote
  • No need to pre-store the feed on Crossbar — it’s processed on-demand

Returns:

  • sigVerifyIx: Ed25519 verification instruction (index 0)
  • queue_account: the Switchboard queue to use
  1. Order Ixs and send the transaction

  2. Verify on chain entrypoint.rs reconstructs the feed, hashes it, and verifies:

  • The quote signatures (using QuoteVerifier)
  • The quote’s feed_id matches the on-chain derived hash
  • If matched, logs the risk score

Run the Example

Install dependencies

cd anchor/client # or pinocchio/client
npm install
  1. Run the test
npm test

Expected output:

Using Payer: <YOUR_PAYER_PUBKEY>

[
  { value: '100000000000000000000', feed_hash: '...', num_oracles: 1 }
]
FeedId: 0xee6ffd4f...
Fetched RiskScore Via Oracle. Tx: 2ZQs9febdjypEd5C43FkmyvTQiJe41Xcb44dBzx9DsQ1X9sSvniS76c6Tft8QiM2kf5jEbN6sgyCcN5ZZqEhuqC8
✔ initializes the Oracle and call the Oracle Program

On the explorer logs you should see:

Program log: Risk Score 100

Security Guarantees

  • Deterministic feed hash: Any feed change (URL, headers, or tasks) changes the hash → rejects stale or spoofed quotes.

  • On-chain signature verification: The first transaction instruction must be the Ed25519 verification ix. The program checks it using Switchboard’s QuoteVerifier.

  • Freshness enforcement: Uses Clock and SlotHashes sysvars to reject old quotes.

  • Secret safety: ${RANGE_API_KEY} is injected only off-chain via variableOverrides; never stored or sent on-chain.

Integration Pattern

To integrate Range + Switchboard in your own Solana program:

  1. Define your feed in TypeScript (HTTP → Parse → Transform → Bound)
  2. Request a quote using fetchQuoteIx
  3. In your program, reconstruct the same feed and hash it
  4. Use QuoteVerifier to check signatures + freshness
  5. Compare the feed IDs and trust only matching results

About

This repo describes how Range APIs can be used programaticly on chain powered by Switchboard.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published