diff options
-rw-r--r-- | app/scripts/controllers/transactions.js | 335 | ||||
-rw-r--r-- | app/scripts/lib/tx-gas-utils.js (renamed from app/scripts/lib/tx-utils.js) | 21 | ||||
-rw-r--r-- | app/scripts/lib/tx-state-manager.js | 221 | ||||
-rw-r--r-- | app/scripts/metamask-controller.js | 2 | ||||
-rw-r--r-- | test/unit/tx-controller-test.js | 238 | ||||
-rw-r--r-- | test/unit/tx-state-manager-test.js | 241 | ||||
-rw-r--r-- | test/unit/tx-utils-test.js | 6 |
7 files changed, 571 insertions, 493 deletions
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index fb3be6073..3f2a7ce16 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -2,35 +2,57 @@ const EventEmitter = require('events') const extend = require('xtend') const ObservableStore = require('obs-store') const ethUtil = require('ethereumjs-util') +const Transaction = require('ethereumjs-tx') const EthQuery = require('ethjs-query') -const TxProviderUtil = require('../lib/tx-utils') +const TransactionStateManger = require('../lib/tx-state-manager') +const TxGasUtil = require('../lib/tx-gas-utils') const PendingTransactionTracker = require('../lib/pending-tx-tracker') const createId = require('../lib/random-id') const NonceTracker = require('../lib/nonce-tracker') -const txStateHistoryHelper = require('../lib/tx-state-history-helper') + +/* + Transaction Controller is an aggregate of sub-controllers and trackers + composing them in a way to be exposed to the metamask controller + - txStateManager + responsible for the state of a transaction and + storing the transaction + - pendingTxTracker + watching blocks for transactions to be include + and emitting confirmed events + - txGasUtil + gas calculations and safety buffering + - nonceTracker + calculating nonces +*/ module.exports = class TransactionController extends EventEmitter { constructor (opts) { super() - this.store = new ObservableStore(extend({ - transactions: [], - }, opts.initState)) - this.memStore = new ObservableStore({}) this.networkStore = opts.networkStore || new ObservableStore({}) this.preferencesStore = opts.preferencesStore || new ObservableStore({}) - this.txHistoryLimit = opts.txHistoryLimit this.provider = opts.provider this.blockTracker = opts.blockTracker this.signEthTx = opts.signTransaction this.ethStore = opts.ethStore + this.memStore = new ObservableStore({}) + this.query = new EthQuery(this.provider) + this.txGasUtil = new TxGasUtil(this.provider) + + this.txStateManager = new TransactionStateManger({ + initState: extend({ + transactions: [], + }, opts.initState), + txHistoryLimit: opts.txHistoryLimit, + getNetwork: this.getNetwork.bind(this), + }) + this.nonceTracker = new NonceTracker({ provider: this.provider, getPendingTransactions: (address) => { - return this.getFilteredTxList({ + return this.txStateManager.getFilteredTxList({ from: address, status: 'submitted', - err: undefined, }) }, getConfirmedTransactions: (address) => { @@ -45,8 +67,6 @@ module.exports = class TransactionController extends EventEmitter { this.setTxStatusFailed(txId, msg) }, }) - this.query = new EthQuery(this.provider) - this.txProviderUtil = new TxProviderUtil(this.provider) this.pendingTxTracker = new PendingTransactionTracker({ provider: this.provider, @@ -56,19 +76,20 @@ module.exports = class TransactionController extends EventEmitter { if (!account) return return account.balance }, - publishTransaction: this.txProviderUtil.publishTransaction.bind(this.txProviderUtil), + publishTransaction: this.query.sendRawTransaction, getPendingTransactions: () => { - const network = this.getNetwork() - return this.getFilteredTxList({ - status: 'submitted', - metamaskNetworkId: network, - }) + return this.txStateManager.getFilteredTxList({ status: 'submitted' }) }, }) - this.pendingTxTracker.on('txWarning', this.updateTx.bind(this)) - this.pendingTxTracker.on('txFailed', this.setTxStatusFailed.bind(this)) - this.pendingTxTracker.on('txConfirmed', this.setTxStatusConfirmed.bind(this)) + this.txStateManager.subscribe(() => { + this.emit('update') + this.emit('updateBadge') + }) + + this.pendingTxTracker.on('txWarning', this.txStateManager.updateTx.bind(this.txStateManager)) + this.pendingTxTracker.on('txFailed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) + this.pendingTxTracker.on('txConfirmed', this.txStateManager.setTxStatusConfirmed.bind(this.txStateManager)) this.blockTracker.on('rawBlock', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker)) // this is a little messy but until ethstore has been either @@ -80,7 +101,7 @@ module.exports = class TransactionController extends EventEmitter { this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker)) // memstore is computed from a few different stores this._updateMemstore() - this.store.subscribe(() => this._updateMemstore()) + this.txStateManager.subscribe(() => this._updateMemstore()) this.networkStore.subscribe(() => this._updateMemstore()) this.preferencesStore.subscribe(() => this._updateMemstore()) } @@ -97,98 +118,27 @@ module.exports = class TransactionController extends EventEmitter { return this.preferencesStore.getState().selectedAddress } - // Returns the number of txs for the current network. - getTxCount () { - return this.getTxList().length - } - - // Returns the full tx list across all networks - getFullTxList () { - return this.store.getState().transactions - } - getUnapprovedTxCount () { - return Object.keys(this.getUnapprovedTxList()).length + return Object.keys(this.txStateManager.getUnapprovedTxList()).length } getPendingTxCount () { - return this.getTxsByMetaData('status', 'signed').length - } - - // Returns the tx list - getTxList () { - const network = this.getNetwork() - const fullTxList = this.getFullTxList() - return this.getTxsByMetaData('metamaskNetworkId', network, fullTxList) + return this.txStateManager.getTxsByMetaData('status', 'signed').length } - // gets tx by Id and returns it - getTx (txId) { - const txList = this.getTxList() - const txMeta = txList.find(txData => txData.id === txId) - return txMeta - } - getUnapprovedTxList () { - const txList = this.getTxList() - return txList.filter((txMeta) => txMeta.status === 'unapproved') - .reduce((result, tx) => { - result[tx.id] = tx - return result - }, {}) - } - - updateTx (txMeta) { - // create txMeta snapshot for history - const currentState = txStateHistoryHelper.snapshotFromTxMeta(txMeta) - // recover previous tx state obj - const previousState = txStateHistoryHelper.replayHistory(txMeta.history) - // generate history entry and add to history - const entry = txStateHistoryHelper.generateHistoryEntry(previousState, currentState) - txMeta.history.push(entry) - - // commit txMeta to state - const txId = txMeta.id - const txList = this.getFullTxList() - const index = txList.findIndex(txData => txData.id === txId) - txList[index] = txMeta - this._saveTxList(txList) - this.emit('update') + getChainId () { + const networkState = this.networkStore.getState() + const getChainId = parseInt(networkState) + if (Number.isNaN(getChainId)) { + return 0 + } else { + return getChainId + } } // Adds a tx to the txlist addTx (txMeta) { - // initialize history - txMeta.history = [] - // capture initial snapshot of txMeta for history - const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta) - txMeta.history.push(snapshot) - - // checks if the length of the tx history is - // longer then desired persistence limit - // and then if it is removes only confirmed - // or rejected tx's. - // not tx's that are pending or unapproved - const txCount = this.getTxCount() - const network = this.getNetwork() - const fullTxList = this.getFullTxList() - const txHistoryLimit = this.txHistoryLimit - - if (txCount > txHistoryLimit - 1) { - const index = fullTxList.findIndex((metaTx) => ((metaTx.status === 'confirmed' || metaTx.status === 'rejected') && network === txMeta.metamaskNetworkId)) - fullTxList.splice(index, 1) - } - fullTxList.push(txMeta) - this._saveTxList(fullTxList) - this.emit('update') - - this.once(`${txMeta.id}:signed`, function (txId) { - this.removeAllListeners(`${txMeta.id}:rejected`) - }) - this.once(`${txMeta.id}:rejected`, function (txId) { - this.removeAllListeners(`${txMeta.id}:signed`) - }) - - this.emit('updateBadge') + this.txStateManager.addTx(txMeta) this.emit(`${txMeta.id}:unapproved`, txMeta) } @@ -198,7 +148,7 @@ module.exports = class TransactionController extends EventEmitter { this.emit('newUnaprovedTx', txMeta) // listen for tx completion (success, fail) return new Promise((resolve, reject) => { - this.once(`${txMeta.id}:finished`, (completedTx) => { + this.txStateManager.once(`${txMeta.id}:finished`, (completedTx) => { switch (completedTx.status) { case 'submitted': return resolve(completedTx.hash) @@ -213,7 +163,7 @@ module.exports = class TransactionController extends EventEmitter { async addUnapprovedTransaction (txParams) { // validate - await this.txProviderUtil.validateTxParams(txParams) + await this.txGasUtil.validateTxParams(txParams) // construct txMeta const txMeta = { id: createId(), @@ -232,17 +182,15 @@ module.exports = class TransactionController extends EventEmitter { async addTxDefaults (txMeta) { const txParams = txMeta.txParams // ensure value + const gasPrice = txParams.gasPrice || await this.query.gasPrice() txParams.value = txParams.value || '0x0' - if (!txParams.gasPrice) { - const gasPrice = await this.query.gasPrice() - txParams.gasPrice = gasPrice - } + txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) // set gasLimit - return await this.txProviderUtil.analyzeGasUsage(txMeta) + return await this.txGasUtil.analyzeGasUsage(txMeta) } async updateAndApproveTransaction (txMeta) { - this.updateTx(txMeta) + this.txStateManager.updateTx(txMeta) await this.approveTransaction(txMeta.id) } @@ -250,9 +198,9 @@ module.exports = class TransactionController extends EventEmitter { let nonceLock try { // approve - this.setTxStatusApproved(txId) + this.txStateManager.setTxStatusApproved(txId) // get next nonce - const txMeta = this.getTx(txId) + const txMeta = this.txStateManager.getTx(txId) const fromAddress = txMeta.txParams.from // wait for a nonce nonceLock = await this.nonceTracker.getNonceLock(fromAddress) @@ -260,14 +208,14 @@ module.exports = class TransactionController extends EventEmitter { txMeta.txParams.nonce = nonceLock.nextNonce // add nonce debugging information to txMeta txMeta.nonceDetails = nonceLock.nonceDetails - this.updateTx(txMeta) + this.txStateManager.updateTx(txMeta) // sign transaction const rawTx = await this.signTransaction(txId) await this.publishTransaction(txId, rawTx) // must set transaction to submitted/failed before releasing lock nonceLock.releaseLock() } catch (err) { - this.setTxStatusFailed(txId, err) + this.txStateManager.setTxStatusFailed(txId, err) // must set transaction to submitted/failed before releasing lock if (nonceLock) nonceLock.releaseLock() // continue with error chain @@ -276,142 +224,37 @@ module.exports = class TransactionController extends EventEmitter { } async signTransaction (txId) { - const txMeta = this.getTx(txId) + const txMeta = this.txStateManager.getTx(txId) const txParams = txMeta.txParams const fromAddress = txParams.from // add network/chain id txParams.chainId = this.getChainId() - const ethTx = this.txProviderUtil.buildEthTxFromParams(txParams) + const ethTx = new Transaction(txParams) await this.signEthTx(ethTx, fromAddress) - this.setTxStatusSigned(txMeta.id) + this.txStateManager.setTxStatusSigned(txMeta.id) const rawTx = ethUtil.bufferToHex(ethTx.serialize()) return rawTx } async publishTransaction (txId, rawTx) { - const txMeta = this.getTx(txId) + const txMeta = this.txStateManager.getTx(txId) txMeta.rawTx = rawTx - this.updateTx(txMeta) - const txHash = await this.txProviderUtil.publishTransaction(rawTx) + this.txStateManager.updateTx(txMeta) + const txHash = await this.query.sendRawTransaction(rawTx) this.setTxHash(txId, txHash) - this.setTxStatusSubmitted(txId) + this.txStateManager.setTxStatusSubmitted(txId) } async cancelTransaction (txId) { - this.setTxStatusRejected(txId) - } - - - getChainId () { - const networkState = this.networkStore.getState() - const getChainId = parseInt(networkState) - if (Number.isNaN(getChainId)) { - return 0 - } else { - return getChainId - } + this.txStateManager.setTxStatusRejected(txId) } // receives a txHash records the tx as signed setTxHash (txId, txHash) { // Add the tx hash to the persisted meta-tx object - const txMeta = this.getTx(txId) + const txMeta = this.txStateManager.getTx(txId) txMeta.hash = txHash - this.updateTx(txMeta) - } - - /* - Takes an object of fields to search for eg: - let thingsToLookFor = { - to: '0x0..', - from: '0x0..', - status: 'signed', - err: undefined, - } - and returns a list of tx with all - options matching - - ****************HINT**************** - | `err: undefined` is like looking | - | for a tx with no err | - | so you can also search txs that | - | dont have something as well by | - | setting the value as undefined | - ************************************ - - this is for things like filtering a the tx list - for only tx's from 1 account - or for filltering for all txs from one account - and that have been 'confirmed' - */ - getFilteredTxList (opts) { - let filteredTxList - Object.keys(opts).forEach((key) => { - filteredTxList = this.getTxsByMetaData(key, opts[key], filteredTxList) - }) - return filteredTxList - } - - getTxsByMetaData (key, value, txList = this.getTxList()) { - return txList.filter((txMeta) => { - if (txMeta.txParams[key]) { - return txMeta.txParams[key] === value - } else { - return txMeta[key] === value - } - }) - } - - // STATUS METHODS - // get::set status - - // should return the status of the tx. - getTxStatus (txId) { - const txMeta = this.getTx(txId) - return txMeta.status - } - - // should update the status of the tx to 'rejected'. - setTxStatusRejected (txId) { - this._setTxStatus(txId, 'rejected') - } - - // should update the status of the tx to 'approved'. - setTxStatusApproved (txId) { - this._setTxStatus(txId, 'approved') - } - - // should update the status of the tx to 'signed'. - setTxStatusSigned (txId) { - this._setTxStatus(txId, 'signed') - } - - // should update the status of the tx to 'submitted'. - setTxStatusSubmitted (txId) { - this._setTxStatus(txId, 'submitted') - } - - // should update the status of the tx to 'confirmed'. - setTxStatusConfirmed (txId) { - this._setTxStatus(txId, 'confirmed') - } - - setTxStatusFailed (txId, err) { - const txMeta = this.getTx(txId) - txMeta.err = { - message: err.toString(), - stack: err.stack, - } - this.updateTx(txMeta) - this._setTxStatus(txId, 'failed') - } - - // merges txParams obj onto txData.txParams - // use extend to ensure that all fields are filled - updateTxParams (txId, txParams) { - const txMeta = this.getTx(txId) - txMeta.txParams = extend(txMeta.txParams, txParams) - this.updateTx(txMeta) + this.txStateManager.updateTx(txMeta) } /* _____________________________________ @@ -419,37 +262,9 @@ module.exports = class TransactionController extends EventEmitter { | PRIVATE METHODS | |______________________________________*/ - - // Should find the tx in the tx list and - // update it. - // should set the status in txData - // - `'unapproved'` the user has not responded - // - `'rejected'` the user has responded no! - // - `'approved'` the user has approved the tx - // - `'signed'` the tx is signed - // - `'submitted'` the tx is sent to a server - // - `'confirmed'` the tx has been included in a block. - // - `'failed'` the tx failed for some reason, included on tx data. - _setTxStatus (txId, status) { - const txMeta = this.getTx(txId) - txMeta.status = status - this.emit(`${txMeta.id}:${status}`, txId) - if (status === 'submitted' || status === 'rejected') { - this.emit(`${txMeta.id}:finished`, txMeta) - } - this.updateTx(txMeta) - this.emit('updateBadge') - } - - // Saves the new/updated txList. - // Function is intended only for internal use - _saveTxList (transactions) { - this.store.updateState({ transactions }) - } - _updateMemstore () { - const unapprovedTxs = this.getUnapprovedTxList() - const selectedAddressTxList = this.getFilteredTxList({ + const unapprovedTxs = this.txStateManager.getUnapprovedTxList() + const selectedAddressTxList = this.txStateManager.getFilteredTxList({ from: this.getSelectedAddress(), metamaskNetworkId: this.getNetwork(), }) diff --git a/app/scripts/lib/tx-utils.js b/app/scripts/lib/tx-gas-utils.js index 5af078dc4..246c94ccd 100644 --- a/app/scripts/lib/tx-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -1,5 +1,4 @@ const EthQuery = require('ethjs-query') -const Transaction = require('ethereumjs-tx') const normalize = require('eth-sig-util').normalize const { hexToBn, @@ -78,26 +77,6 @@ module.exports = class txProvideUtil { return bnToHex(upperGasLimitBn) } - // builds ethTx from txParams object - buildEthTxFromParams (txParams) { - // normalize values - txParams.to = normalize(txParams.to) - txParams.from = normalize(txParams.from) - txParams.value = normalize(txParams.value) - txParams.data = normalize(txParams.data) - txParams.gas = normalize(txParams.gas || txParams.gasLimit) - txParams.gasPrice = normalize(txParams.gasPrice) - txParams.nonce = normalize(txParams.nonce) - // build ethTx - log.info(`Prepared tx for signing: ${JSON.stringify(txParams)}`) - const ethTx = new Transaction(txParams) - return ethTx - } - - async publishTransaction (rawTx) { - return await this.query.sendRawTransaction(rawTx) - } - async validateTxParams (txParams) { if (('value' in txParams) && txParams.value.indexOf('-') === 0) { throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`) diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js new file mode 100644 index 000000000..64925c528 --- /dev/null +++ b/app/scripts/lib/tx-state-manager.js @@ -0,0 +1,221 @@ +const extend = require('xtend') +const ObservableStore = require('obs-store') +const txStateHistoryHelper = require('./tx-state-history-helper') + +module.exports = class TransactionStateManger extends ObservableStore { + constructor ({initState, txHistoryLimit, getNetwork}) { + super(initState) + this.txHistoryLimit = txHistoryLimit + this.getNetwork = getNetwork + } + // Returns the number of txs for the current network. + getTxCount () { + return this.getTxList().length + } + + getTxList () { + const network = this.getNetwork() + const fullTxList = this.getFullTxList() + return fullTxList.filter((txMeta) => txMeta.metamaskNetworkId === network) + } + + getFullTxList () { + return this.getState().transactions + } + + // Returns the tx list + + getUnapprovedTxList () { + const txList = this.getTxsByMetaData('status', 'unapproved') + return txList.reduce((result, tx) => { + result[tx.id] = tx + return result + }, {}) + } + + addTx (txMeta) { + this.once(`${txMeta.id}:signed`, function (txId) { + this.removeAllListeners(`${txMeta.id}:rejected`) + }) + this.once(`${txMeta.id}:rejected`, function (txId) { + this.removeAllListeners(`${txMeta.id}:signed`) + }) + // initialize history + txMeta.history = [] + // capture initial snapshot of txMeta for history + const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta) + txMeta.history.push(snapshot) + + const transactions = this.getFullTxList() + const txCount = this.getTxCount() + const txHistoryLimit = this.txHistoryLimit + + // checks if the length of the tx history is + // longer then desired persistence limit + // and then if it is removes only confirmed + // or rejected tx's. + // not tx's that are pending or unapproved + if (txCount > txHistoryLimit - 1) { + const index = transactions.findIndex((metaTx) => ((metaTx.status === 'confirmed' || metaTx.status === 'rejected'))) + transactions.splice(index, 1) + } + transactions.push(txMeta) + this._saveTxList(transactions) + return txMeta + } + // gets tx by Id and returns it + getTx (txId) { + const txMeta = this.getTxsByMetaData('id', txId)[0] + return txMeta + } + + updateTx (txMeta) { + // create txMeta snapshot for history + const currentState = txStateHistoryHelper.snapshotFromTxMeta(txMeta) + // recover previous tx state obj + const previousState = txStateHistoryHelper.replayHistory(txMeta.history) + // generate history entry and add to history + const entry = txStateHistoryHelper.generateHistoryEntry(previousState, currentState) + txMeta.history.push(entry) + + // commit txMeta to state + const txId = txMeta.id + const txList = this.getFullTxList() + const index = txList.findIndex(txData => txData.id === txId) + txList[index] = txMeta + this._saveTxList(txList) + } + + + // merges txParams obj onto txData.txParams + // use extend to ensure that all fields are filled + updateTxParams (txId, txParams) { + const txMeta = this.getTx(txId) + txMeta.txParams = extend(txMeta.txParams, txParams) + this.updateTx(txMeta) + } + +/* + Takes an object of fields to search for eg: + let thingsToLookFor = { + to: '0x0..', + from: '0x0..', + status: 'signed', + err: undefined, + } + and returns a list of tx with all + options matching + + ****************HINT**************** + | `err: undefined` is like looking | + | for a tx with no err | + | so you can also search txs that | + | dont have something as well by | + | setting the value as undefined | + ************************************ + + this is for things like filtering a the tx list + for only tx's from 1 account + or for filltering for all txs from one account + and that have been 'confirmed' + */ + getFilteredTxList (opts, initialList) { + let filteredTxList = initialList + Object.keys(opts).forEach((key) => { + filteredTxList = this.getTxsByMetaData(key, opts[key], filteredTxList) + }) + return filteredTxList + } + + getTxsByMetaData (key, value, txList = this.getTxList()) { + return txList.filter((txMeta) => { + if (txMeta.txParams[key]) { + return txMeta.txParams[key] === value + } else { + return txMeta[key] === value + } + }) + } + + // STATUS METHODS + // statuses: + // - `'unapproved'` the user has not responded + // - `'rejected'` the user has responded no! + // - `'approved'` the user has approved the tx + // - `'signed'` the tx is signed + // - `'submitted'` the tx is sent to a server + // - `'confirmed'` the tx has been included in a block. + // - `'failed'` the tx failed for some reason, included on tx data. + + // get::set status + + // should return the status of the tx. + getTxStatus (txId) { + const txMeta = this.getTx(txId) + return txMeta.status + } + + // should update the status of the tx to 'rejected'. + setTxStatusRejected (txId) { + this._setTxStatus(txId, 'rejected') + } + + // should update the status of the tx to 'approved'. + setTxStatusApproved (txId) { + this._setTxStatus(txId, 'approved') + } + + // should update the status of the tx to 'signed'. + setTxStatusSigned (txId) { + this._setTxStatus(txId, 'signed') + } + + // should update the status of the tx to 'submitted'. + setTxStatusSubmitted (txId) { + this._setTxStatus(txId, 'submitted') + } + + // should update the status of the tx to 'confirmed'. + setTxStatusConfirmed (txId) { + this._setTxStatus(txId, 'confirmed') + } + + setTxStatusFailed (txId, reason) { + const txMeta = this.getTx(txId) + txMeta.err = reason + this.updateTx(txMeta) + this._setTxStatus(txId, 'failed') + } + +/* _____________________________________ +| | +| PRIVATE METHODS | +|______________________________________*/ + + // Should find the tx in the tx list and + // update it. + // should set the status in txData + // - `'unapproved'` the user has not responded + // - `'rejected'` the user has responded no! + // - `'approved'` the user has approved the tx + // - `'signed'` the tx is signed + // - `'submitted'` the tx is sent to a server + // - `'confirmed'` the tx has been included in a block. + // - `'failed'` the tx failed for some reason, included on tx data. + _setTxStatus (txId, status) { + const txMeta = this.getTx(txId) + txMeta.status = status + this.emit(`${txMeta.id}:${status}`, txId) + if (status === 'submitted' || status === 'rejected') { + this.emit(`${txMeta.id}:finished`, txMeta) + } + this.updateTx(txMeta) + this.emit('updateBadge') + } + + // Saves the new/updated txList. + // Function is intended only for internal use + _saveTxList (transactions) { + this.updateState({ transactions }) + } +}
\ No newline at end of file diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index a007d6fc5..7137190ac 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -133,7 +133,7 @@ module.exports = class MetamaskController extends EventEmitter { this.publicConfigStore = this.initPublicConfigStore() // manual disk state subscriptions - this.txController.store.subscribe((state) => { + this.txController.txStateManager.subscribe((state) => { this.store.updateState({ TransactionController: state }) }) this.keyringController.store.subscribe((state) => { diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index 7bb193242..f969752ec 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -5,7 +5,7 @@ const ObservableStore = require('obs-store') const clone = require('clone') const sinon = require('sinon') const TransactionController = require('../../app/scripts/controllers/transactions') -const TxProvideUtils = require('../../app/scripts/lib/tx-utils') +const TxGasUtils = require('../../app/scripts/lib/tx-gas-utils') const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper') const noop = () => true @@ -34,7 +34,7 @@ describe('Transaction Controller', function () { }), }) txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop }) - txController.txProviderUtils = new TxProvideUtils(txController.provider) + txController.txProviderUtils = new TxGasUtils(txController.provider) }) describe('#newUnapprovedTransaction', function () { @@ -49,12 +49,14 @@ describe('Transaction Controller', function () { id: 1, metamaskNetworkId: currentNetworkId, txParams, + history: [], } - txController.addTx(txMeta) - stub = sinon.stub(txController, 'addUnapprovedTransaction').returns(Promise.resolve(txMeta)) + txController.txStateManager._saveTxList([txMeta]) + stub = sinon.stub(txController, 'addUnapprovedTransaction').returns(Promise.resolve(txController.txStateManager.addTx(txMeta))) }) afterEach(function () { + txController.txStateManager._saveTxList([]) stub.restore() }) @@ -72,7 +74,7 @@ describe('Transaction Controller', function () { txController.once('newUnaprovedTx', (txMetaFromEmit) => { setTimeout(() => { txController.setTxHash(txMetaFromEmit.id, '0x0') - txController.setTxStatusSubmitted(txMetaFromEmit.id) + txController.txStateManager.setTxStatusSubmitted(txMetaFromEmit.id) }, 10) }) @@ -87,7 +89,7 @@ describe('Transaction Controller', function () { it('should reject when finished and status is rejected', function (done) { txController.once('newUnaprovedTx', (txMetaFromEmit) => { setTimeout(() => { - txController.setTxStatusRejected(txMetaFromEmit.id) + txController.txStateManager.setTxStatusRejected(txMetaFromEmit.id) }, 10) }) @@ -110,7 +112,7 @@ describe('Transaction Controller', function () { assert(('txParams' in txMeta), 'should have a txParams') assert(('history' in txMeta), 'should have a history') - const memTxMeta = txController.getTx(txMeta.id) + const memTxMeta = txController.txStateManager.getTx(txMeta.id) assert.deepEqual(txMeta, memTxMeta, `txMeta should be stored in txController after adding it\n expected: ${txMeta} \n got: ${memTxMeta}`) addTxDefaultsStub.restore() done() @@ -163,214 +165,32 @@ describe('Transaction Controller', function () { }) }) - describe('#getTxList', function () { - it('when new should return empty array', function () { - var result = txController.getTxList() - assert.ok(Array.isArray(result)) - assert.equal(result.length, 0) - }) - }) - describe('#addTx', function () { - it('adds a tx returned in getTxList', function () { - var tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(tx, noop) - var result = txController.getTxList() - assert.ok(Array.isArray(result)) - assert.equal(result.length, 1) - assert.equal(result[0].id, 1) - }) - - it('does not override txs from other networks', function () { - var tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } - var tx2 = { id: 2, status: 'confirmed', metamaskNetworkId: otherNetworkId, txParams: {} } - txController.addTx(tx, noop) - txController.addTx(tx2, noop) - var result = txController.getFullTxList() - var result2 = txController.getTxList() - assert.equal(result.length, 2, 'txs were deleted') - assert.equal(result2.length, 1, 'incorrect number of txs on network.') - }) - - it('cuts off early txs beyond a limit', function () { - const limit = txController.txHistoryLimit - for (let i = 0; i < limit + 1; i++) { - const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(tx, noop) - } - var result = txController.getTxList() - assert.equal(result.length, limit, `limit of ${limit} txs enforced`) - assert.equal(result[0].id, 1, 'early txs truncted') - }) - - it('cuts off early txs beyond a limit whether or not it is confirmed or rejected', function () { - const limit = txController.txHistoryLimit - for (let i = 0; i < limit + 1; i++) { - const tx = { id: i, time: new Date(), status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(tx, noop) - } - var result = txController.getTxList() - assert.equal(result.length, limit, `limit of ${limit} txs enforced`) - assert.equal(result[0].id, 1, 'early txs truncted') - }) - - it('cuts off early txs beyond a limit but does not cut unapproved txs', function () { - var unconfirmedTx = { id: 0, time: new Date(), status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(unconfirmedTx, noop) - const limit = txController.txHistoryLimit - for (let i = 1; i < limit + 1; i++) { - const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(tx, noop) - } - var result = txController.getTxList() - assert.equal(result.length, limit, `limit of ${limit} txs enforced`) - assert.equal(result[0].id, 0, 'first tx should still be there') - assert.equal(result[0].status, 'unapproved', 'first tx should be unapproved') - assert.equal(result[1].id, 2, 'early txs truncted') - }) - }) - - describe('#setTxStatusSigned', function () { - it('sets the tx status to signed', function () { - var tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(tx, noop) - txController.setTxStatusSigned(1) - var result = txController.getTxList() - assert.ok(Array.isArray(result)) - assert.equal(result.length, 1) - assert.equal(result[0].status, 'signed') - }) - - it('should emit a signed event to signal the exciton of callback', (done) => { - this.timeout(10000) - var tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } - const noop = function () { - assert(true, 'event listener has been triggered and noop executed') - done() - } - txController.addTx(tx) - txController.on('1:signed', noop) - txController.setTxStatusSigned(1) - }) - }) - - describe('#setTxStatusRejected', function () { - it('sets the tx status to rejected', function () { - var tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(tx) - txController.setTxStatusRejected(1) - var result = txController.getTxList() - assert.ok(Array.isArray(result)) - assert.equal(result.length, 1) - assert.equal(result[0].status, 'rejected') - }) - - it('should emit a rejected event to signal the exciton of callback', (done) => { - this.timeout(10000) - var tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } - txController.addTx(tx) - const noop = function (err, txId) { - assert(true, 'event listener has been triggered and noop executed') - done() - } - txController.on('1:rejected', noop) - txController.setTxStatusRejected(1) - }) - }) - - describe('#updateTx', function () { - it('replaces the tx with the same id', function () { - txController.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - txController.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - const tx1 = txController.getTx('1') - tx1.status = 'blah' - tx1.hash = 'foo' - txController.updateTx(tx1) - const savedResult = txController.getTx('1') - assert.equal(savedResult.hash, 'foo') - }) - - it('updates gas price and adds history items', function () { - const originalGasPrice = '0x01' - const desiredGasPrice = '0x02' - + it('should emit updates', function (done) { const txMeta = { id: '1', status: 'unapproved', + id: 1, metamaskNetworkId: currentNetworkId, - txParams: { - gasPrice: originalGasPrice, - }, + txParams: {} } + const eventNames = ['update', 'updateBadge', '1:unapproved'] + const listeners = [] + eventNames.forEach((eventName) => { + listeners.push(new Promise((resolve) => { + txController.once(eventName, (arg) => { + resolve(arg) + }) + })) + }) + Promise.all(listeners) + .then((returnValues) => { + assert.deepEqual(returnValues.pop(), txMeta, 'last event 1:unapproved should return txMeta') + done() + }) + .catch(done) txController.addTx(txMeta) - const updatedTx = txController.getTx('1') - // verify tx was initialized correctly - assert.equal(updatedTx.history.length, 1, 'one history item (initial)') - assert.equal(Array.isArray(updatedTx.history[0]), false, 'first history item is initial state') - assert.deepEqual(updatedTx.history[0], txStateHistoryHelper.snapshotFromTxMeta(updatedTx), 'first history item is initial state') - // modify value and updateTx - updatedTx.txParams.gasPrice = desiredGasPrice - txController.updateTx(updatedTx) - // check updated value - const result = txController.getTx('1') - assert.equal(result.txParams.gasPrice, desiredGasPrice, 'gas price updated') - // validate history was updated - assert.equal(result.history.length, 2, 'two history items (initial + diff)') - const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice } - assert.deepEqual(result.history[1], [expectedEntry], 'two history items (initial + diff)') - }) - }) - - describe('#getUnapprovedTxList', function () { - it('returns unapproved txs in a hash', function () { - txController.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - txController.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - const result = txController.getUnapprovedTxList() - assert.equal(typeof result, 'object') - assert.equal(result['1'].status, 'unapproved') - assert.equal(result['2'], undefined) - }) - }) - - describe('#getTx', function () { - it('returns a tx with the requested id', function () { - txController.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - txController.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) - assert.equal(txController.getTx('1').status, 'unapproved') - assert.equal(txController.getTx('2').status, 'confirmed') - }) - }) - - describe('#getFilteredTxList', function () { - it('returns a tx with the requested data', function () { - const txMetas = [ - { id: 0, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 1, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 2, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 3, status: 'unapproved', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 4, status: 'unapproved', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 5, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 6, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, - { id: 7, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 8, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - { id: 9, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, - ] - txMetas.forEach((txMeta) => txController.addTx(txMeta, noop)) - let filterParams - - filterParams = { status: 'unapproved', from: '0xaa' } - assert.equal(txController.getFilteredTxList(filterParams).length, 3, `getFilteredTxList - ${JSON.stringify(filterParams)}`) - filterParams = { status: 'unapproved', to: '0xaa' } - assert.equal(txController.getFilteredTxList(filterParams).length, 2, `getFilteredTxList - ${JSON.stringify(filterParams)}`) - filterParams = { status: 'confirmed', from: '0xbb' } - assert.equal(txController.getFilteredTxList(filterParams).length, 3, `getFilteredTxList - ${JSON.stringify(filterParams)}`) - filterParams = { status: 'confirmed' } - assert.equal(txController.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) - filterParams = { from: '0xaa' } - assert.equal(txController.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) - filterParams = { to: '0xaa' } - assert.equal(txController.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) }) }) @@ -404,11 +224,11 @@ describe('Transaction Controller', function () { const pubStub = sinon.stub(txController, 'publishTransaction').callsFake(() => { txController.setTxHash('1', originalValue) - txController.setTxStatusSubmitted('1') + txController.txStateManager.setTxStatusSubmitted('1') }) txController.approveTransaction(txMeta.id).then(() => { - const result = txController.getTx(txMeta.id) + const result = txController.txStateManager.getTx(txMeta.id) const params = result.txParams assert.equal(params.gas, originalValue, 'gas unmodified') diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js new file mode 100644 index 000000000..464e50ee4 --- /dev/null +++ b/test/unit/tx-state-manager-test.js @@ -0,0 +1,241 @@ +const assert = require('assert') +const clone = require('clone') +const ObservableStore = require('obs-store') +const TxStateManager = require('../../app/scripts/lib/tx-state-manager') +const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper') +const noop = () => true + +describe('TransactionStateManger', function () { + let txStateManager + const currentNetworkId = 42 + const otherNetworkId = 2 + + beforeEach(function () { + txStateManager = new TxStateManager({ + initState: { + transactions: [], + }, + txHistoryLimit: 10, + getNetwork: () => currentNetworkId + }) + }) + + describe('#setTxStatusSigned', function () { + it('sets the tx status to signed', function () { + let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx, noop) + txStateManager.setTxStatusSigned(1) + let result = txStateManager.getTxList() + assert.ok(Array.isArray(result)) + assert.equal(result.length, 1) + assert.equal(result[0].status, 'signed') + }) + + it('should emit a signed event to signal the exciton of callback', (done) => { + let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + const noop = function () { + assert(true, 'event listener has been triggered and noop executed') + done() + } + txStateManager.addTx(tx) + txStateManager.on('1:signed', noop) + txStateManager.setTxStatusSigned(1) + + }) + }) + + describe('#setTxStatusRejected', function () { + it('sets the tx status to rejected', function () { + let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx) + txStateManager.setTxStatusRejected(1) + let result = txStateManager.getTxList() + assert.ok(Array.isArray(result)) + assert.equal(result.length, 1) + assert.equal(result[0].status, 'rejected') + }) + + it('should emit a rejected event to signal the exciton of callback', (done) => { + let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx) + const noop = function (err, txId) { + assert(true, 'event listener has been triggered and noop executed') + done() + } + txStateManager.on('1:rejected', noop) + txStateManager.setTxStatusRejected(1) + }) + }) + + describe('#getFullTxList', function () { + it('when new should return empty array', function () { + let result = txStateManager.getTxList() + assert.ok(Array.isArray(result)) + assert.equal(result.length, 0) + }) + }) + + describe('#getTxList', function () { + it('when new should return empty array', function () { + let result = txStateManager.getTxList() + assert.ok(Array.isArray(result)) + assert.equal(result.length, 0) + }) + }) + + describe('#addTx', function () { + it('adds a tx returned in getTxList', function () { + let tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx, noop) + let result = txStateManager.getTxList() + assert.ok(Array.isArray(result)) + assert.equal(result.length, 1) + assert.equal(result[0].id, 1) + }) + + it('does not override txs from other networks', function () { + let tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } + let tx2 = { id: 2, status: 'confirmed', metamaskNetworkId: otherNetworkId, txParams: {} } + txStateManager.addTx(tx, noop) + txStateManager.addTx(tx2, noop) + let result = txStateManager.getFullTxList() + let result2 = txStateManager.getTxList() + assert.equal(result.length, 2, 'txs were deleted') + assert.equal(result2.length, 1, 'incorrect number of txs on network.') + }) + + it('cuts off early txs beyond a limit', function () { + const limit = txStateManager.txHistoryLimit + for (let i = 0; i < limit + 1; i++) { + const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx, noop) + } + let result = txStateManager.getTxList() + assert.equal(result.length, limit, `limit of ${limit} txs enforced`) + assert.equal(result[0].id, 1, 'early txs truncted') + }) + + it('cuts off early txs beyond a limit whether or not it is confirmed or rejected', function () { + const limit = txStateManager.txHistoryLimit + for (let i = 0; i < limit + 1; i++) { + const tx = { id: i, time: new Date(), status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx, noop) + } + let result = txStateManager.getTxList() + assert.equal(result.length, limit, `limit of ${limit} txs enforced`) + assert.equal(result[0].id, 1, 'early txs truncted') + }) + + it('cuts off early txs beyond a limit but does not cut unapproved txs', function () { + let unconfirmedTx = { id: 0, time: new Date(), status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(unconfirmedTx, noop) + const limit = txStateManager.txHistoryLimit + for (let i = 1; i < limit + 1; i++) { + const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx, noop) + } + let result = txStateManager.getTxList() + assert.equal(result.length, limit, `limit of ${limit} txs enforced`) + assert.equal(result[0].id, 0, 'first tx should still be there') + assert.equal(result[0].status, 'unapproved', 'first tx should be unapproved') + assert.equal(result[1].id, 2, 'early txs truncted') + }) + }) + + describe('#updateTx', function () { + it('replaces the tx with the same id', function () { + txStateManager.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + txStateManager.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + const txMeta = txStateManager.getTx('1') + txMeta.hash = 'foo' + txStateManager.updateTx(txMeta) + let result = txStateManager.getTx('1') + assert.equal(result.hash, 'foo') + }) + + it('updates gas price and adds history items', function () { + const originalGasPrice = '0x01' + const desiredGasPrice = '0x02' + + const txMeta = { + id: '1', + status: 'unapproved', + metamaskNetworkId: currentNetworkId, + txParams: { + gasPrice: originalGasPrice, + }, + } + + const updatedMeta = clone(txMeta) + + txStateManager.addTx(txMeta) + const updatedTx = txStateManager.getTx('1') + // verify tx was initialized correctly + assert.equal(updatedTx.history.length, 1, 'one history item (initial)') + assert.equal(Array.isArray(updatedTx.history[0]), false, 'first history item is initial state') + assert.deepEqual(updatedTx.history[0], txStateHistoryHelper.snapshotFromTxMeta(updatedTx), 'first history item is initial state') + // modify value and updateTx + updatedTx.txParams.gasPrice = desiredGasPrice + txStateManager.updateTx(updatedTx) + // check updated value + const result = txStateManager.getTx('1') + assert.equal(result.txParams.gasPrice, desiredGasPrice, 'gas price updated') + // validate history was updated + assert.equal(result.history.length, 2, 'two history items (initial + diff)') + const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice } + assert.deepEqual(result.history[1], [expectedEntry], 'two history items (initial + diff)') + }) + }) + + describe('#getUnapprovedTxList', function () { + it('returns unapproved txs in a hash', function () { + txStateManager.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + txStateManager.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + const result = txStateManager.getUnapprovedTxList() + assert.equal(typeof result, 'object') + assert.equal(result['1'].status, 'unapproved') + assert.equal(result['2'], undefined) + }) + }) + + describe('#getTx', function () { + it('returns a tx with the requested id', function () { + txStateManager.addTx({ id: '1', status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + txStateManager.addTx({ id: '2', status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, noop) + assert.equal(txStateManager.getTx('1').status, 'unapproved') + assert.equal(txStateManager.getTx('2').status, 'confirmed') + }) + }) + + describe('#getFilteredTxList', function () { + it('returns a tx with the requested data', function () { + const txMetas = [ + { id: 0, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, + { id: 1, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, + { id: 2, status: 'unapproved', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, + { id: 3, status: 'unapproved', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, + { id: 4, status: 'unapproved', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, + { id: 5, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, + { id: 6, status: 'confirmed', txParams: { from: '0xaa', to: '0xbb' }, metamaskNetworkId: currentNetworkId }, + { id: 7, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, + { id: 8, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, + { id: 9, status: 'confirmed', txParams: { from: '0xbb', to: '0xaa' }, metamaskNetworkId: currentNetworkId }, + ] + txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop)) + let filterParams + + filterParams = { status: 'unapproved', from: '0xaa' } + assert.equal(txStateManager.getFilteredTxList(filterParams).length, 3, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + filterParams = { status: 'unapproved', to: '0xaa' } + assert.equal(txStateManager.getFilteredTxList(filterParams).length, 2, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + filterParams = { status: 'confirmed', from: '0xbb' } + assert.equal(txStateManager.getFilteredTxList(filterParams).length, 3, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + filterParams = { status: 'confirmed' } + assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + filterParams = { from: '0xaa' } + assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + filterParams = { to: '0xaa' } + assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`) + }) + }) +})
\ No newline at end of file diff --git a/test/unit/tx-utils-test.js b/test/unit/tx-utils-test.js index 43128b977..8ca13412e 100644 --- a/test/unit/tx-utils-test.js +++ b/test/unit/tx-utils-test.js @@ -1,8 +1,10 @@ const assert = require('assert') +const Transaction = require('ethereumjs-tx') const BN = require('bn.js') + const { hexToBn, bnToHex } = require('../../app/scripts/lib/util') -const TxUtils = require('../../app/scripts/lib/tx-utils') +const TxUtils = require('../../app/scripts/lib/tx-gas-utils') describe('txUtils', function () { @@ -28,7 +30,7 @@ describe('txUtils', function () { nonce: '0x3', chainId: 42, } - const ethTx = txUtils.buildEthTxFromParams(txParams) + const ethTx = new Transaction(txParams) assert.equal(ethTx.getChainId(), 42, 'chainId is set from tx params') }) }) |