tornado-relayer/src/sender.js

77 lines
2.8 KiB
JavaScript
Raw Normal View History

2020-05-07 17:19:09 -04:00
const { redisClient } = require('./redis')
const config = require('../config')
2020-05-08 13:29:31 -04:00
const { toBN, toHex, toWei, BN, fromWei } = require('web3-utils')
2020-05-07 17:19:09 -04:00
class Sender {
2020-05-08 13:29:31 -04:00
constructor(web3) {
2020-05-07 17:19:09 -04:00
this.web3 = web3
2020-05-08 13:29:31 -04:00
this.watherInterval = config.watherInterval
this.pendingTxTimeout = config.pendingTxTimeout
2020-05-08 15:03:33 -04:00
this.gasBumpPercentage = 100 + Number(config.gasBumpPercentage)
2020-05-08 13:29:31 -04:00
this.watcher()
2020-05-07 17:19:09 -04:00
}
2020-05-08 13:29:31 -04:00
async watcher() {
try {
const networkNonce = await this.web3.eth.getTransactionCount(this.web3.eth.defaultAccount)
let tx = await redisClient.get('tx:' + networkNonce)
if (tx) {
tx = JSON.parse(tx)
if (Date.now() - tx.date > this.pendingTxTimeout) {
const newGasPrice = toBN(tx.gasPrice).mul(toBN(this.gasBumpPercentage)).div(toBN(100))
2020-07-16 09:33:35 -04:00
const maxGasPrice = toBN(toWei(config.maxGasPrice.toString()))
2020-05-08 13:29:31 -04:00
tx.gasPrice = toHex(BN.min(newGasPrice, maxGasPrice))
tx.date = Date.now()
2020-07-16 09:33:35 -04:00
await redisClient.set('tx:' + tx.nonce, JSON.stringify(tx))
2020-05-08 15:03:33 -04:00
console.log('resubmitting with gas price', fromWei(tx.gasPrice.toString(), 'gwei'), ' gwei')
2020-05-08 13:29:31 -04:00
this.sendTx(tx, null, 9999)
}
}
2020-07-16 09:33:35 -04:00
} catch (e) {
2020-05-08 13:29:31 -04:00
console.error('watcher error:', e)
} finally {
setTimeout(() => this.watcher(), this.watherInterval)
2020-05-07 17:19:09 -04:00
}
}
2020-05-08 13:29:31 -04:00
async sendTx(tx, done, retryAttempt = 1) {
2020-05-07 17:19:09 -04:00
let signedTx = await this.web3.eth.accounts.signTransaction(tx, config.privateKey)
let result = this.web3.eth.sendSignedTransaction(signedTx.rawTransaction)
2020-05-08 13:29:31 -04:00
2020-07-16 09:33:35 -04:00
result.once('transactionHash', (txHash) => {
2020-05-08 13:29:31 -04:00
console.log(`A new successfully sent tx ${txHash}`)
if (done) {
done(null, {
status: 200,
msg: { txHash }
})
}
2020-07-16 09:33:35 -04:00
}).on('error', async (e) => {
2020-05-08 13:29:31 -04:00
console.log(`Error for tx with nonce ${tx.nonce}\n${e.message}`)
2020-07-16 09:33:35 -04:00
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: nonce too low'
|| e.message === 'Returned error: replacement transaction underpriced') {
2020-05-07 17:19:09 -04:00
console.log('nonce too low, retrying')
2020-07-16 09:33:35 -04:00
if (retryAttempt <= 10) {
2020-05-07 17:19:09 -04:00
retryAttempt++
const newNonce = tx.nonce + 1
tx.nonce = newNonce
await redisClient.set('nonce', newNonce)
2020-05-08 13:29:31 -04:00
await redisClient.set('tx:' + newNonce, JSON.stringify(tx))
this.sendTx(tx, done, retryAttempt)
2020-05-07 17:19:09 -04:00
return
}
}
2020-05-08 13:29:31 -04:00
if (done) {
done(null, {
status: 400,
msg: { error: 'Internal Relayer Error. Please use a different relayer service' }
})
}
2020-05-07 17:19:09 -04:00
})
}
}
2020-05-08 13:29:31 -04:00
module.exports = Sender