NOTICE: Switchboard On-Demand on EVM is currently an unaudited alpha.
First Steps!
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.
Installation
You can install the Switchboard On-Demand Solidity SDK by running:
npminstall@switchboard-xyz/on-demand-solidity
And you can install the cross-chain Typescript SDK by running:
npminstall@switchboard-xyz/on-demand
Forge (Optional)
If you're using Forge, add following to your remappings.txt file:
IMPORTANT: Feeds will NOT work unless they been created on-chain.
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.
Get the aggregatorId
When you create a feed in the UI, you'll see a field titled Address, which corresponds to the aggregatorId. This is how feeds will be identified on the Switchboard contract.
Feeds only exist per network
Feeds only exist on a single network. A feed created on Arbitrum will not work if one tries to read its result onto Morph. The feed would need to be re-created on Morph for it to work.
Step 2: Solidity Integration
Solidity
The code below shows the flow for leveraging Switchboard feeds in Solidity.
pragmasolidity ^0.8.0;import {ISwitchboard} from"@switchboard-xyz/on-demand-solidity/ISwitchboard.sol";contract Example { ISwitchboard switchboard;// Every Switchboard feed has a unique aggregator id bytes32 aggregatorId;// Store the latest valueint128public result;// If the transaction fee is not paid, the update will fail.errorInsufficientFee(uint256 expected,uint256 received);// If the feed result is invalid, this error will be emitted.errorInvalidResult(int128 result);// If the Switchboard update succeeds, this event will be emitted with the latest price.eventFeedData(int128 price);/** * @param _switchboard The address of the Switchboard contract * @param _aggregatorId The feed ID for the feed you want to query */constructor(address_switchboard,bytes32_aggregatorId) {// Initialize the target _switchboard// Get the existing Switchboard contract address on your preferred network from the Switchboard Docs switchboard =ISwitchboard(_switchboard); aggregatorId = _aggregatorId; }/** * 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 */functiongetFeedData(bytes[] calldata updates) publicpayable {// Get the fee for updating the feeds. If the transaction fee is not paid, the update will fail.uint256 fees = switchboard.getFee(updates);if (msg.value < fee) {revertInsufficientFee(fee, msg.value); }// Submit the updates to the Switchboard contract switchboard.updateFeeds{ value: fees }(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)// This is encoded as decimal * 10^18 to avoid floating point issues result = switchboard.latestUpdate(aggregatorId).result;// In this example, we revert if the result is negativeif (result <0) {revertInvalidResult(result); }// Emit the latest result from the feedemitFeedData(latestUpdate.result); }}
This contract:
Sets the Switchboard contract address and aggregator ID in the constructor
Defines a function getFeedData
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 aggregatorId).
Emits the latest result from the feed.
Step 3: Using the Feed
Simulating a Result
You might want to show some ticker on a user interface for a particular Switchboard feed. Using Crossbar and its Typescript SDK.
import { CrossbarClient,} from"@switchboard-xyz/on-demand";// for initial testing and development, you can use the rate-limited // https://crossbar.switchboard.xyz instance of crossbarconstcrossbar=newCrossbarClient("https://crossbar.switchboard.xyz");// fetch simulated resultsconstresults=awaitcrossbar.simulateEVMFeeds(1115,// chainId (Core Testnet is 1115) ["0x0eae481a0c635fdfa18ccdccc0f62dfc34b6ef2951f239d4de4acfab0bcdca71"],// aggregator ID's);console.log(results);
Using 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 { CrossbarClient,} from"@switchboard-xyz/on-demand";// Get Crossbar instance for querying updates // for initial testing and development, you can use the rate-limited // https://crossbar.switchboard.xyz instance of crossbarconstcrossbar=newCrossbarClient("http://myCrossbarDeployment.com");// Create a Switchboard On-Demand jobconstchainId=1115; // Core Devnet (as an example)// Get the latest update data for a set of feeds// encoded: `bytes` string of the encoded update for the feed which can be used in your contractconst { encoded } =awaitcrossbar.fetchEVMResults({ chainId, aggregatorIds });// Target contract addressconstexampleAddress="<MY_CONTRACT_ADDRESS>";// The ERC-20 Contract ABI, which is a common contract interface// for tokens (this is the Human-Readable ABI format)constabi= ["function getFeedData(bytes[] calldata updates) public payable"];// ... Setup ethers provider ...// The Contract objectconstexampleContract=newethers.Contract(exampleAddress, abi, provider);// Update feedsawaitexampleContract.getFeedData(encoded);// Fetch the current value (for fun)console.log(awaitexampleContract.result());