mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
controllers - transactions - merge @frankiebee's work with mine
This commit is contained in:
parent
9f8d5f0547
commit
5be154ea20
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,6 +9,7 @@ package
|
|||||||
# IDEs
|
# IDEs
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
|
.sublime-project
|
||||||
|
|
||||||
temp
|
temp
|
||||||
.tmp
|
.tmp
|
||||||
@ -37,4 +38,4 @@ ui/app/css/output/
|
|||||||
notes.txt
|
notes.txt
|
||||||
|
|
||||||
.coveralls.yml
|
.coveralls.yml
|
||||||
.nyc_output
|
.nyc_output
|
@ -78,7 +78,7 @@ class TransactionController extends EventEmitter {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.txStateManager.store.subscribe(() => this.emit('update:badge'))
|
this.txStateManager.store.subscribe(() => this.emit('update:badge'))
|
||||||
this._setupListners()
|
this._setupListeners()
|
||||||
// memstore is computed from a few different stores
|
// memstore is computed from a few different stores
|
||||||
this._updateMemstore()
|
this._updateMemstore()
|
||||||
this.txStateManager.store.subscribe(() => this._updateMemstore())
|
this.txStateManager.store.subscribe(() => this._updateMemstore())
|
||||||
@ -382,8 +382,9 @@ class TransactionController extends EventEmitter {
|
|||||||
is called in constructor applies the listeners for pendingTxTracker txStateManager
|
is called in constructor applies the listeners for pendingTxTracker txStateManager
|
||||||
and blockTracker
|
and blockTracker
|
||||||
*/
|
*/
|
||||||
_setupListners () {
|
_setupListeners () {
|
||||||
this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
|
this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
|
||||||
|
this._setupBlockTrackerListener()
|
||||||
this.pendingTxTracker.on('tx:warning', (txMeta) => {
|
this.pendingTxTracker.on('tx:warning', (txMeta) => {
|
||||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
|
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
|
||||||
})
|
})
|
||||||
@ -399,13 +400,6 @@ class TransactionController extends EventEmitter {
|
|||||||
txMeta.retryCount++
|
txMeta.retryCount++
|
||||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
|
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
|
||||||
})
|
})
|
||||||
|
|
||||||
this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker))
|
|
||||||
// this is a little messy but until ethstore has been either
|
|
||||||
// removed or redone this is to guard against the race condition
|
|
||||||
this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker))
|
|
||||||
this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -429,6 +423,40 @@ class TransactionController extends EventEmitter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setupBlockTrackerListener () {
|
||||||
|
let listenersAreActive = false
|
||||||
|
const latestBlockHandler = this._onLatestBlock.bind(this)
|
||||||
|
const blockTracker = this.blockTracker
|
||||||
|
const txStateManager = this.txStateManager
|
||||||
|
|
||||||
|
txStateManager.on('tx:status-update', updateSubscription)
|
||||||
|
updateSubscription()
|
||||||
|
|
||||||
|
function updateSubscription() {
|
||||||
|
const pendingTxs = txStateManager.getPendingTransactions()
|
||||||
|
if (!listenersAreActive && pendingTxs.length > 0) {
|
||||||
|
blockTracker.on('latest', latestBlockHandler)
|
||||||
|
listenersAreActive = true
|
||||||
|
} else if (listenersAreActive && !pendingTxs.length) {
|
||||||
|
blockTracker.removeListener('latest', latestBlockHandler)
|
||||||
|
listenersAreActive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onLatestBlock (blockNumber) {
|
||||||
|
try {
|
||||||
|
await this.pendingTxTracker.updatePendingTxs()
|
||||||
|
} catch (err) {
|
||||||
|
log.error(err)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.pendingTxTracker.resubmitPendingTxs(blockNumber)
|
||||||
|
} catch (err) {
|
||||||
|
log.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Updates the memStore in transaction controller
|
Updates the memStore in transaction controller
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +35,7 @@ class NonceTracker {
|
|||||||
* @typedef NonceDetails
|
* @typedef NonceDetails
|
||||||
* @property {number} highestLocallyConfirmed - A hex string of the highest nonce on a confirmed transaction.
|
* @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} nextNetworkNonce - The next nonce suggested by the eth_getTransactionCount method.
|
||||||
* @property {number} highetSuggested - The maximum between the other two, the number returned.
|
* @property {number} highestSuggested - The maximum between the other two, the number returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,14 +75,6 @@ class NonceTracker {
|
|||||||
return { nextNonce, nonceDetails, releaseLock }
|
return { nextNonce, nonceDetails, releaseLock }
|
||||||
}
|
}
|
||||||
|
|
||||||
async _getCurrentBlock () {
|
|
||||||
const currentBlock = this.blockTracker.getCurrentBlock()
|
|
||||||
if (currentBlock) return currentBlock
|
|
||||||
return await new Promise((reject, resolve) => {
|
|
||||||
this.blockTracker.once('latest', resolve)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async _globalMutexFree () {
|
async _globalMutexFree () {
|
||||||
const globalMutex = this._lookupMutex('global')
|
const globalMutex = this._lookupMutex('global')
|
||||||
const release = await globalMutex.acquire()
|
const release = await globalMutex.acquire()
|
||||||
@ -108,9 +100,8 @@ class NonceTracker {
|
|||||||
// calculate next nonce
|
// calculate next nonce
|
||||||
// we need to make sure our base count
|
// we need to make sure our base count
|
||||||
// and pending count are from the same block
|
// and pending count are from the same block
|
||||||
const currentBlock = await this._getCurrentBlock()
|
const blockNumber = await this.blockTracker.getLatestBlock()
|
||||||
const blockNumber = currentBlock.blockNumber
|
const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber)
|
||||||
const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber || 'latest')
|
|
||||||
const baseCount = baseCountBN.toNumber()
|
const baseCount = baseCountBN.toNumber()
|
||||||
assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`)
|
assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`)
|
||||||
const nonceDetails = { blockNumber, baseCount }
|
const nonceDetails = { blockNumber, baseCount }
|
||||||
@ -171,6 +162,7 @@ class NonceTracker {
|
|||||||
|
|
||||||
return { name: 'local', nonce: highest, details: { startPoint, highest } }
|
return { name: 'local', nonce: highest, details: { startPoint, highest } }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = NonceTracker
|
module.exports = NonceTracker
|
||||||
|
@ -24,60 +24,27 @@ class PendingTransactionTracker extends EventEmitter {
|
|||||||
super()
|
super()
|
||||||
this.query = new EthQuery(config.provider)
|
this.query = new EthQuery(config.provider)
|
||||||
this.nonceTracker = config.nonceTracker
|
this.nonceTracker = config.nonceTracker
|
||||||
// default is one day
|
|
||||||
this.getPendingTransactions = config.getPendingTransactions
|
this.getPendingTransactions = config.getPendingTransactions
|
||||||
this.getCompletedTransactions = config.getCompletedTransactions
|
this.getCompletedTransactions = config.getCompletedTransactions
|
||||||
this.publishTransaction = config.publishTransaction
|
this.publishTransaction = config.publishTransaction
|
||||||
this.confirmTransaction = config.confirmTransaction
|
this.confirmTransaction = config.confirmTransaction
|
||||||
this._checkPendingTxs()
|
this.updatePendingTxs()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
checks if a signed tx is in a block and
|
checks the network for signed txs and releases the nonce global lock if it is
|
||||||
if it is included emits tx status as 'confirmed'
|
|
||||||
@param block {object}, a full block
|
|
||||||
@emits tx:confirmed
|
|
||||||
@emits tx:failed
|
|
||||||
*/
|
*/
|
||||||
async checkForTxInBlock (blockNumber) {
|
async updatePendingTxs () {
|
||||||
const block = await this._getBlock(blockNumber)
|
const pendingTxs = this.getPendingTransactions()
|
||||||
const signedTxList = this.getPendingTransactions()
|
// in order to keep the nonceTracker accurate we block it while updating pending transactions
|
||||||
if (!signedTxList.length) return
|
const nonceGlobalLock = await this.nonceTracker.getGlobalLock()
|
||||||
signedTxList.forEach((txMeta) => {
|
try {
|
||||||
const txHash = txMeta.hash
|
await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta)))
|
||||||
const txId = txMeta.id
|
} catch (err) {
|
||||||
|
log.error('PendingTransactionTracker - Error updating pending transactions')
|
||||||
if (!txHash) {
|
log.error(err)
|
||||||
const noTxHashErr = new Error('We had an error while submitting this transaction, please try again.')
|
|
||||||
noTxHashErr.name = 'NoTxHashError'
|
|
||||||
this.emit('tx:failed', txId, noTxHashErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!block.transactions.length) return
|
|
||||||
|
|
||||||
block.transactions.forEach((hash) => {
|
|
||||||
if (hash === txHash) {
|
|
||||||
this.confirmTransaction(txId)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
asks the network for the transaction to see if a block number is included on it
|
|
||||||
if we have skipped/missed blocks
|
|
||||||
@param object - oldBlock newBlock
|
|
||||||
*/
|
|
||||||
queryPendingTxs ({ oldBlock, newBlock }) {
|
|
||||||
// check pending transactions on start
|
|
||||||
if (!oldBlock) {
|
|
||||||
this._checkPendingTxs()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
// if we synced by more than one block, check for missed pending transactions
|
nonceGlobalLock.releaseLock()
|
||||||
const diff = Number.parseInt(newBlock, 16) - Number.parseInt(oldBlock, 16)
|
|
||||||
if (diff > 1) this._checkPendingTxs()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,6 +118,7 @@ class PendingTransactionTracker extends EventEmitter {
|
|||||||
this.emit('tx:retry', txMeta)
|
this.emit('tx:retry', txMeta)
|
||||||
return txHash
|
return txHash
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Ask the network for the transaction to see if it has been include in a block
|
Ask the network for the transaction to see if it has been include in a block
|
||||||
@param txMeta {Object} - the txMeta object
|
@param txMeta {Object} - the txMeta object
|
||||||
@ -180,9 +148,8 @@ class PendingTransactionTracker extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get latest transaction status
|
// get latest transaction status
|
||||||
let txParams
|
|
||||||
try {
|
try {
|
||||||
txParams = await this.query.getTransactionByHash(txHash)
|
const txParams = await this.query.getTransactionByHash(txHash)
|
||||||
if (!txParams) return
|
if (!txParams) return
|
||||||
if (txParams.blockNumber) {
|
if (txParams.blockNumber) {
|
||||||
this.confirmTransaction(txId)
|
this.confirmTransaction(txId)
|
||||||
@ -196,34 +163,6 @@ class PendingTransactionTracker extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
checks the network for signed txs and releases the nonce global lock if it is
|
|
||||||
*/
|
|
||||||
async _checkPendingTxs () {
|
|
||||||
const signedTxList = this.getPendingTransactions()
|
|
||||||
// in order to keep the nonceTracker accurate we block it while updating pending transactions
|
|
||||||
const nonceGlobalLock = await this.nonceTracker.getGlobalLock()
|
|
||||||
try {
|
|
||||||
await Promise.all(signedTxList.map((txMeta) => this._checkPendingTx(txMeta)))
|
|
||||||
} catch (err) {
|
|
||||||
log.error('PendingTransactionWatcher - Error updating pending transactions')
|
|
||||||
log.error(err)
|
|
||||||
}
|
|
||||||
nonceGlobalLock.releaseLock()
|
|
||||||
}
|
|
||||||
|
|
||||||
async _getBlock (blockNumber) {
|
|
||||||
let block
|
|
||||||
while (!block) {
|
|
||||||
// block requests will sometimes return null due do the infura api
|
|
||||||
// being backed by multiple out-of-sync clients
|
|
||||||
block = await this.query.getBlockByNumber(blockNumber, false)
|
|
||||||
// if block is null, wait 1 sec then try again
|
|
||||||
if (!block) await timeout(1000)
|
|
||||||
}
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
checks to see if a confirmed txMeta has the same nonce
|
checks to see if a confirmed txMeta has the same nonce
|
||||||
@param txMeta {Object} - txMeta object
|
@param txMeta {Object} - txMeta object
|
||||||
|
@ -99,7 +99,21 @@ function BnMultiplyByFraction (targetBN, numerator, denominator) {
|
|||||||
return targetBN.mul(numBN).div(denomBN)
|
return targetBN.mul(numBN).div(denomBN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyListeners (listeners, emitter) {
|
||||||
|
Object.keys(listeners).forEach((key) => {
|
||||||
|
emitter.on(key, listeners[key])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeListeners (listeners, emitter) {
|
||||||
|
Object.keys(listeners).forEach((key) => {
|
||||||
|
emitter.removeListener(key, listeners[key])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
removeListeners,
|
||||||
|
applyListeners,
|
||||||
getStack,
|
getStack,
|
||||||
getEnvironmentType,
|
getEnvironmentType,
|
||||||
sufficientBalance,
|
sufficientBalance,
|
||||||
|
@ -7,7 +7,7 @@ const { createTestProviderTools } = require('../../../../stub/provider')
|
|||||||
const PendingTransactionTracker = require('../../../../../app/scripts/controllers/transactions/pending-tx-tracker')
|
const PendingTransactionTracker = require('../../../../../app/scripts/controllers/transactions/pending-tx-tracker')
|
||||||
const MockTxGen = require('../../../../lib/mock-tx-gen')
|
const MockTxGen = require('../../../../lib/mock-tx-gen')
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
const noop = () => true
|
const noop =()=>true
|
||||||
const currentNetworkId = 42
|
const currentNetworkId = 42
|
||||||
const otherNetworkId = 36
|
const otherNetworkId = 36
|
||||||
const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex')
|
const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex')
|
||||||
@ -108,56 +108,6 @@ describe('PendingTransactionTracker', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#checkForTxInBlock', function () {
|
|
||||||
it('should return if no pending transactions', function () {
|
|
||||||
// throw a type error if it trys to do anything on the block
|
|
||||||
// thus failing the test
|
|
||||||
const block = Proxy.revocable({}, {}).revoke()
|
|
||||||
pendingTxTracker.checkForTxInBlock(block)
|
|
||||||
})
|
|
||||||
it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) {
|
|
||||||
const block = Proxy.revocable({}, {}).revoke()
|
|
||||||
pendingTxTracker.getPendingTransactions = () => [txMetaNoHash]
|
|
||||||
pendingTxTracker.once('tx:failed', (txId, err) => {
|
|
||||||
assert(txId, txMetaNoHash.id, 'should pass txId')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
pendingTxTracker.checkForTxInBlock(block)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('#queryPendingTxs', function () {
|
|
||||||
it('should call #_checkPendingTxs if their is no oldBlock', function (done) {
|
|
||||||
let newBlock, oldBlock
|
|
||||||
newBlock = '0x01'
|
|
||||||
const originalFunction = pendingTxTracker._checkPendingTxs
|
|
||||||
pendingTxTracker._checkPendingTxs = () => { done() }
|
|
||||||
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
|
|
||||||
pendingTxTracker._checkPendingTxs = originalFunction
|
|
||||||
})
|
|
||||||
it('should call #_checkPendingTxs if oldBlock and the newBlock have a diff of greater then 1', function (done) {
|
|
||||||
let newBlock, oldBlock
|
|
||||||
oldBlock = '0x01'
|
|
||||||
newBlock = '0x03'
|
|
||||||
const originalFunction = pendingTxTracker._checkPendingTxs
|
|
||||||
pendingTxTracker._checkPendingTxs = () => { done() }
|
|
||||||
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
|
|
||||||
pendingTxTracker._checkPendingTxs = originalFunction
|
|
||||||
})
|
|
||||||
it('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less', function (done) {
|
|
||||||
let newBlock, oldBlock
|
|
||||||
oldBlock = '0x1'
|
|
||||||
newBlock = '0x2'
|
|
||||||
const originalFunction = pendingTxTracker._checkPendingTxs
|
|
||||||
pendingTxTracker._checkPendingTxs = () => {
|
|
||||||
const err = new Error('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less')
|
|
||||||
done(err)
|
|
||||||
}
|
|
||||||
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
|
|
||||||
pendingTxTracker._checkPendingTxs = originalFunction
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#_checkPendingTx', function () {
|
describe('#_checkPendingTx', function () {
|
||||||
it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) {
|
it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) {
|
||||||
pendingTxTracker.once('tx:failed', (txId, err) => {
|
pendingTxTracker.once('tx:failed', (txId, err) => {
|
||||||
@ -187,7 +137,6 @@ describe('PendingTransactionTracker', function () {
|
|||||||
it('should warp all txMeta\'s in #_checkPendingTx', function (done) {
|
it('should warp all txMeta\'s in #_checkPendingTx', function (done) {
|
||||||
pendingTxTracker.getPendingTransactions = () => txList
|
pendingTxTracker.getPendingTransactions = () => txList
|
||||||
pendingTxTracker._checkPendingTx = (tx) => { tx.resolve(tx) }
|
pendingTxTracker._checkPendingTx = (tx) => { tx.resolve(tx) }
|
||||||
const list = txList.map
|
|
||||||
Promise.all(txList.map((tx) => tx.processed))
|
Promise.all(txList.map((tx) => tx.processed))
|
||||||
.then((txCompletedList) => done())
|
.then((txCompletedList) => done())
|
||||||
.catch(done)
|
.catch(done)
|
||||||
@ -201,7 +150,7 @@ describe('PendingTransactionTracker', function () {
|
|||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
const txMeta2 = txMeta3 = txMeta
|
const txMeta2 = txMeta3 = txMeta
|
||||||
txList = [txMeta, txMeta2, txMeta3].map((tx) => {
|
txList = [txMeta, txMeta2, txMeta3].map((tx) => {
|
||||||
tx.processed = new Promise ((resolve) => { tx.resolve = resolve })
|
tx.processed = new Promise((resolve) => { tx.resolve = resolve })
|
||||||
return tx
|
return tx
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -218,7 +167,7 @@ describe('PendingTransactionTracker', function () {
|
|||||||
pendingTxTracker.resubmitPendingTxs(blockNuberStub)
|
pendingTxTracker.resubmitPendingTxs(blockNuberStub)
|
||||||
})
|
})
|
||||||
it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) {
|
it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) {
|
||||||
knownErrors =[
|
knownErrors = [
|
||||||
// geth
|
// geth
|
||||||
' Replacement transaction Underpriced ',
|
' Replacement transaction Underpriced ',
|
||||||
' known transaction',
|
' known transaction',
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
|
const EventEmitter = require('events')
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const EthTx = require('ethereumjs-tx')
|
const EthTx = require('ethereumjs-tx')
|
||||||
const EthjsQuery = require('ethjs-query')
|
const EthjsQuery = require('ethjs-query')
|
||||||
@ -26,12 +27,13 @@ describe('Transaction Controller', function () {
|
|||||||
provider = createTestProviderTools({ scaffold: providerResultStub }).provider
|
provider = createTestProviderTools({ scaffold: providerResultStub }).provider
|
||||||
query = new EthjsQuery(provider)
|
query = new EthjsQuery(provider)
|
||||||
fromAccount = getTestAccounts()[0]
|
fromAccount = getTestAccounts()[0]
|
||||||
|
const blockTrackerStub = new EventEmitter()
|
||||||
|
blockTrackerStub.getCurrentBlock = noop
|
||||||
txController = new TransactionController({
|
txController = new TransactionController({
|
||||||
provider,
|
provider,
|
||||||
networkStore: new ObservableStore(currentNetworkId),
|
networkStore: new ObservableStore(currentNetworkId),
|
||||||
txHistoryLimit: 10,
|
txHistoryLimit: 10,
|
||||||
blockTracker: { getCurrentBlock: noop, on: noop, once: noop },
|
blockTracker: blockTrackerStub,
|
||||||
signTransaction: (ethTx) => new Promise((resolve) => {
|
signTransaction: (ethTx) => new Promise((resolve) => {
|
||||||
ethTx.sign(fromAccount.key)
|
ethTx.sign(fromAccount.key)
|
||||||
resolve()
|
resolve()
|
||||||
|
Loading…
Reference in New Issue
Block a user