test tx manager
This commit is contained in:
parent
7000e1fffa
commit
6244ed7392
@ -20,18 +20,18 @@ const defaultConfig = {
|
|||||||
GAS_BUMP_PERCENTAGE: 5,
|
GAS_BUMP_PERCENTAGE: 5,
|
||||||
GAS_BUMP_INTERVAL: 1000 * 60 * 5,
|
GAS_BUMP_INTERVAL: 1000 * 60 * 5,
|
||||||
MAX_GAS_PRICE: 1000,
|
MAX_GAS_PRICE: 1000,
|
||||||
POLL_INTERVAL: 3000,
|
POLL_INTERVAL: 5000,
|
||||||
CONFIRMATIONS: 8,
|
CONFIRMATIONS: 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
class TxManager {
|
class TxManager {
|
||||||
constructor({ privateKey, rpcUrl, broadcastNodes = [], config = {} }) {
|
constructor({ privateKey, rpcUrl, broadcastNodes = [], config = {} }) {
|
||||||
this.config = Object.assign({ ...defaultConfig }, config)
|
this.config = Object.assign({ ...defaultConfig }, config)
|
||||||
this._privateKey = privateKey
|
this._privateKey = '0x' + privateKey
|
||||||
this._web3 = new Web3(rpcUrl)
|
this._web3 = new Web3(rpcUrl)
|
||||||
this._broadcastNodes = broadcastNodes
|
this._broadcastNodes = broadcastNodes
|
||||||
this.address = this._web3.eth.accounts.privateKeyToAccount('0x' + privateKey).address
|
this.address = this._web3.eth.accounts.privateKeyToAccount(this._privateKey).address
|
||||||
this._web3.eth.accounts.wallet.add('0x' + privateKey)
|
this._web3.eth.accounts.wallet.add(this._privateKey)
|
||||||
this._web3.eth.defaultAccount = this.address
|
this._web3.eth.defaultAccount = this.address
|
||||||
this._gasPriceOracle = new GasPriceOracle({ defaultRpc: rpcUrl })
|
this._gasPriceOracle = new GasPriceOracle({ defaultRpc: rpcUrl })
|
||||||
this._mutex = new Mutex()
|
this._mutex = new Mutex()
|
||||||
@ -49,10 +49,16 @@ class TxManager {
|
|||||||
*
|
*
|
||||||
* @param tx Transaction to send
|
* @param tx Transaction to send
|
||||||
*/
|
*/
|
||||||
async submit(tx) {
|
submit(tx) {
|
||||||
|
const _promiEvent = promiEvent()
|
||||||
|
this._submit(tx, _promiEvent)
|
||||||
|
return _promiEvent.eventEmitter
|
||||||
|
}
|
||||||
|
|
||||||
|
async _submit(tx, _promiEvent) {
|
||||||
const release = await this._mutex.acquire()
|
const release = await this._mutex.acquire()
|
||||||
try {
|
try {
|
||||||
await new Transaction(tx, this).submit()
|
return new Transaction(tx, this).submit(_promiEvent)
|
||||||
} finally {
|
} finally {
|
||||||
release()
|
release()
|
||||||
}
|
}
|
||||||
@ -72,11 +78,9 @@ class Transaction {
|
|||||||
this.hashes = []
|
this.hashes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit(_promiEvent) {
|
||||||
await this._prepare()
|
await this._prepare()
|
||||||
const _promiEvent = promiEvent()
|
await this._send(_promiEvent)
|
||||||
this._send(_promiEvent)
|
|
||||||
return _promiEvent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _prepare() {
|
async _prepare() {
|
||||||
@ -86,37 +90,44 @@ class Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _send(_promiEvent) {
|
async _send(_promiEvent) {
|
||||||
const signedTx = await this._web3.eth.accounts.signTransaction(this.tx, this.privateKey)
|
const signedTx = await this._web3.eth.accounts.signTransaction(this.tx, this._privateKey)
|
||||||
this.tx.date = Date.now()
|
this.tx.date = Date.now()
|
||||||
this.tx.hash = signedTx.transactionHash
|
this.tx.hash = signedTx.transactionHash
|
||||||
this.hashes.push(this.tx.hash)
|
this.hashes.push(this.tx.hash)
|
||||||
_promiEvent.emit('transactionHash', signedTx.transactionHash)
|
_promiEvent.eventEmitter.emit('transactionHash', signedTx.transactionHash)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this._broadcast(signedTx.rawTransaction)
|
await this._broadcast(signedTx.rawTransaction)
|
||||||
|
console.log('Broadcasted. Start waiting for mining...')
|
||||||
// The most reliable way to see if one of our tx was mined is to track current nonce
|
// The most reliable way to see if one of our tx was mined is to track current nonce
|
||||||
while (this.tx.nonce <= (await this._getLastNonce())) {
|
let latestNonce = await this._getLastNonce()
|
||||||
|
while (this.tx.nonce > latestNonce) {
|
||||||
if (Date.now() - this.tx.date >= this.config.GAS_BUMP_INTERVAL) {
|
if (Date.now() - this.tx.date >= this.config.GAS_BUMP_INTERVAL) {
|
||||||
if (this._increaseGasPrice()) {
|
if (this._increaseGasPrice()) {
|
||||||
|
console.log('Resubmit with higher gas price')
|
||||||
return this._send()
|
return this._send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await sleep(this.config.POLL_INTERVAL)
|
await sleep(this.config.POLL_INTERVAL)
|
||||||
}
|
}
|
||||||
// got mined, let's check
|
console.log('Mined. Start waiting for confirmations...')
|
||||||
|
await sleep(5000) // todo
|
||||||
let receipt = await this._getReceipts()
|
let receipt = await this._getReceipts()
|
||||||
if (!receipt) {
|
if (!receipt) {
|
||||||
// resubmit
|
// resubmit
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentBlock = await this._web3.eth.getBlockNumber()
|
let currentBlock = await this._web3.eth.getBlockNumber()
|
||||||
let confirmations = currentBlock - receipt.blockNumber
|
let confirmations = currentBlock > receipt.blockNumber ? currentBlock - receipt.blockNumber : 0
|
||||||
while (confirmations < this.config.CONFIRMATIONS) {
|
while (confirmations <= this.config.CONFIRMATIONS) {
|
||||||
_promiEvent.emit('confirmations', confirmations)
|
_promiEvent.eventEmitter.emit('confirmations', confirmations)
|
||||||
|
|
||||||
await sleep(this.config.POLL_INTERVAL)
|
await sleep(this.config.POLL_INTERVAL)
|
||||||
receipt = await this._getReceipts()
|
receipt = await this._getReceipts()
|
||||||
|
if (!receipt) {
|
||||||
|
// resubmit
|
||||||
|
}
|
||||||
currentBlock = await this._web3.eth.getBlockNumber()
|
currentBlock = await this._web3.eth.getBlockNumber()
|
||||||
confirmations = currentBlock - receipt.blockNumber
|
confirmations = currentBlock - receipt.blockNumber
|
||||||
}
|
}
|
||||||
@ -125,6 +136,7 @@ class Transaction {
|
|||||||
this.manager.nonce = this.tx.nonce + 1
|
this.manager.nonce = this.tx.nonce + 1
|
||||||
_promiEvent.resolve(receipt)
|
_promiEvent.resolve(receipt)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log('_send', e)
|
||||||
await this._handleSendError()
|
await this._handleSendError()
|
||||||
|
|
||||||
// _promiEvent.reject(error) ?
|
// _promiEvent.reject(error) ?
|
||||||
@ -198,7 +210,7 @@ class Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getLastNonce() {
|
_getLastNonce() {
|
||||||
return this.web3.eth.getTransactionCount(this.address, 'latest')
|
return this._web3.eth.getTransactionCount(this.address, 'latest')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
testTxManager.js
Normal file
27
testTxManager.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const { toHex, toWei } = require('web3-utils')
|
||||||
|
const TxManager = require('./src/TxManager')
|
||||||
|
const { rpcUrl, privateKey } = require('./config')
|
||||||
|
const TxM = new TxManager({
|
||||||
|
privateKey,
|
||||||
|
rpcUrl,
|
||||||
|
})
|
||||||
|
|
||||||
|
const tx = {
|
||||||
|
from: '0x03Ebd0748Aa4D1457cF479cce56309641e0a98F5',
|
||||||
|
value: 0,
|
||||||
|
gasPrice: toHex(toWei('1', 'gwei')),
|
||||||
|
to: '0x03Ebd0748Aa4D1457cF479cce56309641e0a98F5',
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const receipt = await TxM.submit(tx)
|
||||||
|
.on('transactionHash', (hash) => {
|
||||||
|
console.log('hash', hash)
|
||||||
|
})
|
||||||
|
.on('confirmations', (confirmations) => {
|
||||||
|
console.log('confirmations', confirmations)
|
||||||
|
})
|
||||||
|
console.log('receipt', receipt)
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user