DISCLAIMER: SWITCHBOARD ON-DEMAND FOR SUI IS UNAUDITED. USE AT YOUR OWN RISK.
Installation
You can install the Switchboard On-Demand Typescript Sui-SDK by running:
# Add the Switchboard Sui Typescriptnpmadd@switchboard-xyz/sui-sdk
Creating a Feed
If you're already familiarized with Designing a Feed, building on Sui should be a quick and easy process.
import { CrossbarClient, SwitchboardClient, Aggregator, ON_DEMAND_MAINNET_QUEUE, ON_DEMAND_TESTNET_QUEUE,} from"@switchboard-xyz/sui-sdk";// for initial testing and development, you can use the public// https://crossbar.switchboard.xyz instance of crossbarconstcrossbar=newCrossbarClient("https://crossbar.switchboard.xyz");// ... define some jobs ...constqueue= isMainnetSui ?ON_DEMAND_MAINNET_QUEUE:ON_DEMAND_TESTNET_QUEUE;// Store some job definitionconst { feedHash } =awaitcrossbarClient.store(queue.pubkey.toBase58(), jobs);// Create a SwitchboardClient using the SuiClient configured with your favorite RPC on testnet or mainnetconstsb=newSwitchboardClient(suiClient);// try creating a feedconstfeedName="BTC/USDT";// Require only one oracle response neededconstminSampleSize=1;// Allow update data to be up to 60 seconds oldconstmaxStalenessSeconds=60;// If jobs diverge more than 1%, don't allow the feed to produce a valid updateconstmaxVariance=1e9;// Require only 1 job responseconstminJobResponses=1;//==========================================================// Feed Initialization On-Chain//==========================================================let transaction =newTransaction();// add the tx to the PTBawaitAggregator.initTx(sb, transaction, { feedHash, name: feedName, authority: userAddress, minSampleSize, maxStalenessSeconds, maxVariance, minResponses: minJobResponses,});// Send the transactionconstres=awaitclient.signAndExecuteTransaction({ signer: keypair, transaction, options: { showEffects:true, },});// Capture the created aggregator IDlet aggregatorId;res.effects?.created?.forEach((c) => {if (c.reference.objectId) { aggregatorId =c.reference.objectId; }});// Wait for transaction confirmationawaitclient.waitForTransaction({ digest:res.digest,});// Log the transaction effectsconsole.log(res);
Updating Feeds
With Switchboard On-Demand, you can just pass your PTB into the feed update method and everything else will be handled for you.
constaggregator=newAggregator(sb, aggregatorId);// create the PTBlet feedTx =newTransaction();// Fetch the oracle responses (and write them onto the tx)constresponse=awaitaggregator.fetchUpdateTx(feedTx);// Log the raw oracle responses from Switchboard console.log("Fetch Update Oracle Response: ", response);// send the transactionconstres=awaitclient.signAndExecuteTransaction({ signer: keypair, transaction: feedTx, options: { showEffects:true, },});// wait for the transaction to be confirmedawaitclient.waitForTransaction({ digest:res.digest,});// log the effectsconsole.log(res);
Note: You should make sure that the Switchboard Aggregator update is the first action in your PTB (or at least happens before the feed update is referenced).
Adding Switchboard to your Move Code
Start by updating your Move.toml to include Switchboard. Switchboard uses Sui Move2024 Beta Edition and should be fairly simple to integrate into your existing project.
Move.toml
[dependencies.switchboard]git ="https://github.com/switchboard-xyz/sui.git"subdir ="on_demand"rev ="testnet"# change to mainnet when ready to use mainnet[dependencies.Sui]git ="https://github.com/MystenLabs/sui.git"subdir ="crates/sui-framework/packages/sui-framework"rev ="framework/testnet"# change to framework/mainnet for mainnet# override = true # uncomment this if this gives you conflicts
Once dependencies are sorted out, you should be able to easily reference your updated aggregators.
example.move
module example::switchboard;// Import the Switchboard Aggregator Type and Current Resultuse switchboard::aggregator::{Aggregator, CurrentResult};// Switchboard Decimal type (fixed scale of 18 / 18 decimal places)use switchboard::decimal::Decimal;public entry fun use_switchboard_value( aggregator:&Aggregator,) { // get the latest update info for the feedlet current_result = aggregator.current_result();// get the medianlet result:Decimal= current_result.result();// get the value as a u128 (decimal * 10^18)let result_u128:u128= result.value();// -- Other functions available to you on the Aggregator's CurrentResult -- // get the oldest timestamp of the data considered in computing the result (ms)let min_timestamp_ms:u64= current_result.min_timestamp_ms();// get the latest timestamp in millisecondslet max_timestamp_ms:u64= current_result.max_timestamp_ms();// get the range (maximum value considered - minimum value)let range:Decimal= current_result.range();// get the average (mean) let mean:Decimal= current_result.mean();// get the standard deviation of the computed resultslet stdev:Decimal= current_result.stdev();// get the maximum result of the computed windowlet max_result:Decimal= current_result.max_result();// get the minimumlet min_result:Decimal= current_result.min_result();// check if the result is negative (ignore this if you're using price data)let neg:bool= result.neg();// ... use computed result for something ...}
And with this kind of implementation you'll be able to read Switchboard data feeds.