mirror of
https://github.com/tornadocash/tx-manager.git
synced 2024-06-17 01:43:27 +02:00
fix: cancel/replace
This commit is contained in:
parent
d36a8fec96
commit
e39cf2825d
|
@ -37,6 +37,7 @@ class Transaction {
|
||||||
this._promise = PromiEvent()
|
this._promise = PromiEvent()
|
||||||
this._emitter = this._promise.eventEmitter
|
this._emitter = this._promise.eventEmitter
|
||||||
this.executed = false
|
this.executed = false
|
||||||
|
this.replaced = false
|
||||||
this.retries = 0
|
this.retries = 0
|
||||||
this.currentTxHash = null
|
this.currentTxHash = null
|
||||||
// store all submitted hashes to catch cases when an old tx is mined
|
// store all submitted hashes to catch cases when an old tx is mined
|
||||||
|
@ -63,6 +64,10 @@ class Transaction {
|
||||||
*/
|
*/
|
||||||
async replace(tx) {
|
async replace(tx) {
|
||||||
// todo throw error if the current transaction is mined already
|
// 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')
|
console.log('Replacing current transaction')
|
||||||
if (!this.executed) {
|
if (!this.executed) {
|
||||||
// Tx was not executed yet, just replace it
|
// Tx was not executed yet, just replace it
|
||||||
|
@ -80,7 +85,7 @@ class Transaction {
|
||||||
? min(gasLimit, this.manager.config.BLOCK_GAS_LIMIT)
|
? min(gasLimit, this.manager.config.BLOCK_GAS_LIMIT)
|
||||||
: gasLimit
|
: gasLimit
|
||||||
}
|
}
|
||||||
// TODO: check if the new tx params is valid
|
|
||||||
tx.chainId = this.tx.chainId
|
tx.chainId = this.tx.chainId
|
||||||
tx.nonce = this.tx.nonce // can be different from `this.manager._nonce`
|
tx.nonce = this.tx.nonce // can be different from `this.manager._nonce`
|
||||||
|
|
||||||
|
@ -90,13 +95,16 @@ class Transaction {
|
||||||
} else if (this.tx.maxFeePerGas) {
|
} else if (this.tx.maxFeePerGas) {
|
||||||
tx.maxFeePerGas = max(this.tx.maxFeePerGas, tx.maxFeePerGas || 0)
|
tx.maxFeePerGas = max(this.tx.maxFeePerGas, tx.maxFeePerGas || 0)
|
||||||
tx.maxPriorityFeePerGas = max(this.tx.maxPriorityFeePerGas, tx.maxPriorityFeePerGas || 0)
|
tx.maxPriorityFeePerGas = max(this.tx.maxPriorityFeePerGas, tx.maxPriorityFeePerGas || 0)
|
||||||
} else {
|
|
||||||
const gasParams = await this._getGasParams()
|
|
||||||
tx = { ...tx, ...gasParams }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tx = { ...tx }
|
this.tx = { ...tx }
|
||||||
this._increaseGasPrice()
|
await this._prepare()
|
||||||
|
|
||||||
|
if (tx.gasPrice || tx.maxFeePerGas) {
|
||||||
|
this._increaseGasPrice()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.replaced = true
|
||||||
await this._send()
|
await this._send()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +156,10 @@ class Transaction {
|
||||||
const net = await this.manager._provider.getNetwork()
|
const net = await this.manager._provider.getNetwork()
|
||||||
this.manager._chainId = net.chainId
|
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) {
|
if (!this.tx.gasLimit || this.manager.config.ESTIMATE_GAS) {
|
||||||
const gas = await this._estimateGas(this.tx)
|
const gas = await this._estimateGas(this.tx)
|
||||||
|
@ -161,15 +172,15 @@ class Transaction {
|
||||||
if (!this.manager._nonce) {
|
if (!this.manager._nonce) {
|
||||||
this.manager._nonce = await this._getLastNonce()
|
this.manager._nonce = await this._getLastNonce()
|
||||||
}
|
}
|
||||||
this.tx.nonce = this.manager._nonce
|
|
||||||
|
|
||||||
if (this.tx.gasPrice || (this.tx.maxFeePerGas && this.tx.maxPriorityFeePerGas)) {
|
if (!this.tx.nonce) {
|
||||||
return
|
this.tx.nonce = this.manager._nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
const gasParams = await this._getGasParams()
|
if (!this.tx.gasPrice && !this.tx.maxFeePerGas && !this.tx.maxPriorityFeePerGas) {
|
||||||
|
const gasParams = await this._getGasParams()
|
||||||
this.tx = Object.assign(this.tx, gasParams)
|
this.tx = Object.assign(this.tx, gasParams)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -317,6 +328,10 @@ class Transaction {
|
||||||
|
|
||||||
// nonce is too low, trying to increase and resubmit
|
// nonce is too low, trying to increase and resubmit
|
||||||
if (this._hasError(message, nonceErrors)) {
|
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`)
|
console.log(`Nonce ${this.tx.nonce} is too low, increasing and retrying`)
|
||||||
if (this.retries <= this.manager.config.MAX_RETRIES) {
|
if (this.retries <= this.manager.config.MAX_RETRIES) {
|
||||||
this.tx.nonce++
|
this.tx.nonce++
|
||||||
|
|
|
@ -91,16 +91,23 @@ const transactionTests = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should cancel', async () => {
|
it('should cancel', async () => {
|
||||||
|
const currentNonce = await this.manager._wallet.getTransactionCount('latest')
|
||||||
const tx = this.manager.createTx(tx3)
|
const tx = this.manager.createTx(tx3)
|
||||||
setTimeout(() => tx.cancel(), 1000)
|
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 () => {
|
it('should replace', async () => {
|
||||||
|
const currentNonce = await this.manager._wallet.getTransactionCount('latest')
|
||||||
const tx = this.manager.createTx(tx3)
|
const tx = this.manager.createTx(tx3)
|
||||||
setTimeout(() => tx.replace(tx4), 1000)
|
setTimeout(() => tx.replace(tx4), 1000)
|
||||||
const receipt = await sendTx(tx)
|
const receipt = await sendTx(tx)
|
||||||
|
const transaction = await this.manager._provider.getTransaction(receipt.transactionHash)
|
||||||
receipt.to.should.equal(tx4.to)
|
receipt.to.should.equal(tx4.to)
|
||||||
|
transaction.nonce.should.equal(currentNonce)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should increase nonce', async () => {
|
it('should increase nonce', async () => {
|
||||||
|
@ -118,7 +125,7 @@ const transactionTests = () => {
|
||||||
this.manager.config.ENABLE_EIP1559 = true
|
this.manager.config.ENABLE_EIP1559 = true
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('should send multiple txs', async () => {
|
it('should send multiple txs', async () => {
|
||||||
const genTx = value => ({
|
const genTx = value => ({
|
||||||
value,
|
value,
|
||||||
to: '0x0039F22efB07A647557C7C5d17854CFD6D489eF3',
|
to: '0x0039F22efB07A647557C7C5d17854CFD6D489eF3',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user