forked from sei-protocol/sei-chain
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoracle.js
152 lines (140 loc) · 4.41 KB
/
oracle.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
const { SigningCosmWasmClient } = require('@cosmjs/cosmwasm-stargate');
const { GasPrice, assertIsDeliverTxSuccess } = require('@cosmjs/stargate');
require('dotenv').config();
require('log-timestamp');
const prices = require(`./prices`).prices;
const utils = require('./utils').utils;
// TODO(psu): Insert actual addresses
const TOKEN_ADDR_MAP = {
btc: 'cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr',
eth: 'cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr',
sol: 'cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr',
osmo: 'cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr',
};
/**
* Price oracle class for posting prices to sei-chain.
*/
class PriceOracle {
constructor(marketIDs, chainRpc, wallet, account, contractAddress, gasFee) {
if (!marketIDs) {
throw new Error('must specify at least one market ID');
}
if (!chainRpc) {
throw new Error('must specify at rpc endpoint for chain');
}
// Validate each market ID on CoinGecko (primary) and Binance (backup)
for (let i = 0; i < marketIDs.length; i += 1) {
try {
utils.loadPrimaryMarket(marketIDs[i]);
utils.loadBackupMarket(marketIDs[i]);
} catch (e) {
console.log("couldn't load remote market from market ID, error:", e);
return;
}
}
this.marketIDs = marketIDs;
this.wallet = wallet;
this.account = account;
this.chainRpc = chainRpc;
this.contractAddress = contractAddress;
this.gasFee = gasFee;
}
/**
* Get prices for each market
*/
async getAndPostPrices() {
const chainClient = await SigningCosmWasmClient.connectWithSigner(
this.chainRpc,
this.wallet,
{ gasPrice: GasPrice.fromString(this.gasFee) }
);
await asyncForEach(this.marketIDs, async (market) => {
const fetchedPrice = await this.fetchPrice(market);
if (!fetchedPrice.success) {
return;
}
// Post fetched price
const msg = { "update_price": { "token_addr": TOKEN_ADDR_MAP[market], "price": String(fetchedPrice.price) } };
const result = await chainClient.execute(
this.account.address,
this.contractAddress,
msg,
"auto"
);
console.log(`Finished executing contract for price update ${result}`);
assertIsDeliverTxSuccess(result);
return fetchedPrice.price;
});
}
/**
* Fetches price for a market ID
* @param {String} marketID the market's ID
*/
async fetchPrice(marketID) {
let error = false;
let res;
try {
res = await this.fetchPrimaryPrice(marketID);
if (!res.success) {
error = true;
}
} catch (error) {
error = true;
}
if (error) {
console.log("trying backup price source after error");
res = await this.fetchBackupPrice(marketID);
}
return res;
}
/**
* Fetches price from the primary source for a market
* @param {String} marketID the market's ID
*/
async fetchPrimaryPrice(marketID) {
return this.fetchPriceCoinGecko(marketID);
}
/**
* Fetches price from the backup source for a market
* @param {String} marketID the market's ID
*/
async fetchBackupPrice(marketID) {
return this.fetchPriceBinance(marketID);
}
/**
* Fetches price from Binance
* @param {String} marketID the market's ID
*/
async fetchPriceBinance(marketID) {
let retreivedPrice;
try {
retreivedPrice = await prices.getBinancePrice(marketID);
console.debug(`Binance price for ${marketID}: ${retreivedPrice}`);
} catch (e) {
console.log(`could not get ${marketID} price from Binance: ${e}`);
return { price: null, success: false };
}
return { price: retreivedPrice, success: true };
}
/**
* Fetches price from Coin Gecko
* @param {String} marketID the market's ID
*/
async fetchPriceCoinGecko(marketID) {
let retreivedPrice;
try {
retreivedPrice = await prices.getCoinGeckoPrice(marketID);
console.debug(`Coin Gecko price for ${marketID}: ${retreivedPrice}`);
} catch (e) {
console.log(`could not get ${marketID} price from Coin Gecko: ${e}`);
return { price: null, success: false };
}
return { price: retreivedPrice, success: true };
}
}
var asyncForEach = async (array, callback) => {
for (let index = 0; index < array.length; index += 1) {
await callback(array[index], index, array);
}
};
module.exports.PriceOracle = PriceOracle;