@switchboard-xyz/on-demand-solidity
v0.0.4
Published
Switchboard Solidity SDK
Downloads
31
Readme
Switchboard On-Demand on EVM
A collection of libraries and examples for interacting with Switchboard on EVM chains.
NOTE: Switchboard On-Demand on EVM is currently an unaudited alpha. Use at your own risk.
Documentation and examples for using Switchboard On-Demand on Ethereum Virtual Machine (EVM) Networks. With Switchboard On-Demand, users can customize and create low-latency data feeds from any source.
Current Deployments
Core Mainnet: 0x33A5066f65f66161bEb3f827A3e40fce7d7A2e6C Core Testnet: 0x2f833D73bA1086F3E5CDE9e9a695783984636A76 Arbitrum Sepolia: 0xa2a0425fa3c5669d384f4e6c8068dfcf64485b3b Arbitrum One: 0xad9b8604b6b97187cde9e826cdeb7033c8c37198 Morph Holesky: 0x3c1604DF82FDc873D289a47c6bb07AFA21f299e5
Table of Contents
Overview
Switchboard On-Demand is a decentralized oracle service that allows users to create custom data feeds on the Ethereum Virtual Machine (EVM) networks. Users can create a feed that specifies the data sources, aggregation method, and other parameters. Once the feed is created, users can query Switchboard oracles to resolve it, and verify the data on-chain. This is an example of a pull-based oracle service, where users can request custom data on-demand with low-latency and low gas cost.
Getting Started
To get started with Switchboard On-Demand, you will need to install the Switchboard CLI and set up a Switchboard account. You can then create a Switchboard On-Demand job and query the oracle to get the data.
There's a Solidity-SDK that you can use to interact with the oracle contract on-chain and leverage customized oracle data within your smart contracts. For querying oracle updates off-chain for on-chain submission, you can use the Switchboard On-Demand Typescript-SDK.
Prerequisites
To use Switchboard On-Demand, you will need to have a basic understanding of Ethereum and smart contracts. For more on Switchboard's Architecture, see the docs (EVM docs will be consolidated with main docs upon completion of audit).
Installation
You can install the Switchboard On-Demand Solidity SDK by running:
npm install @switchboard-xyz/on-demand-solidity
And you can install the cross-chain Typescript SDK by running:
npm install @switchboard-xyz/on-demand
Forge (Optional)
If you're using Forge, add following to your remappings.txt file: @switchboard-xyz/on-demand-solidity/=node_modules/@switchboard-xyz/on-demand-solidity
Usage
Designing a Switchboard On-Demand Feed
To design a Switchboard On-Demand feed, you can use the On-Demand Builder. Switchboard Feeds are created by specifying data sources and aggregation methods in an OracleJob format.
Here's an example of creating a feed for querying ETH/USDC on Binance:
import {
createJob,
simulateJob,
getDevnetQueue,
} from "@switchboard-xyz/on-demand";
// ...
const job = createJob({
tasks: [
{
httpTask: "https://api.binance.com/api/v3/ticker/price?symbol=ETHUSDC",
},
{
jsonParseTask: "$.price",
},
],
});
// Get the latest update data for the feed
const result = await simulateFeed({
// Within feeds you can have multiple jobs, the final result will be the median of all jobs
jobs: [job],
// Here we'll use devnet because we're going to be using a non-prod network
queue: await getDevnetQueue(),
});
console.log(result); // Job's output price, feedId (derived from Job Definition, and Switchboard Queue ID)
Solidity
The code below shows the flow for leveraging Switchboard feeds in Solidity.
pragma solidity ^0.8.0;
import {ISwitchboard} from "@switchboard-xyz/on-demand-solidity/ISwitchboard.sol";
import {Structs} from "@@switchboard-xyz/on-demand-solidity/structs/Structs.sol";
contract Example {
ISwitchboard switchboard;
// Every Switchboard Feed has a unique feed ID derived from the OracleJob definition and Switchboard Queue ID.
bytes32 feedId;
// If the transaction fee is not paid, the update will fail.
error InsufficientFee(uint256 expected, uint256 received);
// If the feed result is invalid, this error will be emitted.
error InvalidResult(int128 result);
// If the Switchboard update succeeds, this event will be emitted with the latest price.
event FeedData(int128 price);
/**
* @param _switchboard The address of the Switchboard contract
* @param _feedId The feed ID for the feed you want to query
*/
constructor(address _switchboard, bytes32 _feedId) {
// Initialize the target _switchboard
// Get the existing Switchboard contract address on your preferred network from the Switchboard Docs
switchboard = ISwitchboard(_switchboard);
feedId = _feedId;
}
/**
* getFeedData is a function that uses an encoded Switchboard update
* If the update is successful, it will read the latest price from the feed
* See below for fetching encoded updates (e.g., using the Switchboard Typescript SDK)
* @param updates Encoded feed updates to update the contract with the latest result
*/
function getFeedData(bytes[] calldata updates) public payable {
// Get the fee for updating the feeds. If the transaction fee is not paid, the update will fail.
uint256 fee = switchboard.getFee(updates);
if (msg.value < fee) {
revert InsufficientFee(fee, msg.value);
}
// Submit the updates to the Switchboard contract
switchboard.updateFeeds{ value: fee }(updates);
// Read the current value from a Switchboard feed.
// This will fail if the feed doesn't have fresh updates ready (e.g. if the feed update failed)
Structs.Update latestUpdate = switchboard.getLatestValue(feedId);
// Get the latest feed result
// This is encoded as decimal * 10^18 to avoid floating point issues
// Some feeds require negative numbers, so results are int128's, but this example uses positive numbers
int128 result = latestUpdate.result;
// In this example, we revert if the result is negative
if (result < 0) {
revert InvalidResult(result);
}
// Emit the latest result from the feed
emit FeedData(latestUpdate.result);
}
}
This contract:
- Sets the Switchboard contract address and feed ID in the constructor
- Defines a function
getFeedData
that:- Checks if the transaction fee is paid, using
switchboard.getFee(bytes[] calldata updates)
- Submits the updates to the Switchboard contract using
switchboard.updateFeeds(bytes[] calldata updates)
- Reads the latest value from the feed using
switchboard.getLatestValue(bytes32 feedId)
- Emits the latest result from the feed
- Checks if the transaction fee is paid, using
Getting the Encoded Updates
To get the encoded updates for the feed, you can use the Switchboard Typescript SDK. Here's an example of how to get the encoded updates:
import * as ethers from "ethers";
interface OracleData {
oracle_pubkey: string;
queue_pubkey: string;
oracle_signing_pubkey: string;
feed_hash: string;
recent_hash: string;
failure_error: string;
success_value: string;
msg: string;
signature: string;
recovery_id: number;
recent_successes_if_failed: any[];
timestamp: number;
result: number;
}
interface FeedResponse {
encoded: string[];
results: OracleData[];
}
// Create a Switchboard On-Demand job
const results = await fetch(
"https://crossbar.switchboard.xyz/updates/evm/1116/0xfd2b067707a96e5b67a7500e56706a39193f956a02e9c0a744bf212b19c7246c"
);
// Target contract address
const exampleAddress = "0xc65f0acf9df6b4312d3f3ce42a778767b3e66b8a";
// for tokens (this is the Human-Readable ABI format)
const abi = ["function getFeedData(bytes[] calldata updates) public payable"];
// ... Setup ethers provider ...
// The Contract object
const exampleContract = new ethers.Contract(exampleAddress, abi, provider);