updated feed-walkthrough example
This commit is contained in:
parent
a8c045614b
commit
e0514925d3
|
@ -0,0 +1,59 @@
|
|||
# Switchboard-V2 Feed Walkthrough
|
||||
|
||||
This example will walk you through
|
||||
|
||||
- creating a personal oracle queue with a crank
|
||||
- add a SOL/USD data feed onto the crank
|
||||
- spin up a docker environment to run your own oracle
|
||||
- fulfill your update request on-chain
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
ts-node src/main [PAYER_KEYPAIR_PATH]
|
||||
```
|
||||
|
||||
where **PAYER_KEYPAIR_PATH** is the location of your Solana keypair, defaulting
|
||||
to `~/.config/solana/id.json` if not provided
|
||||
|
||||
When prompted, run the docker compose script in a new shell to start your local
|
||||
oracle then confirm the prompt to turn the crank and request an update on-chain.
|
||||
The oracle is ready to fulfill updates when it sees the following logs:
|
||||
|
||||
```bash
|
||||
{"timestamp":"2022-09-23T19:24:11.874Z","level":"info","message":"Loaded 1000 nonce accounts"}
|
||||
{"timestamp":"2022-09-23T19:24:11.885Z","level":"info","message":"started health check handler"}
|
||||
{"timestamp":"2022-09-23T19:24:11.886Z","level":"info","message":"Heartbeat routine started with an interval of 15 seconds."}
|
||||
{"timestamp":"2022-09-23T19:24:11.887Z","level":"info","message":"Watching event: AggregatorOpenRoundEvent ..."}
|
||||
{"timestamp":"2022-09-23T19:24:11.893Z","level":"info","message":"Watching event: VrfRequestRandomnessEvent ..."}
|
||||
{"timestamp":"2022-09-23T19:24:11.894Z","level":"info","message":"Using default performance monitoring"}
|
||||
```
|
||||
|
||||
Example Output:
|
||||
|
||||
```bash
|
||||
$ ts-node src/main
|
||||
######## Switchboard Setup ########
|
||||
Program State BYM81n8HvTJuqZU1PmTVcwZ9G8uoji7FKM6EaPkwphPt
|
||||
Oracle Queue AVbBmSeKJppRcphaPY1fPbFQW48Eg851G4XfqyTPMZNF
|
||||
Crank 6fNsrJhaB2MPpwpcxW7AL5zyoiq7Gyz2mM6q3aVz7xxh
|
||||
Oracle CmTr9FSeuhMPBLEPa3o2M71RwRnBz6LMcsfzHaW721Ak
|
||||
Permission 2pC5ESkVKGx4yowGrVB21f6eXaaMRQY5cBazfqn1bAQs
|
||||
Aggregator (SOL/USD) FLixyyJVzfCF4PmDG2VcFm1LUBu1aBTXox3oCWNVU88m
|
||||
Permission EVerqanwRrHRvtPXDRdFHPc7VnXuyEPRr9XA5udpFA4E
|
||||
Lease FC6SfAEuoB1SoZAnCqkMyyYnSfLSy8KfPUFH9SASBUzU
|
||||
Job (FTX) BbNzfRQjTYiCZVfvK1qpQkkon3kP2tbvaCHfzsyjeBU3
|
||||
✔ Switchboard setup complete
|
||||
######## Start the Oracle ########
|
||||
Run the following command in a new shell
|
||||
|
||||
ORACLE_KEY=CmTr9FSeuhMPBLEPa3o2M71RwRnBz6LMcsfzHaW721Ak PAYER_KEYPAIR=/Users/switchboard/.config/solana/id.json RPC_URL=https://api.devnet.solana.com docker-compose up
|
||||
|
||||
Select 'Y' when the docker container displays Starting listener... [y/n]: y
|
||||
|
||||
✔ Crank turned
|
||||
######## Aggregator Result ########
|
||||
Result: 30.91
|
||||
|
||||
✔ Aggregator succesfully updated!
|
||||
```
|
|
@ -0,0 +1,17 @@
|
|||
version: "3.3"
|
||||
services:
|
||||
oracle:
|
||||
image: "switchboardlabs/node:dev-v2-09-13-22"
|
||||
network_mode: host
|
||||
restart: always
|
||||
secrets:
|
||||
- PAYER_SECRETS
|
||||
environment:
|
||||
- LIVE=1
|
||||
- CLUSTER=devnet
|
||||
- HEARTBEAT_INTERVAL=15 # Seconds
|
||||
- ORACLE_KEY=${ORACLE_KEY}
|
||||
- RPC_URL=${RPC_URL}
|
||||
secrets:
|
||||
PAYER_SECRETS:
|
||||
file: ${PAYER_KEYPAIR}
|
|
@ -1,5 +1,6 @@
|
|||
import * as anchor from "@project-serum/anchor";
|
||||
import * as spl from "@solana/spl-token-v2";
|
||||
import type { PublicKey } from "@solana/web3.js";
|
||||
import { clusterApiUrl, Connection, Keypair } from "@solana/web3.js";
|
||||
import { IOracleJob, OracleJob } from "@switchboard-xyz/common";
|
||||
import {
|
||||
|
@ -17,23 +18,54 @@ import {
|
|||
} from "@switchboard-xyz/switchboard-v2";
|
||||
import chalk from "chalk";
|
||||
import dotenv from "dotenv";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import readlineSync from "readline-sync";
|
||||
import { getKeypair, sleep, toAccountString } from "./utils";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
export const toAccountString = (
|
||||
label: string,
|
||||
publicKey: PublicKey | string | undefined
|
||||
): string => {
|
||||
if (typeof publicKey === "string") {
|
||||
return `${chalk.blue(label.padEnd(24, " "))} ${chalk.yellow(publicKey)}`;
|
||||
}
|
||||
if (!publicKey) {
|
||||
return "";
|
||||
}
|
||||
return `${chalk.blue(label.padEnd(24, " "))} ${chalk.yellow(
|
||||
publicKey.toString()
|
||||
)}`;
|
||||
};
|
||||
|
||||
export const sleep = (ms: number): Promise<any> =>
|
||||
new Promise((s) => setTimeout(s, ms));
|
||||
|
||||
export const getKeypair = (keypairPath: string): Keypair => {
|
||||
if (!fs.existsSync(keypairPath)) {
|
||||
throw new Error(
|
||||
`failed to load authority keypair from ${keypairPath}, try providing a path to your keypair with the script 'ts-node src/main KEYPAIR_PATH'`
|
||||
);
|
||||
}
|
||||
const keypairString = fs.readFileSync(keypairPath, "utf8");
|
||||
const keypairBuffer = new Uint8Array(JSON.parse(keypairString));
|
||||
const walletKeypair = Keypair.fromSecretKey(keypairBuffer);
|
||||
return walletKeypair;
|
||||
};
|
||||
|
||||
async function main() {
|
||||
// get payer keypair
|
||||
let authority: Keypair;
|
||||
if (process.env.PAYER_KEYPAIR) {
|
||||
authority = getKeypair(process.env.PAYER_KEYPAIR);
|
||||
let payerKeypairPath: string;
|
||||
if (process.argv.length > 2 && process.argv[2]) {
|
||||
payerKeypairPath = process.argv[2];
|
||||
} else if (process.env.PAYER_KEYPAIR) {
|
||||
payerKeypairPath = process.env.PAYER_KEYPAIR;
|
||||
} else {
|
||||
// attempt to load default keypair
|
||||
const homeDir = os.homedir();
|
||||
authority = getKeypair(path.join(homeDir, ".config/solana/id.json"));
|
||||
payerKeypairPath = path.join(os.homedir(), ".config/solana/id.json");
|
||||
}
|
||||
const authority = getKeypair(payerKeypairPath);
|
||||
|
||||
// get cluster
|
||||
let cluster: "mainnet-beta" | "devnet" | "localnet";
|
||||
|
@ -195,7 +227,7 @@ async function main() {
|
|||
console.log(chalk.yellow("######## Start the Oracle ########"));
|
||||
console.log(chalk.blue("Run the following command in a new shell\r\n"));
|
||||
console.log(
|
||||
` ORACLE_KEY=${oracleAccount.publicKey} PAYER_KEYPAIR=${authority} RPC_URL=${rpcUrl} docker-compose up\r\n`
|
||||
` ORACLE_KEY=${oracleAccount.publicKey} PAYER_KEYPAIR=${payerKeypairPath} RPC_URL=${rpcUrl} docker-compose up\r\n`
|
||||
);
|
||||
if (
|
||||
!readlineSync.keyInYN(
|
||||
|
@ -217,7 +249,7 @@ async function main() {
|
|||
const crank = await crankAccount.loadData();
|
||||
const queue = await queueAccount.loadData();
|
||||
|
||||
const crankTurnSignature = await crankAccount.popTxn({
|
||||
const crankTurnSignature = await crankAccount.pop({
|
||||
payoutWallet: tokenAccount,
|
||||
queuePubkey: queueAccount.publicKey,
|
||||
queueAuthority: queue.authority,
|
||||
|
@ -248,7 +280,15 @@ async function main() {
|
|||
console.log(chalk.yellow("######## Aggregator Result ########"));
|
||||
await sleep(5000);
|
||||
try {
|
||||
const result = await aggregatorAccount.getLatestValue();
|
||||
let result = await aggregatorAccount.getLatestValue();
|
||||
if (result === null) {
|
||||
// wait a bit longer
|
||||
await sleep(2500);
|
||||
result = await aggregatorAccount.getLatestValue();
|
||||
if (result === null) {
|
||||
throw new Error(`Aggregator currently holds no value.`);
|
||||
}
|
||||
}
|
||||
console.log(`${chalk.blue("Result:")} ${chalk.green(result)}\r\n`);
|
||||
console.log(chalk.green("\u2714 Aggregator succesfully updated!"));
|
||||
} catch (error: any) {
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import type { PublicKey } from "@solana/web3.js";
|
||||
import { Keypair } from "@solana/web3.js";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
|
||||
export const toAccountString = (
|
||||
label: string,
|
||||
publicKey: PublicKey | string | undefined
|
||||
): string => {
|
||||
if (typeof publicKey === "string") {
|
||||
return `${chalk.blue(label.padEnd(24, " "))} ${chalk.yellow(publicKey)}`;
|
||||
}
|
||||
if (!publicKey) return "";
|
||||
return `${chalk.blue(label.padEnd(24, " "))} ${chalk.yellow(
|
||||
publicKey.toString()
|
||||
)}`;
|
||||
};
|
||||
|
||||
export const sleep = (ms: number): Promise<any> =>
|
||||
new Promise((s) => setTimeout(s, ms));
|
||||
|
||||
export const getKeypair = (path: string): Keypair => {
|
||||
if (!fs.existsSync(path)) {
|
||||
throw new Error(`failed to load authority keypair from ${path}`);
|
||||
}
|
||||
const keypairString = fs.readFileSync(path, "utf8");
|
||||
const keypairBuffer = new Uint8Array(JSON.parse(keypairString));
|
||||
const walletKeypair = Keypair.fromSecretKey(keypairBuffer);
|
||||
return walletKeypair;
|
||||
};
|
Loading…
Reference in New Issue