onchain prices

This commit is contained in:
Alexey 2019-12-23 19:38:44 +03:00
parent 9e2eef492a
commit 91b97e0276
7 changed files with 80 additions and 28 deletions

View File

@ -1,5 +1,7 @@
NET_ID=42 NET_ID=42
RPC_URL=https://kovan.infura.io RPC_URL=https://kovan.infura.io
# ORACLE_RPC_URL should always point to mainnet
ORACLE_RPC_URL=https://mainnet.infura.io
REDIS_URL=redis://127.0.0.1:6379 REDIS_URL=redis://127.0.0.1:6379
# without 0x prefix # without 0x prefix

33
abis/PriceOracle.abi.json Normal file
View File

@ -0,0 +1,33 @@
[
{
"constant": true,
"inputs": [
{
"internalType": "contract IERC20[]",
"name": "fromTokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "oneUnitAmounts",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "parts",
"type": "uint256[]"
}
],
"name": "getPricesInETH",
"outputs": [
{
"internalType": "uint256[]",
"name": "prices",
"type": "uint256[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]

View File

@ -1,10 +1,12 @@
require('dotenv').config() require('dotenv').config()
module.exports = { module.exports = {
version: '1.0', version: '1.1',
netId: Number(process.env.NET_ID) || 42, netId: Number(process.env.NET_ID) || 42,
redisUrl: process.env.REDIS_URL, redisUrl: process.env.REDIS_URL,
rpcUrl: process.env.RPC_URL || 'https://kovan.infura.io/v3/a3f4d001c1fc4a359ea70dd27fd9cb51', rpcUrl: process.env.RPC_URL || 'https://kovan.infura.io/',
oracleRpcUrl: process.env.ORACLE_RPC_URL || 'https://mainnet.infura.io/',
oracleAddress: '0x5c4c5622670423b8ee5F3A02F505D139fbAfb618',
privateKey: process.env.PRIVATE_KEY, privateKey: process.env.PRIVATE_KEY,
mixers: { mixers: {
netId1: { netId1: {

View File

@ -12,7 +12,6 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bull": "^3.12.1", "bull": "^3.12.1",
"coingecko-api": "^1.0.6",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"express": "^4.17.1", "express": "^4.17.1",
"ioredis": "^4.14.1", "ioredis": "^4.14.1",

View File

@ -1,37 +1,50 @@
const CoinGecko = require('coingecko-api')
const fetch = require('node-fetch') const fetch = require('node-fetch')
const { toWei } = require('web3-utils') const Web3 = require('Web3')
const { gasOracleUrls, defaultGasPrice } = require('../config') const { gasOracleUrls, defaultGasPrice, oracleRpcUrl, oracleAddress } = require('../config')
const { getMainnetTokens } = require('./utils') const { getArgsForOracle } = require('./utils')
const { redisClient } = require('./redis') const { redisClient } = require('./redis')
const priceOracleABI = require('../abis/PriceOracle.abi.json')
class Fetcher { class Fetcher {
constructor(web3) { constructor(web3) {
this.web3 = web3 this.web3 = web3
this.oracleWeb3 = new Web3(oracleRpcUrl)
this.oracle = new this.oracleWeb3.eth.Contract(priceOracleABI, oracleAddress)
this.ethPrices = { this.ethPrices = {
dai: '6700000000000000' // 0.0067 dai: '6700000000000000', // 0.0067
cdai: '157380000000000',
cusdc: '164630000000000',
usdc: '7878580000000000',
usdt: '7864940000000000'
} }
this.tokenAddresses
this.oneUintAmount
this.parts
this.currencyLookup
this.gasPrices = { this.gasPrices = {
fast: defaultGasPrice fast: defaultGasPrice
} }
const { tokenAddresses, oneUintAmount, parts, currencyLookup } = getArgsForOracle()
this.tokenAddresses = tokenAddresses
this.oneUintAmount = oneUintAmount
this.parts = parts
this.currencyLookup = currencyLookup
} }
async fetchPrices() { async fetchPrices() {
const { tokenAddresses, currencyLookup } = getMainnetTokens()
try { try {
const CoinGeckoClient = new CoinGecko() let prices = await this.oracle.methods.getPricesInETH(
const price = await CoinGeckoClient.simple.fetchTokenPrice({ this.tokenAddresses,
contract_addresses: tokenAddresses, this.oneUintAmount,
vs_currencies: 'eth', this.parts
assetPlatform: 'ethereum' ).call()
}) this.ethPrices = prices.reduce((acc, price, i) => {
this.ethPrices = Object.entries(price.data).reduce((acc, token) => { acc[this.currencyLookup[this.tokenAddresses[i]]] = price
if (token[1].eth) {
acc[currencyLookup[token[0]]] = toWei(token[1].eth.toString())
}
return acc return acc
}, {}) }, {})
setTimeout(() => this.fetchPrices(), 1000 * 30) setTimeout(() => this.fetchPrices(), 1000 * 30)
} catch(e) { } catch(e) {
console.error('fetchPrices', e)
setTimeout(() => this.fetchPrices(), 1000 * 30) setTimeout(() => this.fetchPrices(), 1000 * 30)
} }
} }

View File

@ -138,21 +138,29 @@ function isEnoughFee({ gas, gasPrices, currency, amount, refund, ethPrices, fee
return { isEnough: true } return { isEnough: true }
} }
function getMainnetTokens() { function getArgsForOracle() {
const tokens = mixers['netId1'] const tokens = mixers['netId1']
const tokenAddresses = [] const tokenAddresses = []
const oneUintAmount = []
const parts = [] // this is probably should be removed
const currencyLookup = {} const currencyLookup = {}
Object.entries(tokens).map(([currency, data]) => { Object.entries(tokens).map(([currency, data]) => {
if (currency !== 'eth') { if (currency !== 'eth') {
tokenAddresses.push(data.tokenAddress) tokenAddresses.push(data.tokenAddress)
currencyLookup[data.tokenAddress.toLowerCase()] = currency oneUintAmount.push(
toBN('10')
.pow(toBN(data.decimals.toString()))
.toString()
)
parts.push('1')
currencyLookup[data.tokenAddress] = currency
} }
}) })
return { tokenAddresses, currencyLookup } return { tokenAddresses, oneUintAmount, parts, currencyLookup }
} }
function getMixers() { function getMixers() {
return mixers[`netId${netId}`] return mixers[`netId${netId}`]
} }
module.exports = { isValidProof, isValidArgs, sleep, isKnownContract, isEnoughFee, getMixers, getMainnetTokens } module.exports = { isValidProof, isValidArgs, sleep, isKnownContract, isEnoughFee, getMixers, getArgsForOracle }

View File

@ -477,11 +477,6 @@ cluster-key-slot@^1.1.0:
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
coingecko-api@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/coingecko-api/-/coingecko-api-1.0.6.tgz#ecc42eb96fb1cc721e319c3d06244a642394ab34"
integrity sha512-6oJ3aB9F4AlsHQQ4F5N9753FGmMQrr12aGJl79KSfdNOFJ7wvFLSqsBoOBzgYJEab3hJ7cCWnmo2dMJs6KsA3A==
color-convert@^1.9.0: color-convert@^1.9.0:
version "1.9.3" version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"