From db7c27b7373c023915fd3a862a39147f2d63a6d3 Mon Sep 17 00:00:00 2001 From: Nicholas Clarke Date: Wed, 5 May 2021 16:02:45 -0700 Subject: [PATCH] Added cli command oracle-file for submitting prices by updating a local file (#3) --- README.md | 17 +++++++++++++++++ src/cli.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/feeds.ts | 31 ++++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d17998e..e9aead1 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,23 @@ not use this key for production! NOTE 2: You might get error messages if somebody else is also running the oracle. +### Manual price feed +Alternatively, you can submit prices to the oracle manually by instructing the oracle to watch for changes to a local file. +This can be useful for testing specific behaviour (such as triggering liquidations). + +Run the oracle: +``` +yarn solink oracle-file {pair} {filepath} +``` + +{pair} must be one of the aggregator pairs in deploy.sandbox.json + +Then you can update prices by running +``` +echo {price} > {filepath} +``` + + # Observe The Aggregators With the oracle running, you can subscribe to price changes. In another diff --git a/src/cli.ts b/src/cli.ts index 4267724..6ae94ea 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -10,6 +10,8 @@ import { PriceFeeder } from "./PriceFeeder" import { sleep, walletFromEnv } from "./utils" import { PublicKey, Wallet } from "solray" import { log } from "./log" +import { Submitter } from "./Submitter" +import { file } from "./feeds" const cli = new Command() @@ -83,4 +85,51 @@ cli.command("observe").action(async (name?: string) => { } }) + +cli.command("oracle-file ").action(async (pair, path) => { + + console.log(pair); + console.log(path); + + let deployInfo = loadJSONFile(process.env.DEPLOY_FILE!) + + // validate pair arg here + if (!(pair in deployInfo.aggregators)) { + throw 'Invalid pair ' + pair; + } + + let slot = await conn.getSlot() + conn.onSlotChange((slotInfo) => { + slot = slotInfo.slot + }) + + const wallet = await walletFromEnv("ORACLE_MNEMONIC", conn) + // await maybeRequestAirdrop(wallet.pubkey) + + let aggregatorInfo = deployInfo.aggregators[pair]; + + const oracleInfo = Object.values(aggregatorInfo.oracles).find( + (oracleInfo) => { + return oracleInfo.owner.equals(wallet.pubkey) + } + ) + + let minValueChangeForNewRound = 0 + + const submitter = new Submitter( + deployInfo.programID, + aggregatorInfo.pubkey, + oracleInfo!.pubkey, + wallet, + file(pair, path), + { + minValueChangeForNewRound, + }, + () => slot + ) + + submitter.start(); + +}) + cli.parse(process.argv) diff --git a/src/feeds.ts b/src/feeds.ts index 1be8c4a..dd138f7 100644 --- a/src/feeds.ts +++ b/src/feeds.ts @@ -5,7 +5,7 @@ import { eventsIter, median, notify } from "./utils" import { log } from "./log" import winston from "winston" - +import fs from "fs"; const SECONDS = 1000 export const UPDATE = "UPDATE" @@ -444,3 +444,32 @@ export function coinbase(pair: string): IPriceFeed { return eventsIter(emitter, UPDATE) } + +export function file(pair: string, filepath: string): IPriceFeed { + const emitter = new EventEmitter() + + try { + fs.accessSync(filepath); + } catch { + fs.writeFileSync(filepath, ''); + console.log('feed file created at ' + filepath) + } + + console.log('started file feed for ' + pair) + + fs.watch(filepath, (event) => { + if (event === 'change') { + const data = fs.readFileSync(filepath, 'utf8') + const price: IPrice = { + source: "file", + pair, + decimals: 2, + value: parseFloat(data) + } + console.log('price update: ', price) + emitter.emit(UPDATE, price) + } + }); + + return eventsIter(emitter, UPDATE) +} \ No newline at end of file