update gas-price-oracle
This commit is contained in:
parent
f8cb27e6d5
commit
1ac1b6c5ce
@ -17,7 +17,9 @@
|
|||||||
"indent": [
|
"indent": [
|
||||||
"error",
|
"error",
|
||||||
2,
|
2,
|
||||||
{"SwitchCase": 1}
|
{
|
||||||
|
"SwitchCase": 1
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"linebreak-style": [
|
"linebreak-style": [
|
||||||
"error",
|
"error",
|
||||||
@ -35,6 +37,14 @@
|
|||||||
"error",
|
"error",
|
||||||
"always"
|
"always"
|
||||||
],
|
],
|
||||||
"require-await": "error"
|
"require-await": "error",
|
||||||
|
"space-before-function-paren": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"anonymous": "always",
|
||||||
|
"named": "never",
|
||||||
|
"asyncArrow": "always"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
version: 2.7,
|
version: 2.8,
|
||||||
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/',
|
rpcUrl: process.env.RPC_URL || 'https://kovan.infura.io/',
|
||||||
@ -145,7 +145,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
defaultGasPrice: 20,
|
defaultGasPrice: 20,
|
||||||
gasOracleUrls: ['https://ethgasstation.info/json/ethgasAPI.json', 'https://gas-oracle.zoltu.io/'],
|
|
||||||
port: process.env.APP_PORT,
|
port: process.env.APP_PORT,
|
||||||
relayerServiceFee: Number(process.env.RELAYER_FEE),
|
relayerServiceFee: Number(process.env.RELAYER_FEE),
|
||||||
maxGasPrice: process.env.MAX_GAS_PRICE || 200,
|
maxGasPrice: process.env.MAX_GAS_PRICE || 200,
|
||||||
|
40
package-lock.json
generated
40
package-lock.json
generated
@ -179,6 +179,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
||||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||||
},
|
},
|
||||||
|
"axios": {
|
||||||
|
"version": "0.19.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||||
|
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "1.5.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
@ -198,6 +206,11 @@
|
|||||||
"tweetnacl": "^0.14.3"
|
"tweetnacl": "^0.14.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bignumber.js": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
|
||||||
|
},
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
@ -1462,6 +1475,24 @@
|
|||||||
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
|
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"follow-redirects": {
|
||||||
|
"version": "1.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||||
|
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "=3.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"for-each": {
|
"for-each": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||||
@ -1535,6 +1566,15 @@
|
|||||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"gas-price-oracle": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/gas-price-oracle/-/gas-price-oracle-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-lIxzxu5LtkdUewaFl6MlBU2Me6rWL58ENeAOD2AM/KZYB0Os7EcIBq87ixTced4UF2zb9bzPcVPoEVuH7icOJQ==",
|
||||||
|
"requires": {
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"bignumber.js": "^9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"get-port": {
|
"get-port": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-port/-/get-port-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-port/-/get-port-5.0.0.tgz",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "relay",
|
"name": "relay",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Relayer for Tornado mixer. https://tornado.cash",
|
"description": "Relayer for Tornado.cash privacy solution. https://tornado.cash",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node app.js",
|
"start": "node app.js",
|
||||||
@ -14,6 +14,7 @@
|
|||||||
"bull": "^3.12.1",
|
"bull": "^3.12.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"gas-price-oracle": "^0.1.4",
|
||||||
"ioredis": "^4.14.1",
|
"ioredis": "^4.14.1",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"web3": "^1.2.2",
|
"web3": "^1.2.2",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
const fetch = require('node-fetch')
|
|
||||||
const Web3 = require('web3')
|
const Web3 = require('web3')
|
||||||
const { gasOracleUrls, defaultGasPrice, oracleRpcUrl, oracleAddress } = require('../config')
|
const { defaultGasPrice, oracleRpcUrl, oracleAddress } = require('../config')
|
||||||
const { getArgsForOracle } = require('./utils')
|
const { getArgsForOracle } = require('./utils')
|
||||||
const { redisClient } = require('./redis')
|
const { redisClient } = require('./redis')
|
||||||
const priceOracleABI = require('../abis/PriceOracle.abi.json')
|
const priceOracleABI = require('../abis/PriceOracle.abi.json')
|
||||||
@ -44,35 +43,6 @@ class Fetcher {
|
|||||||
setTimeout(() => this.fetchPrices(), 1000 * 30)
|
setTimeout(() => this.fetchPrices(), 1000 * 30)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fetchGasPrice({ oracleIndex = 0 } = {}) {
|
|
||||||
oracleIndex = (oracleIndex + 1) % gasOracleUrls.length
|
|
||||||
const url = gasOracleUrls[oracleIndex]
|
|
||||||
const delimiter = url === 'https://ethgasstation.info/json/ethgasAPI.json' ? 10 : 1
|
|
||||||
try {
|
|
||||||
const response = await fetch(url)
|
|
||||||
if (response.status === 200) {
|
|
||||||
const json = await response.json()
|
|
||||||
if (Number(json.fast) === 0) {
|
|
||||||
throw new Error('Fetch gasPrice failed')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.fast) {
|
|
||||||
this.gasPrices.fast = Number(json.fast) / delimiter
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.percentile_97) {
|
|
||||||
this.gasPrices.fast = parseInt(json.percentile_90) + 1 / delimiter
|
|
||||||
}
|
|
||||||
// console.log('gas price fetch', this.gasPrices)
|
|
||||||
} else {
|
|
||||||
throw Error('Fetch gasPrice failed')
|
|
||||||
}
|
|
||||||
setTimeout(() => this.fetchGasPrice({ oracleIndex }), 15000)
|
|
||||||
} catch (e) {
|
|
||||||
console.log('fetchGasPrice', e.message)
|
|
||||||
setTimeout(() => this.fetchGasPrice({ oracleIndex }), 15000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async fetchNonce() {
|
async fetchNonce() {
|
||||||
try {
|
try {
|
||||||
const nonce = await this.web3.eth.getTransactionCount(this.web3.eth.defaultAccount)
|
const nonce = await this.web3.eth.getTransactionCount(this.web3.eth.defaultAccount)
|
||||||
|
@ -10,7 +10,7 @@ const {
|
|||||||
maxGasPrice
|
maxGasPrice
|
||||||
} = require('../config')
|
} = require('../config')
|
||||||
const relayController = require('./relayController')
|
const relayController = require('./relayController')
|
||||||
const { fetcher, web3 } = require('./instances')
|
const { fetcher, web3, gasPriceOracle } = require('./instances')
|
||||||
const { getMixers } = require('./utils')
|
const { getMixers } = require('./utils')
|
||||||
const mixers = getMixers()
|
const mixers = getMixers()
|
||||||
const { redisClient } = require('./redis')
|
const { redisClient } = require('./redis')
|
||||||
@ -39,11 +39,11 @@ app.get('/', function (req, res) {
|
|||||||
|
|
||||||
app.get('/status', async function (req, res) {
|
app.get('/status', async function (req, res) {
|
||||||
let nonce = await redisClient.get('nonce')
|
let nonce = await redisClient.get('nonce')
|
||||||
const { ethPrices, gasPrices } = fetcher
|
const { ethPrices } = fetcher
|
||||||
res.json({
|
res.json({
|
||||||
relayerAddress: web3.eth.defaultAccount,
|
relayerAddress: web3.eth.defaultAccount,
|
||||||
mixers,
|
mixers,
|
||||||
gasPrices,
|
gasPrices: await gasPriceOracle.gasPrices(),
|
||||||
netId,
|
netId,
|
||||||
ethPrices,
|
ethPrices,
|
||||||
relayerServiceFee,
|
relayerServiceFee,
|
||||||
@ -57,14 +57,12 @@ app.post('/relay', relayController)
|
|||||||
let server = app.listen(port || 8000)
|
let server = app.listen(port || 8000)
|
||||||
server.setTimeout(600000)
|
server.setTimeout(600000)
|
||||||
console.log('Gas price oracle started.')
|
console.log('Gas price oracle started.')
|
||||||
fetcher.fetchGasPrice()
|
|
||||||
fetcher.fetchPrices()
|
fetcher.fetchPrices()
|
||||||
fetcher.fetchNonce()
|
fetcher.fetchNonce()
|
||||||
|
|
||||||
console.log('Relayer started on port', port || 8000)
|
console.log('Relayer started on port', port || 8000)
|
||||||
console.log(`relayerAddress: ${web3.eth.defaultAccount}`)
|
console.log(`relayerAddress: ${web3.eth.defaultAccount}`)
|
||||||
console.log(`mixers: ${JSON.stringify(mixers)}`)
|
console.log(`mixers: ${JSON.stringify(mixers)}`)
|
||||||
console.log(`gasPrices: ${JSON.stringify(fetcher.gasPrices)}`)
|
|
||||||
console.log(`netId: ${netId}`)
|
console.log(`netId: ${netId}`)
|
||||||
console.log(`ethPrices: ${JSON.stringify(fetcher.ethPrices)}`)
|
console.log(`ethPrices: ${JSON.stringify(fetcher.ethPrices)}`)
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
|
const { rpcUrl } = require('../config')
|
||||||
const Fetcher = require('./Fetcher')
|
const Fetcher = require('./Fetcher')
|
||||||
const Sender = require('./sender')
|
const Sender = require('./sender')
|
||||||
|
const { GasPriceOracle } = require('gas-price-oracle')
|
||||||
const web3 = require('./setupWeb3')
|
const web3 = require('./setupWeb3')
|
||||||
const fetcher = new Fetcher(web3)
|
const fetcher = new Fetcher(web3)
|
||||||
const sender = new Sender(web3)
|
const sender = new Sender(web3)
|
||||||
|
const gasPriceOracle = new GasPriceOracle({ defaultRpc: rpcUrl })
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fetcher,
|
fetcher,
|
||||||
web3,
|
web3,
|
||||||
sender
|
sender,
|
||||||
|
gasPriceOracle
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ const {
|
|||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const { redisClient, redisOpts } = require('./redis')
|
const { redisClient, redisOpts } = require('./redis')
|
||||||
|
|
||||||
const { web3, fetcher, sender } = require('./instances')
|
const { web3, fetcher, sender, gasPriceOracle } = require('./instances')
|
||||||
const withdrawQueue = new Queue('withdraw', redisOpts)
|
const withdrawQueue = new Queue('withdraw', redisOpts)
|
||||||
|
|
||||||
const reponseCbs = {}
|
const reponseCbs = {}
|
||||||
@ -67,7 +67,7 @@ async function relayController(req, resp) {
|
|||||||
|
|
||||||
withdrawQueue.process(async function (job, done) {
|
withdrawQueue.process(async function (job, done) {
|
||||||
console.log(Date.now(), ' withdraw started', job.id)
|
console.log(Date.now(), ' withdraw started', job.id)
|
||||||
const gasPrices = fetcher.gasPrices
|
const gasPrices = await gasPriceOracle.gasPrices()
|
||||||
const { contract, nullifierHash, root, proof, args, refund, currency, amount, fee } = job.data
|
const { contract, nullifierHash, root, proof, args, refund, currency, amount, fee } = job.data
|
||||||
console.log(JSON.stringify(job.data))
|
console.log(JSON.stringify(job.data))
|
||||||
// job.data contains the custom data passed when the job was created
|
// job.data contains the custom data passed when the job was created
|
||||||
|
@ -19,7 +19,7 @@ class Sender {
|
|||||||
tx = JSON.parse(tx)
|
tx = JSON.parse(tx)
|
||||||
if (Date.now() - tx.date > this.pendingTxTimeout) {
|
if (Date.now() - tx.date > this.pendingTxTimeout) {
|
||||||
const newGasPrice = toBN(tx.gasPrice).mul(toBN(this.gasBumpPercentage)).div(toBN(100))
|
const newGasPrice = toBN(tx.gasPrice).mul(toBN(this.gasBumpPercentage)).div(toBN(100))
|
||||||
const maxGasPrice = toBN(toWei(config.maxGasPrice))
|
const maxGasPrice = toBN(toWei(config.maxGasPrice.toString()))
|
||||||
tx.gasPrice = toHex(BN.min(newGasPrice, maxGasPrice))
|
tx.gasPrice = toHex(BN.min(newGasPrice, maxGasPrice))
|
||||||
tx.date = Date.now()
|
tx.date = Date.now()
|
||||||
await redisClient.set('tx:' + tx.nonce, JSON.stringify(tx))
|
await redisClient.set('tx:' + tx.nonce, JSON.stringify(tx))
|
||||||
@ -38,7 +38,7 @@ class Sender {
|
|||||||
let signedTx = await this.web3.eth.accounts.signTransaction(tx, config.privateKey)
|
let signedTx = await this.web3.eth.accounts.signTransaction(tx, config.privateKey)
|
||||||
let result = this.web3.eth.sendSignedTransaction(signedTx.rawTransaction)
|
let result = this.web3.eth.sendSignedTransaction(signedTx.rawTransaction)
|
||||||
|
|
||||||
result.once('transactionHash', function(txHash){
|
result.once('transactionHash', (txHash) => {
|
||||||
console.log(`A new successfully sent tx ${txHash}`)
|
console.log(`A new successfully sent tx ${txHash}`)
|
||||||
if (done) {
|
if (done) {
|
||||||
done(null, {
|
done(null, {
|
||||||
@ -46,7 +46,7 @@ class Sender {
|
|||||||
msg: { txHash }
|
msg: { txHash }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).on('error', async function(e){
|
}).on('error', async (e) => {
|
||||||
console.log(`Error for tx with nonce ${tx.nonce}\n${e.message}`)
|
console.log(`Error for tx with nonce ${tx.nonce}\n${e.message}`)
|
||||||
if (e.message === 'Returned error: Transaction gas price supplied is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce.'
|
if (e.message === 'Returned error: Transaction gas price supplied is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce.'
|
||||||
|| e.message === 'Returned error: Transaction nonce is too low. Try incrementing the nonce.'
|
|| e.message === 'Returned error: Transaction nonce is too low. Try incrementing the nonce.'
|
||||||
|
Loading…
Reference in New Issue
Block a user