fix: cancel/replace

This commit is contained in:
Danil Kovtonyuk 2022-07-12 23:00:55 +10:00
parent d36a8fec96
commit e39cf2825d
No known key found for this signature in database
GPG Key ID: E72A919BF08C3746
2 changed files with 36 additions and 14 deletions

View File

@ -37,6 +37,7 @@ class Transaction {
this._promise = PromiEvent()
this._emitter = this._promise.eventEmitter
this.executed = false
this.replaced = false
this.retries = 0
this.currentTxHash = null
// store all submitted hashes to catch cases when an old tx is mined
@ -63,6 +64,10 @@ class Transaction {
*/
async replace(tx) {
// todo throw error if the current transaction is mined already
// if (this.currentTxHash) {
// throw new Error('Previous transaction was mined')
// }
console.log('Replacing current transaction')
if (!this.executed) {
// Tx was not executed yet, just replace it
@ -80,7 +85,7 @@ class Transaction {
? min(gasLimit, this.manager.config.BLOCK_GAS_LIMIT)
: gasLimit
}
// TODO: check if the new tx params is valid
tx.chainId = this.tx.chainId
tx.nonce = this.tx.nonce // can be different from `this.manager._nonce`
@ -90,13 +95,16 @@ class Transaction {
} else if (this.tx.maxFeePerGas) {
tx.maxFeePerGas = max(this.tx.maxFeePerGas, tx.maxFeePerGas || 0)
tx.maxPriorityFeePerGas = max(this.tx.maxPriorityFeePerGas, tx.maxPriorityFeePerGas || 0)
} else {
const gasParams = await this._getGasParams()
tx = { ...tx, ...gasParams }
}
this.tx = { ...tx }
this._increaseGasPrice()
await this._prepare()
if (tx.gasPrice || tx.maxFeePerGas) {
this._increaseGasPrice()
}
this.replaced = true
await this._send()
}
@ -148,7 +156,10 @@ class Transaction {
const net = await this.manager._provider.getNetwork()
this.manager._chainId = net.chainId
}
this.tx.chainId = this.manager._chainId
if (!this.tx.chainId) {
this.tx.chainId = this.manager._chainId
}
if (!this.tx.gasLimit || this.manager.config.ESTIMATE_GAS) {
const gas = await this._estimateGas(this.tx)
@ -161,15 +172,15 @@ class Transaction {
if (!this.manager._nonce) {
this.manager._nonce = await this._getLastNonce()
}
this.tx.nonce = this.manager._nonce
if (this.tx.gasPrice || (this.tx.maxFeePerGas && this.tx.maxPriorityFeePerGas)) {
return
if (!this.tx.nonce) {
this.tx.nonce = this.manager._nonce
}
const gasParams = await this._getGasParams()
this.tx = Object.assign(this.tx, gasParams)
if (!this.tx.gasPrice && !this.tx.maxFeePerGas && !this.tx.maxPriorityFeePerGas) {
const gasParams = await this._getGasParams()
this.tx = Object.assign(this.tx, gasParams)
}
}
/**
@ -317,6 +328,10 @@ class Transaction {
// nonce is too low, trying to increase and resubmit
if (this._hasError(message, nonceErrors)) {
if (this.replaced) {
console.log('Transaction with the same nonce was mined')
return // do nothing
}
console.log(`Nonce ${this.tx.nonce} is too low, increasing and retrying`)
if (this.retries <= this.manager.config.MAX_RETRIES) {
this.tx.nonce++

View File

@ -91,16 +91,23 @@ const transactionTests = () => {
})
it('should cancel', async () => {
const currentNonce = await this.manager._wallet.getTransactionCount('latest')
const tx = this.manager.createTx(tx3)
setTimeout(() => tx.cancel(), 1000)
await sendTx(tx)
const receipt = await sendTx(tx)
const transaction = await this.manager._provider.getTransaction(receipt.transactionHash)
transaction.value.toNumber().should.equal(0)
transaction.nonce.should.equal(currentNonce)
})
it('should replace', async () => {
const currentNonce = await this.manager._wallet.getTransactionCount('latest')
const tx = this.manager.createTx(tx3)
setTimeout(() => tx.replace(tx4), 1000)
const receipt = await sendTx(tx)
const transaction = await this.manager._provider.getTransaction(receipt.transactionHash)
receipt.to.should.equal(tx4.to)
transaction.nonce.should.equal(currentNonce)
})
it('should increase nonce', async () => {
@ -118,7 +125,7 @@ const transactionTests = () => {
this.manager.config.ENABLE_EIP1559 = true
})
it.skip('should send multiple txs', async () => {
it('should send multiple txs', async () => {
const genTx = value => ({
value,
to: '0x0039F22efB07A647557C7C5d17854CFD6D489eF3',