10 Commits

Author SHA1 Message Date
Danil Kovtonyuk
37f6faa42d bump gas price oracle 2021-08-17 17:23:54 +10:00
Danil Kovtonyuk
9599788224 bump gas price oracle 2021-06-15 13:31:41 +03:00
Danil Kovtonyuk
72a665a19a add gasPriceOracleConfig 2021-06-03 16:16:31 +03:00
Roman Storm
f6a4e93a23 fix mutex 2021-02-16 22:08:12 -08:00
Roman Storm
af7c597af9 Merge branch 'master' of github.com:tornadocash/tx-manager 2021-02-16 21:48:51 -08:00
Roman Storm
221dce3d73 add MAX_GAS_PRICE 2021-02-16 21:48:44 -08:00
poma
8d4bab7fc2 handle bump gas price error 2021-02-17 08:40:14 +03:00
poma
af65d78be9 fix await 2021-02-17 08:39:50 +03:00
Roman Storm
bc0b369095 fix gas price bump 2021-02-16 20:01:30 -08:00
Alexey Pertsev
e1620e15c1 Block gas limit (#1)
update gas-price-oracle dep, add BLOCK_GAS_LIMIT const
2020-12-24 08:39:07 +03:00
5 changed files with 52 additions and 21 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "tx-manager",
"version": "0.2.9",
"version": "0.3.2",
"description": "",
"main": "index.js",
"scripts": {
@@ -23,7 +23,7 @@
"dependencies": {
"async-mutex": "^0.2.4",
"ethers": "^5.0.17",
"gas-price-oracle": "^0.2.0",
"gas-price-oracle": "^0.3.4",
"web3-core-promievent": "^1.3.0"
},
"devDependencies": {

View File

@@ -66,6 +66,7 @@ class Transaction {
if (!tx.gasLimit) {
tx.gasLimit = await this._wallet.estimateGas(tx)
tx.gasLimit = Math.floor(tx.gasLimit * this.config.GAS_LIMIT_MULTIPLIER)
tx.gasLimit = Math.min(tx.gasLimit, this.config.BLOCK_GAS_LIMIT)
}
tx.nonce = this.tx.nonce // can be different from `this.manager._nonce`
tx.gasPrice = Math.max(this.tx.gasPrice, tx.gasPrice || 0) // start no less than current tx gas price
@@ -95,16 +96,16 @@ class Transaction {
* @private
*/
async _execute() {
await this.manager._mutex.acquire()
const mutexRelease = await this.manager._mutex.acquire()
try {
await this._prepare()
await this._send()
const receipt = this._waitForConfirmations()
const receipt = await this._waitForConfirmations()
// we could have bumped nonce during execution, so get the latest one + 1
this.manager._nonce = this.tx.nonce + 1
return receipt
} finally {
this.manager._mutex.release()
mutexRelease()
}
}
@@ -115,14 +116,22 @@ class Transaction {
* @private
*/
async _prepare() {
if (!this.config.BLOCK_GAS_LIMIT) {
const lastBlock = await this._provider.getBlock('latest')
this.config.BLOCK_GAS_LIMIT = Math.floor(lastBlock.gasLimit.toNumber() * 0.95)
}
if (!this.tx.gasLimit || this.config.ESTIMATE_GAS) {
const gas = await this._wallet.estimateGas(this.tx)
if (!this.tx.gasLimit) {
this.tx.gasLimit = Math.floor(gas * this.config.GAS_LIMIT_MULTIPLIER)
const gasLimit = Math.floor(gas * this.config.GAS_LIMIT_MULTIPLIER)
this.tx.gasLimit = Math.min(gasLimit, this.config.BLOCK_GAS_LIMIT)
}
}
if (!this.tx.gasPrice) {
this.tx.gasPrice = await this._getGasPrice('fast')
const fastGasPrice = BigNumber.from(await this._getGasPrice('fast'))
const maxGasPrice = parseUnits(this.config.MAX_GAS_PRICE.toString(), 'gwei')
this.tx.gasPrice = min(fastGasPrice, maxGasPrice).toHexString()
}
if (!this.manager._nonce) {
this.manager._nonce = await this._getLastNonce()
@@ -293,8 +302,11 @@ class Transaction {
console.log(
`Gas price ${formatUnits(this.tx.gasPrice, 'gwei')} gwei is too low, increasing and retrying`,
)
this._increaseGasPrice()
if (this._increaseGasPrice()) {
return this._send()
} else {
throw new Error('Already at max gas price, but still not enough to submit the transaction')
}
}
if (this._hasError(message, sameTxErrors)) {
@@ -319,17 +331,17 @@ class Transaction {
}
_increaseGasPrice() {
const maxGasPrice = parseUnits(this.config.MAX_GAS_PRICE.toString(), 'gwei')
const minGweiBump = parseUnits(this.config.MIN_GWEI_BUMP.toString(), 'gwei')
const oldGasPrice = BigNumber.from(this.tx.gasPrice)
if (oldGasPrice.gte(maxGasPrice)) {
console.log('Already at max gas price, not bumping')
return false
}
const newGasPrice = max(
oldGasPrice.mul(100 + this.config.GAS_BUMP_PERCENTAGE).div(100),
oldGasPrice.add(minGweiBump),
)
const maxGasPrice = parseUnits(this.config.MAX_GAS_PRICE.toString(), 'gwei')
if (oldGasPrice.eq(maxGasPrice)) {
console.log('Already at max gas price, not bumping')
return false
}
this.tx.gasPrice = min(newGasPrice, maxGasPrice).toHexString()
console.log(`Increasing gas price to ${formatUnits(this.tx.gasPrice, 'gwei')} gwei`)
return true

View File

@@ -14,17 +14,18 @@ const defaultConfig = {
CONFIRMATIONS: 8,
ESTIMATE_GAS: true,
THROW_ON_REVERT: true,
BLOCK_GAS_LIMIT: null,
}
class TxManager {
constructor({ privateKey, rpcUrl, broadcastNodes = [], config = {} }) {
constructor({ privateKey, rpcUrl, broadcastNodes = [], config = {}, gasPriceOracleConfig = {} }) {
this.config = Object.assign({ ...defaultConfig }, config)
this._privateKey = privateKey.startsWith('0x') ? privateKey : '0x' + privateKey
this._provider = new ethers.providers.JsonRpcProvider(rpcUrl)
this._wallet = new ethers.Wallet(this._privateKey, this._provider)
this.address = this._wallet.address
this._broadcastNodes = broadcastNodes
this._gasPriceOracle = new GasPriceOracle({ defaultRpc: rpcUrl })
this._gasPriceOracle = new GasPriceOracle({ defaultRpc: rpcUrl, ...gasPriceOracleConfig })
this._mutex = new Mutex()
this._nonce = null
}

View File

@@ -10,7 +10,7 @@ describe('TxManager', () => {
privateKey: PRIVATE_KEY,
rpcUrl: RPC_URL,
config: {
CONFIRMATIONS: 3,
CONFIRMATIONS: 1,
GAS_BUMP_INTERVAL: 1000 * 15,
},
})
@@ -101,5 +101,23 @@ describe('TxManager', () => {
console.log('receipt', receipt)
})
it.only('should send multiple txs', async () => {
const genTx = value => ({
value,
to: '0x0039F22efB07A647557C7C5d17854CFD6D489eF3',
})
await Promise.all([
manager.createTx(genTx(1)).send(),
manager.createTx(genTx(2)).send(),
manager.createTx(genTx(3)).send(),
manager.createTx(genTx(4)).send(),
manager.createTx(genTx(5)).send(),
manager.createTx(genTx(6)).send(),
manager.createTx(genTx(7)).send(),
manager.createTx(genTx(8)).send(),
manager.createTx(genTx(9)).send(),
manager.createTx(genTx(10)).send(),
])
})
})
})

View File

@@ -1141,10 +1141,10 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
gas-price-oracle@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.2.0.tgz#981926c96089497115113162b03151aacfe44a5a"
integrity sha512-2+mMyunV/pMJrmKl/IeEtX860NaE/bQ7H4D8PO2dc0OQd8ZAj/e4WJ+C9F/uOeG3dwm8SEFjofOvcYRHeGxo/Q==
gas-price-oracle@^0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.3.4.tgz#c98f6e24cf4bea96be2fe85383d53601b2ab5761"
integrity sha512-bba9zWd2hQ32AuPFDzL8E5QxAzXNfGKR1UZCa14fSYJWc9yo3k7wabITMkGEv0cbKpHmyK/kHhhDTBtugI6eAg==
dependencies:
axios "^0.19.2"
bignumber.js "^9.0.0"