Merge pull request #7 from blockworks-foundation/add_spport_for_legacy_oracles
Add support for legacy oracles
This commit is contained in:
commit
208759f577
|
@ -22,7 +22,7 @@
|
|||
"blockworks"
|
||||
]
|
||||
},
|
||||
"sol:usd": {
|
||||
"btc:usdt": {
|
||||
"decimals": 2,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
|
@ -33,7 +33,7 @@
|
|||
"blockworks"
|
||||
]
|
||||
},
|
||||
"srm:usd": {
|
||||
"eth:usdt": {
|
||||
"decimals": 2,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
|
@ -43,6 +43,28 @@
|
|||
"oracles": [
|
||||
"blockworks"
|
||||
]
|
||||
},
|
||||
"sol:usd": {
|
||||
"decimals": 4,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
"restartDelay": 0,
|
||||
"rewardAmount": 10000,
|
||||
"rewardTokenAccount": "3oLHHTaRqNsuTMjsTtkVy8bock6Bx8gCmDxku4TurVj1",
|
||||
"oracles": [
|
||||
"blockworks"
|
||||
]
|
||||
},
|
||||
"srm:usd": {
|
||||
"decimals": 4,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
"restartDelay": 0,
|
||||
"rewardAmount": 10000,
|
||||
"rewardTokenAccount": "3oLHHTaRqNsuTMjsTtkVy8bock6Bx8gCmDxku4TurVj1",
|
||||
"oracles": [
|
||||
"blockworks"
|
||||
]
|
||||
}
|
||||
},
|
||||
"oracles": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"aggregators": {
|
||||
"btc:usd": {
|
||||
"btc:usdt": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "6Xvk6VC423bbhwnCfMyPfE4C1vytoqsVMUY1Lbqeh6pf"
|
||||
|
@ -10,7 +10,7 @@
|
|||
"base58": "GXdZLSvnreqyUd92tXFShpF8DPvpqDBRkukAtraZ3rCf"
|
||||
},
|
||||
"config": {
|
||||
"description": "btc:usd",
|
||||
"description": "btc:usdt",
|
||||
"decimals": 2,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
|
@ -34,7 +34,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eth:usd": {
|
||||
"eth:usdt": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "4CoKvk3NUXYiHKGbQvihadw6TC8LTN1qjfadPcsaURbW"
|
||||
|
@ -44,7 +44,7 @@
|
|||
"base58": "GXdZLSvnreqyUd92tXFShpF8DPvpqDBRkukAtraZ3rCf"
|
||||
},
|
||||
"config": {
|
||||
"description": "eth:usd",
|
||||
"description": "eth:usdt",
|
||||
"decimals": 2,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
|
@ -68,17 +68,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"sol:usd": {
|
||||
"btc:usd": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "Ej5FrNjhXaePK7cVMZtSooatzXMeunNsjxrnubefEyNC"
|
||||
"base58": "FuEnReoxhqW8Li6EMLoaaUWbWAEjTfSRuBARo5GrGCqN"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
"base58": "GXdZLSvnreqyUd92tXFShpF8DPvpqDBRkukAtraZ3rCf"
|
||||
},
|
||||
"config": {
|
||||
"description": "sol:usd",
|
||||
"description": "btc:usd",
|
||||
"decimals": 2,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
|
@ -93,7 +93,75 @@
|
|||
"blockworks": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "4fuTrajqBHGGM1ig4b57DD9JxcN5Q2MmoDVnMtnucjS7"
|
||||
"base58": "AhD1vCnNBgECpoBrfsqP83KSZsd4TtrWvP3FgebUDoRu"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
"base58": "GXdZLSvnreqyUd92tXFShpF8DPvpqDBRkukAtraZ3rCf"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"eth:usd": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "GzfYWGM1oeVrha9zvM1awnTJEUAuinpnVRUyYQYELzqg"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
"base58": "GXdZLSvnreqyUd92tXFShpF8DPvpqDBRkukAtraZ3rCf"
|
||||
},
|
||||
"config": {
|
||||
"description": "eth:usd",
|
||||
"decimals": 2,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
"restartDelay": 0,
|
||||
"rewardTokenAccount": {
|
||||
"type": "PublicKey",
|
||||
"base58": "3oLHHTaRqNsuTMjsTtkVy8bock6Bx8gCmDxku4TurVj1"
|
||||
},
|
||||
"rewardAmount": 10000
|
||||
},
|
||||
"oracles": {
|
||||
"blockworks": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "HhBmYDPRzJDCbtsTcaB2j6sbpcNDK41CUciev94eroUE"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
"base58": "GXdZLSvnreqyUd92tXFShpF8DPvpqDBRkukAtraZ3rCf"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sol:usd": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "AshULbjkGvse8YW2ojjeqHdMbFGigLy2xxiGVhsLqX5T"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
"base58": "GXdZLSvnreqyUd92tXFShpF8DPvpqDBRkukAtraZ3rCf"
|
||||
},
|
||||
"config": {
|
||||
"description": "sol:usd",
|
||||
"decimals": 4,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
"restartDelay": 0,
|
||||
"rewardTokenAccount": {
|
||||
"type": "PublicKey",
|
||||
"base58": "3oLHHTaRqNsuTMjsTtkVy8bock6Bx8gCmDxku4TurVj1"
|
||||
},
|
||||
"rewardAmount": 10000
|
||||
},
|
||||
"oracles": {
|
||||
"blockworks": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "2K38TaiEJEiPZY3TGKjuLMoHgZgXxX7YX2wRD2WvfUDM"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
|
@ -105,7 +173,7 @@
|
|||
"srm:usd": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "GR9tYpi8CM8u8sdRaJZoP32KoWBphyoWV3xoNt4XwmRV"
|
||||
"base58": "B3nWGxqNQzJeRfpYSXU8qJaTQxspZmqAt91FRAhfoFQL"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
|
@ -113,7 +181,7 @@
|
|||
},
|
||||
"config": {
|
||||
"description": "srm:usd",
|
||||
"decimals": 2,
|
||||
"decimals": 4,
|
||||
"minSubmissions": 1,
|
||||
"maxSubmissions": 13,
|
||||
"restartDelay": 0,
|
||||
|
@ -127,7 +195,7 @@
|
|||
"blockworks": {
|
||||
"pubkey": {
|
||||
"type": "PublicKey",
|
||||
"base58": "8tn58rnF1QzPqQea4xegck556s45DUGBJvWLNdsLpT69"
|
||||
"base58": "CsyV4JuPjdYRusw4sa7Ba8Ab8yR7vjyp4wAPuC2neejS"
|
||||
},
|
||||
"owner": {
|
||||
"type": "PublicKey",
|
||||
|
|
|
@ -11,7 +11,7 @@ async function main() {
|
|||
// const aggfeed2 = new AggregatedFeed(feeds, "eth:usd")
|
||||
|
||||
for (let pair of ["btc:usd", "eth:usd"]) {
|
||||
const aggfeed = new AggregatedFeed(feeds, pair)
|
||||
const aggfeed = new AggregatedFeed(feeds, [], 2, pair)
|
||||
|
||||
setImmediate(async () => {
|
||||
for await (let _ of aggfeed.updates()) {
|
||||
|
|
|
@ -16,22 +16,44 @@ import { Submitter, SubmitterConfig } from "./Submitter"
|
|||
import { log } from "./log"
|
||||
import { conn } from "./context"
|
||||
|
||||
// 0 => Coinbase, BTC-USD
|
||||
// 1 => BitStamp, live_trades_btcusd
|
||||
// 2 => FTX, BTC/USD
|
||||
// 3 => Binance, BTCBUSD
|
||||
// 4 => OKEx, BTC-USDC
|
||||
|
||||
const priceFeedMapping = {
|
||||
'btc:usdt': {
|
||||
minValueChangeForNewRound: 5000,
|
||||
useFeeds: [0,2,3,4],
|
||||
pairNames: ['BTC-USDT', 'BTC/USDT', 'BTCUSDT', 'BTC-USDT']
|
||||
},
|
||||
'btc:usd': {
|
||||
minValueChangeForNewRound: 5000,
|
||||
useFeeds: [0,1,2,3]
|
||||
useFeeds: [0,1,2,3,4],
|
||||
pairNames: ['BTC-USD', 'live_trades_btcusd', 'BTC/USD', 'BTCBUSD', 'BTC-USDC']
|
||||
},
|
||||
'eth:usdt': {
|
||||
minValueChangeForNewRound: 150,
|
||||
useFeeds: [0,2,3,4],
|
||||
pairNames: ['ETH-USDT', 'ETH/USDT', 'ETHUSDT', 'ETH-USDT']
|
||||
},
|
||||
'eth:usd': {
|
||||
minValueChangeForNewRound: 150,
|
||||
useFeeds: [0,1,2,3]
|
||||
useFeeds: [0,1,2,3,4],
|
||||
pairNames: ['ETH-USD', 'live_trades_ethusd', 'ETH/USD', 'ETHBUSD', 'ETH-USDC']
|
||||
},
|
||||
'sol:usd': {
|
||||
minValueChangeForNewRound: 4,
|
||||
useFeeds: [2,3,4]
|
||||
useFeeds: [2,3,4],
|
||||
pairNames: ['SOL/USD', 'SOLBUSD', 'SOL-USDT']
|
||||
// uses USDT for OKEx
|
||||
},
|
||||
'srm:usd': {
|
||||
minValueChangeForNewRound: 1,
|
||||
useFeeds: [2,3,4]
|
||||
useFeeds: [2,3,4],
|
||||
pairNames: ['SRM/USD', 'SRMBUSD', 'SRM-USDT']
|
||||
// uses USDT for OKEx
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -77,7 +99,7 @@ export class PriceFeeder {
|
|||
}
|
||||
|
||||
const useFeeds = (priceFeedMapping[name]) ? priceFeedMapping[name].useFeeds.map(x => this.feeds[x]) : this.feeds;
|
||||
const feed = new AggregatedFeed(useFeeds, name)
|
||||
const feed = new AggregatedFeed(useFeeds, priceFeedMapping[name].pairNames, aggregatorInfo.config.decimals, name)
|
||||
const priceFeed = feed.medians()
|
||||
|
||||
const minValueChangeForNewRound = priceFeedMapping[name].minValueChangeForNewRound || 100
|
||||
|
|
167
src/feeds.ts
167
src/feeds.ts
|
@ -97,6 +97,58 @@ export abstract class PriceFeed {
|
|||
abstract handleSubscribe(pair: string): Promise<void>
|
||||
}
|
||||
|
||||
export class CoinBase extends PriceFeed {
|
||||
protected log = log.child({ class: CoinBase.name })
|
||||
protected baseurl = "wss://ws-feed.pro.coinbase.com"
|
||||
|
||||
parseMessage(data) {
|
||||
const payload = JSON.parse(data)
|
||||
|
||||
// {
|
||||
// "type": "ticker",
|
||||
// "sequence": 22772426228,
|
||||
// "product_id": "BTC-USD",
|
||||
// "price": "53784.59",
|
||||
// "open_24h": "58795.78",
|
||||
// "volume_24h": "35749.39437842",
|
||||
// "low_24h": "53221",
|
||||
// "high_24h": "58799.66",
|
||||
// "volume_30d": "733685.27275521",
|
||||
// "best_bid": "53784.58",
|
||||
// "best_ask": "53784.59",
|
||||
// "side": "buy",
|
||||
// "time": "2021-03-16T06:26:06.791440Z",
|
||||
// "trade_id": 145698988,
|
||||
// "last_size": "0.00474597"
|
||||
// }
|
||||
|
||||
if (payload.type != "ticker") {
|
||||
return
|
||||
}
|
||||
|
||||
const pair = payload.product_id as string
|
||||
|
||||
const price: IPrice = {
|
||||
source: CoinBase.name,
|
||||
pair,
|
||||
decimals: 2,
|
||||
value: Math.floor(payload.price * 100),
|
||||
}
|
||||
|
||||
return price
|
||||
}
|
||||
|
||||
async handleSubscribe(pair: string) {
|
||||
this.conn.send(
|
||||
JSON.stringify({
|
||||
type: "subscribe",
|
||||
product_ids: [pair],
|
||||
channels: ["ticker"],
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class BitStamp extends PriceFeed {
|
||||
protected log = log.child({ class: BitStamp.name })
|
||||
protected baseurl = "wss://ws.bitstamp.net"
|
||||
|
@ -125,10 +177,7 @@ export class BitStamp extends PriceFeed {
|
|||
return
|
||||
}
|
||||
|
||||
const channel = (payload.channel as string).replace("live_trades_", "")
|
||||
|
||||
// assume that the base symbol for the pair is 3 letters
|
||||
const pair = channel.slice(0, 3) + ":" + channel.slice(3)
|
||||
const pair = payload.channel as string
|
||||
|
||||
const price: IPrice = {
|
||||
source: BitStamp.name,
|
||||
|
@ -141,14 +190,11 @@ export class BitStamp extends PriceFeed {
|
|||
}
|
||||
|
||||
async handleSubscribe(pair: string) {
|
||||
// "btc:usd" => "BTCUSD"
|
||||
const targetPair = pair.replace(":", "").toUpperCase()
|
||||
|
||||
this.conn.send(
|
||||
JSON.stringify({
|
||||
event: "bts:subscribe",
|
||||
data: {
|
||||
channel: `live_trades_${targetPair.replace("/", "").toLowerCase()}`,
|
||||
channel: pair,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
@ -180,7 +226,7 @@ export class FTX extends PriceFeed {
|
|||
return
|
||||
}
|
||||
|
||||
const pair = (payload.market as string).replace("/", ":").toLowerCase()
|
||||
const pair = payload.market as string
|
||||
|
||||
const price: IPrice = {
|
||||
source: FTX.name,
|
||||
|
@ -193,70 +239,11 @@ export class FTX extends PriceFeed {
|
|||
}
|
||||
|
||||
async handleSubscribe(pair: string) {
|
||||
// "btc:usd" => "BTC-USD"
|
||||
const targetPair = pair.replace(":", "/").toUpperCase()
|
||||
|
||||
this.conn.send(
|
||||
JSON.stringify({
|
||||
op: "subscribe",
|
||||
channel: "ticker",
|
||||
market: targetPair,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class CoinBase extends PriceFeed {
|
||||
protected log = log.child({ class: CoinBase.name })
|
||||
protected baseurl = "wss://ws-feed.pro.coinbase.com"
|
||||
|
||||
parseMessage(data) {
|
||||
const payload = JSON.parse(data)
|
||||
|
||||
// {
|
||||
// "type": "ticker",
|
||||
// "sequence": 22772426228,
|
||||
// "product_id": "BTC-USD",
|
||||
// "price": "53784.59",
|
||||
// "open_24h": "58795.78",
|
||||
// "volume_24h": "35749.39437842",
|
||||
// "low_24h": "53221",
|
||||
// "high_24h": "58799.66",
|
||||
// "volume_30d": "733685.27275521",
|
||||
// "best_bid": "53784.58",
|
||||
// "best_ask": "53784.59",
|
||||
// "side": "buy",
|
||||
// "time": "2021-03-16T06:26:06.791440Z",
|
||||
// "trade_id": 145698988,
|
||||
// "last_size": "0.00474597"
|
||||
// }
|
||||
|
||||
if (payload.type != "ticker") {
|
||||
return
|
||||
}
|
||||
|
||||
// "BTC-USD" => "btc:usd"
|
||||
const pair = (payload.product_id as string).replace("-", ":").toLowerCase()
|
||||
|
||||
const price: IPrice = {
|
||||
source: CoinBase.name,
|
||||
pair,
|
||||
decimals: 2,
|
||||
value: Math.floor(payload.price * 100),
|
||||
}
|
||||
|
||||
return price
|
||||
}
|
||||
|
||||
async handleSubscribe(pair: string) {
|
||||
// "btc:usd" => "BTC-USD"
|
||||
const targetPair = pair.replace(":", "-").toUpperCase()
|
||||
|
||||
this.conn.send(
|
||||
JSON.stringify({
|
||||
type: "subscribe",
|
||||
product_ids: [targetPair],
|
||||
channels: ["ticker"],
|
||||
market: pair,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -286,11 +273,8 @@ export class Binance extends PriceFeed {
|
|||
if (payload.e != "trade") {
|
||||
return
|
||||
}
|
||||
// "btcbusd" => "btc:usd"
|
||||
// assume that the base symbol for the pair is 3 letters
|
||||
const baseCurrency = payload.s.slice(0, 3).toLowerCase();
|
||||
const quoteCurrency = payload.s.slice(3).toLowerCase();
|
||||
const pair = `${baseCurrency}:${quoteCurrency == 'busd' ? 'usd' : quoteCurrency}`;
|
||||
|
||||
const pair = payload.s;
|
||||
|
||||
|
||||
const price: IPrice = {
|
||||
|
@ -304,9 +288,7 @@ export class Binance extends PriceFeed {
|
|||
}
|
||||
|
||||
async handleSubscribe(pair: string) {
|
||||
// "btc:usd" => "btcbusd"
|
||||
const [baseCurrency, quoteCurrency] = pair.split(':')
|
||||
const targetPair = `${baseCurrency}${(quoteCurrency.toLowerCase() === 'usd' ? 'busd' : quoteCurrency)}@trade`.toLowerCase()
|
||||
const targetPair = `${pair}@trade`.toLowerCase()
|
||||
this.conn.send(
|
||||
JSON.stringify({
|
||||
method: "SUBSCRIBE",
|
||||
|
@ -354,10 +336,8 @@ export class OKEx extends PriceFeed {
|
|||
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 pair = payload.data[0].instrument_id as string;
|
||||
|
||||
const price: IPrice = {
|
||||
source: OKEx.name,
|
||||
pair,
|
||||
|
@ -369,9 +349,7 @@ export class OKEx extends PriceFeed {
|
|||
}
|
||||
|
||||
async handleSubscribe(pair: string) {
|
||||
// "btc:usd" => "BTC-USDT"
|
||||
const [baseCurrency, quoteCurrency] = pair.split(':')
|
||||
const targetPair = `spot/ticker:${baseCurrency.toUpperCase()}-${(quoteCurrency.toLowerCase() === 'usd' ? 'USDT' : quoteCurrency)}`
|
||||
const targetPair = `spot/ticker:${pair}`
|
||||
this.conn.send(
|
||||
JSON.stringify({
|
||||
"op": "subscribe",
|
||||
|
@ -388,29 +366,30 @@ export class AggregatedFeed {
|
|||
public prices: IPrice[] = []
|
||||
|
||||
// assume that the feeds are already connected
|
||||
constructor(public feeds: PriceFeed[], public pair: string) {
|
||||
constructor(public feeds: PriceFeed[], public pairMappings: string[], public decimals: number, public pair: string) {
|
||||
this.subscribe()
|
||||
}
|
||||
|
||||
private subscribe() {
|
||||
const pair = this.pair
|
||||
const pairMappings = this.pairMappings;
|
||||
const decimals = this.decimals;
|
||||
|
||||
let i = 0
|
||||
for (let feed of this.feeds) {
|
||||
feed.subscribe(pair)
|
||||
|
||||
const index = i
|
||||
i++
|
||||
let j = 0
|
||||
|
||||
for (let i = 0; i < this.feeds.length; i++) {
|
||||
const feed = this.feeds[i];
|
||||
feed.subscribe(pairMappings[i]);
|
||||
const index = j;
|
||||
j++;
|
||||
// store the price updates in the ith position of `this.prices`
|
||||
feed.emitter.on(UPDATE, (price: IPrice) => {
|
||||
if (price.pair != pair) {
|
||||
if (price.pair != pairMappings[i]) {
|
||||
return
|
||||
}
|
||||
|
||||
price.timestamp = Date.now()
|
||||
price.decimals = decimals;
|
||||
this.prices[index] = price
|
||||
|
||||
this.onPriceUpdate(price)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue