aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/scripts/controllers/transactions/index.js2
-rw-r--r--app/scripts/controllers/transactions/nonce-tracker.js161
-rw-r--r--package-lock.json79
-rw-r--r--package.json1
-rw-r--r--test/unit/app/controllers/transactions/nonce-tracker-test.js238
5 files changed, 74 insertions, 407 deletions
diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js
index dd497a11e..1ae925835 100644
--- a/app/scripts/controllers/transactions/index.js
+++ b/app/scripts/controllers/transactions/index.js
@@ -17,7 +17,7 @@ const {
const TransactionStateManager = require('./tx-state-manager')
const TxGasUtil = require('./tx-gas-utils')
const PendingTransactionTracker = require('./pending-tx-tracker')
-const NonceTracker = require('./nonce-tracker')
+const NonceTracker = require('nonce-tracker')
const txUtils = require('./lib/util')
const cleanErrorStack = require('../../lib/cleanErrorStack')
const log = require('loglevel')
diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js
deleted file mode 100644
index 421036368..000000000
--- a/app/scripts/controllers/transactions/nonce-tracker.js
+++ /dev/null
@@ -1,161 +0,0 @@
-const EthQuery = require('ethjs-query')
-const assert = require('assert')
-const Mutex = require('await-semaphore').Mutex
-/**
- @param opts {Object}
- @param {Object} opts.provider a ethereum provider
- @param {Function} opts.getPendingTransactions a function that returns an array of txMeta
- whosee status is `submitted`
- @param {Function} opts.getConfirmedTransactions a function that returns an array of txMeta
- whose status is `confirmed`
- @class
-*/
-class NonceTracker {
-
- constructor ({ provider, blockTracker, getPendingTransactions, getConfirmedTransactions }) {
- this.provider = provider
- this.blockTracker = blockTracker
- this.ethQuery = new EthQuery(provider)
- this.getPendingTransactions = getPendingTransactions
- this.getConfirmedTransactions = getConfirmedTransactions
- this.lockMap = {}
- }
-
- /**
- @returns {Promise<Object>} with the key releaseLock (the gloabl mutex)
- */
- async getGlobalLock () {
- const globalMutex = this._lookupMutex('global')
- // await global mutex free
- const releaseLock = await globalMutex.acquire()
- return { releaseLock }
- }
-
- /**
- * @typedef NonceDetails
- * @property {number} highestLocallyConfirmed - A hex string of the highest nonce on a confirmed transaction.
- * @property {number} nextNetworkNonce - The next nonce suggested by the eth_getTransactionCount method.
- * @property {number} highestSuggested - The maximum between the other two, the number returned.
- */
-
- /**
- this will return an object with the `nextNonce` `nonceDetails` of type NonceDetails, and the releaseLock
- Note: releaseLock must be called after adding a signed tx to pending transactions (or discarding).
-
- @param address {string} the hex string for the address whose nonce we are calculating
- @returns {Promise<NonceDetails>}
- */
- async getNonceLock (address) {
- // await global mutex free
- await this._globalMutexFree()
- // await lock free, then take lock
- const releaseLock = await this._takeMutex(address)
- try {
- // evaluate multiple nextNonce strategies
- const nonceDetails = {}
- const networkNonceResult = await this._getNetworkNextNonce(address)
- const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address)
- const nextNetworkNonce = networkNonceResult.nonce
- const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed)
-
- const pendingTxs = this.getPendingTransactions(address)
- const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0
-
- nonceDetails.params = {
- highestLocallyConfirmed,
- highestSuggested,
- nextNetworkNonce,
- }
- nonceDetails.local = localNonceResult
- nonceDetails.network = networkNonceResult
-
- const nextNonce = Math.max(networkNonceResult.nonce, localNonceResult.nonce)
- assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`)
-
- // return nonce and release cb
- return { nextNonce, nonceDetails, releaseLock }
- } catch (err) {
- // release lock if we encounter an error
- releaseLock()
- throw err
- }
- }
-
- async _globalMutexFree () {
- const globalMutex = this._lookupMutex('global')
- const releaseLock = await globalMutex.acquire()
- releaseLock()
- }
-
- async _takeMutex (lockId) {
- const mutex = this._lookupMutex(lockId)
- const releaseLock = await mutex.acquire()
- return releaseLock
- }
-
- _lookupMutex (lockId) {
- let mutex = this.lockMap[lockId]
- if (!mutex) {
- mutex = new Mutex()
- this.lockMap[lockId] = mutex
- }
- return mutex
- }
-
- async _getNetworkNextNonce (address) {
- // calculate next nonce
- // we need to make sure our base count
- // and pending count are from the same block
- const blockNumber = await this.blockTracker.getLatestBlock()
- const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber)
- const baseCount = baseCountBN.toNumber()
- assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`)
- const nonceDetails = { blockNumber, baseCount }
- return { name: 'network', nonce: baseCount, details: nonceDetails }
- }
-
- _getHighestLocallyConfirmed (address) {
- const confirmedTransactions = this.getConfirmedTransactions(address)
- const highest = this._getHighestNonce(confirmedTransactions)
- return Number.isInteger(highest) ? highest + 1 : 0
- }
-
- _getHighestNonce (txList) {
- const nonces = txList.map((txMeta) => {
- const nonce = txMeta.txParams.nonce
- assert(typeof nonce, 'string', 'nonces should be hex strings')
- return parseInt(nonce, 16)
- })
- const highestNonce = Math.max.apply(null, nonces)
- return highestNonce
- }
-
- /**
- @typedef {object} highestContinuousFrom
- @property {string} - name the name for how the nonce was calculated based on the data used
- @property {number} - nonce the next suggested nonce
- @property {object} - details the provided starting nonce that was used (for debugging)
- */
- /**
- @param txList {array} - list of txMeta's
- @param startPoint {number} - the highest known locally confirmed nonce
- @returns {highestContinuousFrom}
- */
- _getHighestContinuousFrom (txList, startPoint) {
- const nonces = txList.map((txMeta) => {
- const nonce = txMeta.txParams.nonce
- assert(typeof nonce, 'string', 'nonces should be hex strings')
- return parseInt(nonce, 16)
- })
-
- let highest = startPoint
- while (nonces.includes(highest)) {
- highest++
- }
-
- return { name: 'local', nonce: highest, details: { startPoint, highest } }
- }
-
-}
-
-module.exports = NonceTracker
diff --git a/package-lock.json b/package-lock.json
index 8844b21a5..526420356 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8854,7 +8854,7 @@
},
"engine.io-client": {
"version": "3.2.1",
- "resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
"integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
"dev": true,
"requires": {
@@ -9473,7 +9473,7 @@
},
"inquirer": {
"version": "0.12.0",
- "resolved": "http://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
"integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
"dev": true,
"requires": {
@@ -9566,7 +9566,7 @@
},
"table": {
"version": "3.8.3",
- "resolved": "http://registry.npmjs.org/table/-/table-3.8.3.tgz",
+ "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
"integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
"dev": true,
"requires": {
@@ -10157,7 +10157,7 @@
"dependencies": {
"babelify": {
"version": "7.3.0",
- "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz",
+ "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz",
"integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=",
"dev": true,
"requires": {
@@ -15815,6 +15815,23 @@
"requires": {
"bn.js": "^4.11.8",
"ethereumjs-util": "^6.0.0"
+ },
+ "dependencies": {
+ "ethereumjs-util": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz",
+ "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.11.0",
+ "create-hash": "^1.1.2",
+ "ethjs-util": "0.1.6",
+ "keccak": "^1.0.2",
+ "rlp": "^2.0.0",
+ "safe-buffer": "^5.1.1",
+ "secp256k1": "^3.0.1"
+ }
+ }
}
},
"ethereumjs-block": {
@@ -19798,6 +19815,23 @@
"requires": {
"bn.js": "^4.11.8",
"ethereumjs-util": "^6.0.0"
+ },
+ "dependencies": {
+ "ethereumjs-util": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz",
+ "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.11.0",
+ "create-hash": "^1.1.2",
+ "ethjs-util": "0.1.6",
+ "keccak": "^1.0.2",
+ "rlp": "^2.0.0",
+ "safe-buffer": "^5.1.1",
+ "secp256k1": "^3.0.1"
+ }
+ }
}
},
"ethereumjs-block": {
@@ -20952,7 +20986,7 @@
},
"got": {
"version": "5.6.0",
- "resolved": "http://registry.npmjs.org/got/-/got-5.6.0.tgz",
+ "resolved": "https://registry.npmjs.org/got/-/got-5.6.0.tgz",
"integrity": "sha1-ux1+4WO3gIK7yOuDbz85UATqb78=",
"dev": true,
"requires": {
@@ -27909,6 +27943,37 @@
"underscore": "~1.4.4"
}
},
+ "nonce-tracker": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/nonce-tracker/-/nonce-tracker-1.0.0.tgz",
+ "integrity": "sha512-hxKokxgLvOZx9A5qPQKwL34G1/YwMC5xJWZHFUKfvwxypkn2nP0KVJjbcoXwY6pXsRRa11KdFEPW61N4YCGnWQ==",
+ "requires": {
+ "assert": "^1.4.1",
+ "await-semaphore": "^0.1.3",
+ "ethjs-query": "^0.3.8"
+ },
+ "dependencies": {
+ "ethjs-query": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.8.tgz",
+ "integrity": "sha512-/J5JydqrOzU8O7VBOwZKUWXxHDGr46VqNjBCJgBVNNda+tv7Xc8Y2uJc6aMHHVbeN3YOQ7YRElgIc0q1CI02lQ==",
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "ethjs-format": "0.2.7",
+ "ethjs-rpc": "0.2.0",
+ "promise-to-callback": "^1.0.0"
+ }
+ },
+ "ethjs-rpc": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.2.0.tgz",
+ "integrity": "sha512-RINulkNZTKnj4R/cjYYtYMnFFaBcVALzbtEJEONrrka8IeoarNB9Jbzn+2rT00Cv8y/CxAI+GgY1d0/i2iQeOg==",
+ "requires": {
+ "promise-to-callback": "^1.0.0"
+ }
+ }
+ }
+ },
"nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
@@ -30423,7 +30488,7 @@
},
"po2json": {
"version": "0.4.5",
- "resolved": "http://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz",
+ "resolved": "https://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz",
"integrity": "sha1-R7spUtoy1Yob4vJWpZjuvAt0URg=",
"dev": true,
"requires": {
@@ -35856,7 +35921,7 @@
},
"socket.io-parser": {
"version": "3.2.0",
- "resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
"integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
"dev": true,
"requires": {
diff --git a/package.json b/package.json
index 0ae402600..89e0388d4 100644
--- a/package.json
+++ b/package.json
@@ -133,6 +133,7 @@
"mkdirp": "^0.5.1",
"multihashes": "^0.4.12",
"multiplex": "^6.7.0",
+ "nonce-tracker": "^1.0.0",
"number-to-bn": "^1.7.0",
"obj-multiplex": "^1.0.0",
"obs-store": "^3.0.2",
diff --git a/test/unit/app/controllers/transactions/nonce-tracker-test.js b/test/unit/app/controllers/transactions/nonce-tracker-test.js
deleted file mode 100644
index 51ac390e9..000000000
--- a/test/unit/app/controllers/transactions/nonce-tracker-test.js
+++ /dev/null
@@ -1,238 +0,0 @@
-const assert = require('assert')
-const NonceTracker = require('../../../../../app/scripts/controllers/transactions/nonce-tracker')
-const MockTxGen = require('../../../../lib/mock-tx-gen')
-const providerResultStub = {}
-
-describe('Nonce Tracker', function () {
- let nonceTracker, pendingTxs, confirmedTxs
-
- describe('#getNonceLock', function () {
-
- describe('with 3 confirmed and 1 pending', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 })
- pendingTxs = txGen.generate({ status: 'submitted' }, { count: 1 })
- nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x1')
- })
-
- it('should return 4', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '4', `nonce should be 4 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
-
- it('should use localNonce if network returns a nonce lower then a confirmed tx in state', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '4', 'nonce should be 4')
- await nonceLock.releaseLock()
- })
- })
-
- describe('sentry issue 476304902', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- pendingTxs = txGen.generate({ status: 'submitted' }, {
- fromNonce: 3,
- count: 29,
- })
- nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x3')
- })
-
- it('should return 9', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '32', `nonce should be 32 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('issue 3670', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- pendingTxs = txGen.generate({ status: 'submitted' }, {
- fromNonce: 6,
- count: 3,
- })
- nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x6')
- })
-
- it('should return 9', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '9', `nonce should be 9 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('with no previous txs', function () {
- beforeEach(function () {
- nonceTracker = generateNonceTrackerWith([], [])
- })
-
- it('should return 0', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 returned ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('with multiple previous txs with same nonce', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 1 })
- pendingTxs = txGen.generate({
- status: 'submitted',
- txParams: { nonce: '0x01' },
- }, { count: 5 })
-
- nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x0')
- })
-
- it('should return nonce after those', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('when local confirmed count is higher than network nonce', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 })
- nonceTracker = generateNonceTrackerWith([], confirmedTxs, '0x1')
- })
-
- it('should return nonce after those', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '3', `nonce should be 3 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('when local pending count is higher than other metrics', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 })
- nonceTracker = generateNonceTrackerWith(pendingTxs, [])
- })
-
- it('should return nonce after those', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('when provider nonce is higher than other metrics', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 })
- nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x05')
- })
-
- it('should return nonce after those', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('when there are some pending nonces below the remote one and some over.', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 })
- nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x03')
- })
-
- it('should return nonce after those', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('when there are pending nonces non sequentially over the network nonce.', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- txGen.generate({ status: 'submitted' }, { count: 5 })
- // 5 over that number
- pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 })
- nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x00')
- })
-
- it('should return nonce after network nonce', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('When all three return different values', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 })
- pendingTxs = txGen.generate({
- status: 'submitted',
- nonce: 100,
- }, { count: 1 })
- // 0x32 is 50 in hex:
- nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x32')
- })
-
- it('should return nonce after network nonce', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '50', `nonce should be 50 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
-
- describe('Faq issue 67', function () {
- beforeEach(function () {
- const txGen = new MockTxGen()
- confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 })
- pendingTxs = txGen.generate({
- status: 'submitted',
- }, { count: 10 })
- // 0x40 is 64 in hex:
- nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x40')
- })
-
- it('should return nonce after network nonce', async function () {
- this.timeout(15000)
- const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926')
- assert.equal(nonceLock.nextNonce, '74', `nonce should be 74 got ${nonceLock.nextNonce}`)
- await nonceLock.releaseLock()
- })
- })
- })
-})
-
-function generateNonceTrackerWith (pending, confirmed, providerStub = '0x0') {
- const getPendingTransactions = () => pending
- const getConfirmedTransactions = () => confirmed
- providerResultStub.result = providerStub
- const provider = {
- sendAsync: (_, cb) => { cb(undefined, providerResultStub) },
- }
- const blockTracker = {
- getCurrentBlock: () => '0x11b568',
- getLatestBlock: async () => '0x11b568',
- }
- return new NonceTracker({
- provider,
- blockTracker,
- getPendingTransactions,
- getConfirmedTransactions,
- })
-}