From 91b97e027630d2c80fd17cf57326775ce058aa07 Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 23 Dec 2019 19:38:44 +0300 Subject: [PATCH] onchain prices --- .env.example | 2 ++ abis/PriceOracle.abi.json | 33 ++++++++++++++++++++++++++++ config.js | 6 ++++-- package.json | 1 - src/Fetcher.js | 45 +++++++++++++++++++++++++-------------- src/utils.js | 16 ++++++++++---- yarn.lock | 5 ----- 7 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 abis/PriceOracle.abi.json diff --git a/.env.example b/.env.example index 177cd99..459ac8c 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,7 @@ NET_ID=42 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 # without 0x prefix diff --git a/abis/PriceOracle.abi.json b/abis/PriceOracle.abi.json new file mode 100644 index 0000000..ac5be41 --- /dev/null +++ b/abis/PriceOracle.abi.json @@ -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" + } +] diff --git a/config.js b/config.js index 9fc3dee..ed4b53c 100644 --- a/config.js +++ b/config.js @@ -1,10 +1,12 @@ require('dotenv').config() module.exports = { - version: '1.0', + version: '1.1', netId: Number(process.env.NET_ID) || 42, 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, mixers: { netId1: { diff --git a/package.json b/package.json index ca86941..12827b6 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "license": "MIT", "dependencies": { "bull": "^3.12.1", - "coingecko-api": "^1.0.6", "dotenv": "^8.2.0", "express": "^4.17.1", "ioredis": "^4.14.1", diff --git a/src/Fetcher.js b/src/Fetcher.js index 5e68a5e..08bc1f1 100644 --- a/src/Fetcher.js +++ b/src/Fetcher.js @@ -1,37 +1,50 @@ -const CoinGecko = require('coingecko-api') const fetch = require('node-fetch') -const { toWei } = require('web3-utils') -const { gasOracleUrls, defaultGasPrice } = require('../config') -const { getMainnetTokens } = require('./utils') +const Web3 = require('Web3') +const { gasOracleUrls, defaultGasPrice, oracleRpcUrl, oracleAddress } = require('../config') +const { getArgsForOracle } = require('./utils') const { redisClient } = require('./redis') +const priceOracleABI = require('../abis/PriceOracle.abi.json') class Fetcher { constructor(web3) { this.web3 = web3 + this.oracleWeb3 = new Web3(oracleRpcUrl) + this.oracle = new this.oracleWeb3.eth.Contract(priceOracleABI, oracleAddress) 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 = { fast: defaultGasPrice } + + const { tokenAddresses, oneUintAmount, parts, currencyLookup } = getArgsForOracle() + this.tokenAddresses = tokenAddresses + this.oneUintAmount = oneUintAmount + this.parts = parts + this.currencyLookup = currencyLookup } async fetchPrices() { - const { tokenAddresses, currencyLookup } = getMainnetTokens() try { - const CoinGeckoClient = new CoinGecko() - const price = await CoinGeckoClient.simple.fetchTokenPrice({ - contract_addresses: tokenAddresses, - vs_currencies: 'eth', - assetPlatform: 'ethereum' - }) - this.ethPrices = Object.entries(price.data).reduce((acc, token) => { - if (token[1].eth) { - acc[currencyLookup[token[0]]] = toWei(token[1].eth.toString()) - } + let prices = await this.oracle.methods.getPricesInETH( + this.tokenAddresses, + this.oneUintAmount, + this.parts + ).call() + this.ethPrices = prices.reduce((acc, price, i) => { + acc[this.currencyLookup[this.tokenAddresses[i]]] = price return acc }, {}) setTimeout(() => this.fetchPrices(), 1000 * 30) } catch(e) { + console.error('fetchPrices', e) setTimeout(() => this.fetchPrices(), 1000 * 30) } } diff --git a/src/utils.js b/src/utils.js index fe6265d..6dd1a63 100644 --- a/src/utils.js +++ b/src/utils.js @@ -138,21 +138,29 @@ function isEnoughFee({ gas, gasPrices, currency, amount, refund, ethPrices, fee return { isEnough: true } } -function getMainnetTokens() { +function getArgsForOracle() { const tokens = mixers['netId1'] const tokenAddresses = [] + const oneUintAmount = [] + const parts = [] // this is probably should be removed const currencyLookup = {} Object.entries(tokens).map(([currency, data]) => { if (currency !== 'eth') { 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() { return mixers[`netId${netId}`] } -module.exports = { isValidProof, isValidArgs, sleep, isKnownContract, isEnoughFee, getMixers, getMainnetTokens } +module.exports = { isValidProof, isValidArgs, sleep, isKnownContract, isEnoughFee, getMixers, getArgsForOracle } diff --git a/yarn.lock b/yarn.lock index 8afa542..a5fc4fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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" 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: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"