Price Feeds Tutorial

Example Code: The complete working example for this tutorial is available at sb-on-demand-examples/sui/feeds/basicarrow-up-right

This tutorial walks you through integrating Switchboard oracle price feeds into your Sui Move contracts using the Quote Verifier pattern. You'll learn how to securely fetch, verify, and use real-time price data.

What You'll Build

A Move contract that:

  • Fetches real-time price data from multiple Switchboard oracles

  • Verifies oracle signatures cryptographically

  • Validates data freshness and price deviation

  • Stores verified prices for your DeFi logic

Plus a TypeScript client that fetches oracle data and submits it to your contract.

Prerequisites

  • Node.js 18+ and npm/pnpm

  • A Sui keypair with SUI tokens (testnet or mainnet)

  • Basic understanding of Move and TypeScript

Key Concepts

The Quote Verifier Pattern

Switchboard uses a Quote Verifier pattern to ensure oracle data is legitimate. The verifier:

  • Checks that data comes from authorized oracles on the correct queue

  • Tracks timestamps and slots to prevent replay attacks

  • Enables custom validation logic (freshness, deviation limits)

Why Use Quote Verifier?

Without verification:

  • Anyone could submit fake prices if you don't check the queue ID

  • You'd have to track last update timestamps yourself

  • Stale data could be replayed to manipulate prices

With verification:

  • Only data from the authorized oracle queue is accepted

  • Automatic freshness checks prevent stale data

  • Replay attacks are prevented

  • You don't need to manually track update timestamps

Feed Hashes

Each price feed has a unique 32-byte hex identifier. You can find feed hashes in the Switchboard Explorerarrow-up-right.

Example: BTC/USD feed hash:

The Move Contract

Here's the complete Move contract that consumes oracle data with built-in verification:

Contract Walkthrough

Imports

  • QuoteVerifier - Manages quote verification and storage

  • Quotes - The signed oracle data structure

  • Decimal - Switchboard's decimal type for price values

QuoteConsumer Struct

The QuoteConsumer is a shared object that stores:

  • quote_verifier: Handles signature verification and prevents replay attacks

  • last_price: Most recent verified price

  • last_update_time: Timestamp for freshness checks

  • max_age_ms: Maximum acceptable quote age (e.g., 300000 = 5 minutes)

  • max_deviation_bps: Maximum price change in basis points (e.g., 1000 = 10%)

The update_price Function

This is the core function that processes oracle data:

  1. verify_quotes() - Verifies all oracle signatures and ensures they're from the correct queue

  2. quote_exists() - Confirms the requested feed is in the quotes

  3. get_quote() - Retrieves the verified quote data

  4. Freshness check - Rejects data older than 10 seconds

  5. Deviation check - Prevents sudden price jumps that might indicate manipulation

  6. Store and emit - Updates state and emits a PriceUpdated event

Business Logic Examples

The contract includes example functions for common DeFi use cases:

The TypeScript Client

Here's the complete TypeScript client that creates a QuoteConsumer and updates prices:

Client Walkthrough

Step 1: Create QuoteConsumer

This creates a shared QuoteConsumer object tied to Switchboard's oracle queue.

Step 2: Fetch Oracle Quotes

Quote.fetchUpdateQuote() contacts Crossbar to get signed price data from multiple oracles. The quotes object is added to the transaction automatically.

Step 3: Update Price

This calls your contract's update_price function with the fetched quotes. The Move contract will verify signatures and update the stored price.

Project Structure

Available Scripts

Running the Example

1. Clone the Examples Repository

2. Install Dependencies

3. Build the Move Contract

4. Deploy the Contract

Save the package ID from the deployment output.

5. Run the Example

Expected Output

Adding to Your Project

1. Add Switchboard to Move.toml

2. Import in Your Move Module

3. Add Quote Verifier to Your Struct

4. TypeScript Dependencies

Available Feeds

Asset
Feed Hash

BTC/USD

0x4cd1cad962425681af07b9254b7d804de3ca3446fbfd1371bb258d2c75059812

ETH/USD

0xa0950ee5ee117b2e2c30f154a69e17bfb489a7610c508dc5f67eb2a14616d8ea

SOL/USD

0x822512ee9add93518eca1c105a38422841a76c590db079eebb283deb2c14caa9

SUI/USD

0x7ceef94f404e660925ea4b33353ff303effaf901f224bdee50df3a714c1299e9

Find more feeds at the Switchboard Explorerarrow-up-right.

Deployments

Network
Package ID

Mainnet

0xa81086572822d67a1559942f23481de9a60c7709c08defafbb1ca8dffc44e210

Testnet

0x28005599a66e977bff26aeb1905a02cda5272fd45bb16a5a9eb38e8659658cff

Troubleshooting

"EInvalidQuote"

  • The requested feed hash is not in the quotes

  • Verify the feed hash is correct and included in fetchUpdateQuote()

"EQuoteExpired"

  • Quote data is older than 10 seconds

  • Fetch fresh data before calling update_price()

  • Check network latency

"EPriceDeviationTooHigh"

  • Price changed more than the configured max_deviation_bps

  • This can happen during high volatility

  • Adjust the threshold if needed for your use case

"EInvalidQueue"

  • The quotes are from a different oracle queue

  • Verify you're using the correct queue ID for your network (mainnet vs testnet)

Build Errors

Next Steps

  • Multiple Feeds: Pass multiple feed hashes to fetchUpdateQuote() to update several prices in one transaction

  • Real-time Streaming: See the Surge Price Streamarrow-up-right tutorial for WebSocket-based streaming

  • Custom Feeds: Learn how to create custom data feeds in the Custom Feeds section

Last updated