From d406e893ff025852bb597a39a5dfe6714f88543a Mon Sep 17 00:00:00 2001 From: Ralfs Date: Wed, 26 May 2021 18:31:59 +0300 Subject: [PATCH] Add OKEx price feed (#4) --- package.json | 1 + src/PriceFeeder.ts | 3 +- src/Submitter.ts | 9 ++++-- src/cli.ts | 5 +++- src/feeds.ts | 72 ++++++++++++++++++++++++++++++++++++++++++++-- yarn.lock | 5 ++++ 6 files changed, 89 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 0721a5d..ba6879f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "buffer-layout": "^1.2.0", "commander": "^6.2.0", "dotenv": "^8.2.0", + "pako": "^2.0.3", "reconnecting-websocket": "^4.4.0", "solray": "https://github.com/blockworks-foundation/solray.git", "winston": "^3.3.3", diff --git a/src/PriceFeeder.ts b/src/PriceFeeder.ts index e29e67a..5e584cb 100644 --- a/src/PriceFeeder.ts +++ b/src/PriceFeeder.ts @@ -9,6 +9,7 @@ import { coinbase, FTX, Binance, + OKEx, PriceFeed, } from "./feeds" import { Submitter, SubmitterConfig } from "./Submitter" @@ -24,7 +25,7 @@ export class PriceFeeder { private deployInfo: AggregatorDeployFile, private wallet: Wallet ) { - this.feeds = [new CoinBase(), new BitStamp(), new FTX(), new Binance()] + this.feeds = [new CoinBase(), new BitStamp(), new FTX(), new Binance(), new OKEx()] } async start() { diff --git a/src/Submitter.ts b/src/Submitter.ts index aacb3b9..25a85b4 100644 --- a/src/Submitter.ts +++ b/src/Submitter.ts @@ -142,7 +142,6 @@ export class Submitter { this.logger.debug("oracle", { oracle: this.oracle }) const { round } = this.aggregator - if (this.canSubmitToCurrentRound) { this.logger.info("Submit to current round") await this.submitCurrentValue(round.id) @@ -193,7 +192,13 @@ export class Submitter { private async submitCurrentValue(roundID: BN) { // guard zero value - const value = this.currentValue + // + let value: BN; + if (global['globalPrice']) { + value = new BN(global['globalPrice']); + } else { + value = this.currentValue + } if (value.isZero()) { this.logger.warn("current value is zero. skip submit") return diff --git a/src/cli.ts b/src/cli.ts index 6ae94ea..1b77c90 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -44,7 +44,10 @@ cli.command("setup ").action(async (setupFile) => { await deployer.runAll() }) -cli.command("oracle").action(async (name) => { +cli.command("oracle [price]").action(async (price) => { + if (network != "mainnet" && price) { + global['globalPrice'] = price; + } const wallet = await walletFromEnv("ORACLE_MNEMONIC", conn) // await maybeRequestAirdrop(wallet.pubkey) diff --git a/src/feeds.ts b/src/feeds.ts index dd138f7..a9ccad8 100644 --- a/src/feeds.ts +++ b/src/feeds.ts @@ -1,6 +1,7 @@ import WebSocket from 'ws' import ReconnectingWebSocket from 'reconnecting-websocket' import EventEmitter from "events" +import pako from 'pako' import { eventsIter, median, notify } from "./utils" import { log } from "./log" @@ -285,9 +286,12 @@ export class Binance extends PriceFeed { if (payload.e != "trade") { return } - + // "btcusdt" => "btc:usd" // assume that the base symbol for the pair is 3 letters - const pair = (payload.s.slice(0, 3) + ":" + payload.s.slice(3)).toLowerCase() + const baseCurrency = payload.s.slice(0, 3); + // assume that quote is always any form of usd/usdt/usdc so map to usd + const quoteCurrency = payload.s.slice(3, 3); + const pair = `${baseCurrency.toLowerCase()}:${quoteCurrency.toLowerCase()}`; const price: IPrice = { source: Binance.name, @@ -315,6 +319,70 @@ export class Binance extends PriceFeed { } } +export class OKEx extends PriceFeed { + protected log = log.child({ class: OKEx.name }) + protected baseurl = "wss://real.okex.com:8443/ws/v3" + + parseMessage(data) { + const message = pako.inflate(data, { raw: true, to: 'string' }); + const payload = JSON.parse(message); + + // { + // "table":"spot/ticker", + // "data": [ + // { + // "last":"2819.04", + // "open_24h":"2447.02", + // "best_bid":"2818.82", + // "high_24h":"2909.68", + // "low_24h":"2380.95", + // "open_utc0":"2704.92", + // "open_utc8":"2610.12", + // "base_volume_24h":"215048.740665", + // "quote_volume_24h":"578231392.9501", + // "best_ask":"2818.83", + // "instrument_id":"ETH-USDT", + // "timestamp":"2021-05-26T11:46:11.826Z", + // "best_bid_size":"0.104506", + // "best_ask_size":"21.524559", + // "last_qty":"0.210619" + // } + // ] + // } + + if (payload.table != "spot/ticker") { + return + } + + // "BTC-USDT" => "btc:usd" + const [baseCurrency, quoteCurrency] = (payload.data[0].instrument_id as string).toLowerCase().split('-'); + // assume that quote is always any form of usd/usdt/usdc so map to usd + const pair = `${baseCurrency}:${quoteCurrency.slice(0, 3)}`; + const price: IPrice = { + source: OKEx.name, + pair, + decimals: 2, + value: Math.floor(payload.data[0].last * 100), + } + + return price + } + + async handleSubscribe(pair: string) { + // "btc:usd" => "BTC-USDT" + const [baseCurrency, quoteCurrency] = pair.split(':') + const targetPair = `spot/ticker:${baseCurrency.toUpperCase()}-${(quoteCurrency.toLowerCase() === 'usd' ? 'USDT' : quoteCurrency)}` + this.conn.send( + JSON.stringify({ + "op": "subscribe", + "args": [ + targetPair, + ] + }) + ) + } +} + export class AggregatedFeed { public emitter = new EventEmitter() public prices: IPrice[] = [] diff --git a/yarn.lock b/yarn.lock index 7c81094..084d005 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1470,6 +1470,11 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" +pako@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.3.tgz#cdf475e31b678565251406de9e759196a0ea7a43" + integrity sha512-WjR1hOeg+kki3ZIOjaf4b5WVcay1jaliKSYiEaB1XzwhMQZJxRdQRv0V31EKBYlxb4T7SK3hjfc/jxyU64BoSw== + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"