From 2d7c3c2b00a698b19ac015624154c3c1cd2619b2 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Fri, 6 Apr 2018 11:07:20 -0700 Subject: meta - transactions - create a transactions dir in controller and move relevant files into it --- app/scripts/lib/nonce-tracker.js | 148 -------------- app/scripts/lib/pending-tx-tracker.js | 189 ------------------ app/scripts/lib/tx-gas-utils.js | 103 ---------- app/scripts/lib/tx-state-history-helper.js | 41 ---- app/scripts/lib/tx-state-manager.js | 303 ----------------------------- 5 files changed, 784 deletions(-) delete mode 100644 app/scripts/lib/nonce-tracker.js delete mode 100644 app/scripts/lib/pending-tx-tracker.js delete mode 100644 app/scripts/lib/tx-gas-utils.js delete mode 100644 app/scripts/lib/tx-state-history-helper.js delete mode 100644 app/scripts/lib/tx-state-manager.js (limited to 'app/scripts/lib') diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js deleted file mode 100644 index 5b1cd7f43..000000000 --- a/app/scripts/lib/nonce-tracker.js +++ /dev/null @@ -1,148 +0,0 @@ -const EthQuery = require('ethjs-query') -const assert = require('assert') -const Mutex = require('await-semaphore').Mutex - -class NonceTracker { - - constructor ({ provider, getPendingTransactions, getConfirmedTransactions }) { - this.provider = provider - this.ethQuery = new EthQuery(provider) - this.getPendingTransactions = getPendingTransactions - this.getConfirmedTransactions = getConfirmedTransactions - this.lockMap = {} - } - - async getGlobalLock () { - const globalMutex = this._lookupMutex('global') - // await global mutex free - const releaseLock = await globalMutex.acquire() - return { releaseLock } - } - - // releaseLock must be called - // releaseLock must be called after adding signed tx to pending transactions (or discarding) - async getNonceLock (address) { - // await global mutex free - await this._globalMutexFree() - // await lock free, then take lock - const releaseLock = await this._takeMutex(address) - // 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 } - } - - async _getCurrentBlock () { - const blockTracker = this._getBlockTracker() - const currentBlock = blockTracker.getCurrentBlock() - if (currentBlock) return currentBlock - return await new Promise((reject, resolve) => { - blockTracker.once('latest', resolve) - }) - } - - async _globalMutexFree () { - const globalMutex = this._lookupMutex('global') - const release = await globalMutex.acquire() - release() - } - - 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 currentBlock = await this._getCurrentBlock() - const blockNumber = currentBlock.blockNumber - const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber || 'latest') - 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 - } - - _reduceTxListToUniqueNonces (txList) { - const reducedTxList = txList.reduce((reducedList, txMeta, index) => { - if (!index) return [txMeta] - const nonceMatches = txList.filter((txData) => { - return txMeta.txParams.nonce === txData.txParams.nonce - }) - if (nonceMatches.length > 1) return reducedList - reducedList.push(txMeta) - return reducedList - }, []) - return reducedTxList - } - - _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 - } - - _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 } } - } - - // this is a hotfix for the fact that the blockTracker will - // change when the network changes - _getBlockTracker () { - return this.provider._blockTracker - } -} - -module.exports = NonceTracker diff --git a/app/scripts/lib/pending-tx-tracker.js b/app/scripts/lib/pending-tx-tracker.js deleted file mode 100644 index e8869e6b8..000000000 --- a/app/scripts/lib/pending-tx-tracker.js +++ /dev/null @@ -1,189 +0,0 @@ -const EventEmitter = require('events') -const EthQuery = require('ethjs-query') -/* - - Utility class for tracking the transactions as they - go from a pending state to a confirmed (mined in a block) state - - As well as continues broadcast while in the pending state - - ~config is not optional~ - requires a: { - provider: //, - nonceTracker: //see nonce tracker, - getPendingTransactions: //() a function for getting an array of transactions, - publishTransaction: //(rawTx) a async function for publishing raw transactions, - } - -*/ - -module.exports = class PendingTransactionTracker extends EventEmitter { - constructor (config) { - super() - this.query = new EthQuery(config.provider) - this.nonceTracker = config.nonceTracker - // default is one day - this.getPendingTransactions = config.getPendingTransactions - this.getCompletedTransactions = config.getCompletedTransactions - this.publishTransaction = config.publishTransaction - this._checkPendingTxs() - } - - // checks if a signed tx is in a block and - // if included sets the tx status as 'confirmed' - checkForTxInBlock (block) { - const signedTxList = this.getPendingTransactions() - if (!signedTxList.length) return - signedTxList.forEach((txMeta) => { - const txHash = txMeta.hash - const txId = txMeta.id - - if (!txHash) { - 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 - } - - - block.transactions.forEach((tx) => { - if (tx.hash === txHash) this.emit('tx:confirmed', txId) - }) - }) - } - - 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 - const diff = Number.parseInt(newBlock.number, 16) - Number.parseInt(oldBlock.number, 16) - if (diff > 1) this._checkPendingTxs() - } - - - resubmitPendingTxs (block) { - const pending = this.getPendingTransactions() - // only try resubmitting if their are transactions to resubmit - if (!pending.length) return - pending.forEach((txMeta) => this._resubmitTx(txMeta, block.number).catch((err) => { - /* - Dont marked as failed if the error is a "known" transaction warning - "there is already a transaction with the same sender-nonce - but higher/same gas price" - - Also don't mark as failed if it has ever been broadcast successfully. - A successful broadcast means it may still be mined. - */ - const errorMessage = err.message.toLowerCase() - const isKnownTx = ( - // geth - errorMessage.includes('replacement transaction underpriced') || - errorMessage.includes('known transaction') || - // parity - errorMessage.includes('gas price too low to replace') || - errorMessage.includes('transaction with the same hash was already imported') || - // other - errorMessage.includes('gateway timeout') || - errorMessage.includes('nonce too low') - ) - // ignore resubmit warnings, return early - if (isKnownTx) return - // encountered real error - transition to error state - txMeta.warning = { - error: errorMessage, - message: 'There was an error when resubmitting this transaction.', - } - this.emit('tx:warning', txMeta, err) - })) - } - - async _resubmitTx (txMeta, latestBlockNumber) { - if (!txMeta.firstRetryBlockNumber) { - this.emit('tx:block-update', txMeta, latestBlockNumber) - } - - const firstRetryBlockNumber = txMeta.firstRetryBlockNumber || latestBlockNumber - const txBlockDistance = Number.parseInt(latestBlockNumber, 16) - Number.parseInt(firstRetryBlockNumber, 16) - - const retryCount = txMeta.retryCount || 0 - - // Exponential backoff to limit retries at publishing - if (txBlockDistance <= Math.pow(2, retryCount) - 1) return - - // Only auto-submit already-signed txs: - if (!('rawTx' in txMeta)) return - - const rawTx = txMeta.rawTx - const txHash = await this.publishTransaction(rawTx) - - // Increment successful tries: - this.emit('tx:retry', txMeta) - return txHash - } - - async _checkPendingTx (txMeta) { - const txHash = txMeta.hash - const txId = txMeta.id - - // extra check in case there was an uncaught error during the - // signature and submission process - if (!txHash) { - 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 another tx with the same nonce is mined, set as failed. - const taken = await this._checkIfNonceIsTaken(txMeta) - if (taken) { - const nonceTakenErr = new Error('Another transaction with this nonce has been mined.') - nonceTakenErr.name = 'NonceTakenErr' - return this.emit('tx:failed', txId, nonceTakenErr) - } - - // get latest transaction status - let txParams - try { - txParams = await this.query.getTransactionByHash(txHash) - if (!txParams) return - if (txParams.blockNumber) { - this.emit('tx:confirmed', txId) - } - } catch (err) { - txMeta.warning = { - error: err.message, - message: 'There was a problem loading this transaction.', - } - this.emit('tx:warning', txMeta, err) - } - } - - // checks the network for signed txs and - // if confirmed sets the tx status as 'confirmed' - 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) { - console.error('PendingTransactionWatcher - Error updating pending transactions') - console.error(err) - } - nonceGlobalLock.releaseLock() - } - - async _checkIfNonceIsTaken (txMeta) { - const address = txMeta.txParams.from - const completed = this.getCompletedTransactions(address) - const sameNonce = completed.filter((otherMeta) => { - return otherMeta.txParams.nonce === txMeta.txParams.nonce - }) - return sameNonce.length > 0 - } - -} diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js deleted file mode 100644 index c579e462a..000000000 --- a/app/scripts/lib/tx-gas-utils.js +++ /dev/null @@ -1,103 +0,0 @@ -const EthQuery = require('ethjs-query') -const { - hexToBn, - BnMultiplyByFraction, - bnToHex, -} = require('./util') -const { addHexPrefix } = require('ethereumjs-util') -const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. - -/* -tx-utils are utility methods for Transaction manager -its passed ethquery -and used to do things like calculate gas of a tx. -*/ - -module.exports = class TxGasUtil { - - constructor (provider) { - this.query = new EthQuery(provider) - } - - async analyzeGasUsage (txMeta) { - const block = await this.query.getBlockByNumber('latest', true) - let estimatedGasHex - try { - estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit) - } catch (err) { - const simulationFailed = ( - err.message.includes('Transaction execution error.') || - err.message.includes('gas required exceeds allowance or always failing transaction') - ) - if (simulationFailed) { - txMeta.simulationFails = true - return txMeta - } - } - this.setTxGas(txMeta, block.gasLimit, estimatedGasHex) - return txMeta - } - - async estimateTxGas (txMeta, blockGasLimitHex) { - const txParams = txMeta.txParams - - // check if gasLimit is already specified - txMeta.gasLimitSpecified = Boolean(txParams.gas) - - // if it is, use that value - if (txMeta.gasLimitSpecified) { - return txParams.gas - } - - // if recipient has no code, gas is 21k max: - const recipient = txParams.to - const hasRecipient = Boolean(recipient) - let code - if (recipient) code = await this.query.getCode(recipient) - - if (hasRecipient && (!code || code === '0x')) { - txParams.gas = SIMPLE_GAS_COST - txMeta.simpleSend = true // Prevents buffer addition - return SIMPLE_GAS_COST - } - - // if not, fall back to block gasLimit - const blockGasLimitBN = hexToBn(blockGasLimitHex) - const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20) - txParams.gas = bnToHex(saferGasLimitBN) - - // run tx - return await this.query.estimateGas(txParams) - } - - setTxGas (txMeta, blockGasLimitHex, estimatedGasHex) { - txMeta.estimatedGas = addHexPrefix(estimatedGasHex) - const txParams = txMeta.txParams - - // if gasLimit was specified and doesnt OOG, - // use original specified amount - if (txMeta.gasLimitSpecified || txMeta.simpleSend) { - txMeta.estimatedGas = txParams.gas - return - } - // if gasLimit not originally specified, - // try adding an additional gas buffer to our estimation for safety - const recommendedGasHex = this.addGasBuffer(txMeta.estimatedGas, blockGasLimitHex) - txParams.gas = recommendedGasHex - return - } - - addGasBuffer (initialGasLimitHex, blockGasLimitHex) { - const initialGasLimitBn = hexToBn(initialGasLimitHex) - const blockGasLimitBn = hexToBn(blockGasLimitHex) - const upperGasLimitBn = blockGasLimitBn.muln(0.9) - const bufferedGasLimitBn = initialGasLimitBn.muln(1.5) - - // if initialGasLimit is above blockGasLimit, dont modify it - if (initialGasLimitBn.gt(upperGasLimitBn)) return bnToHex(initialGasLimitBn) - // if bufferedGasLimit is below blockGasLimit, use bufferedGasLimit - if (bufferedGasLimitBn.lt(upperGasLimitBn)) return bnToHex(bufferedGasLimitBn) - // otherwise use blockGasLimit - return bnToHex(upperGasLimitBn) - } -} \ No newline at end of file diff --git a/app/scripts/lib/tx-state-history-helper.js b/app/scripts/lib/tx-state-history-helper.js deleted file mode 100644 index 94c7b6792..000000000 --- a/app/scripts/lib/tx-state-history-helper.js +++ /dev/null @@ -1,41 +0,0 @@ -const jsonDiffer = require('fast-json-patch') -const clone = require('clone') - -module.exports = { - generateHistoryEntry, - replayHistory, - snapshotFromTxMeta, - migrateFromSnapshotsToDiffs, -} - - -function migrateFromSnapshotsToDiffs (longHistory) { - return ( - longHistory - // convert non-initial history entries into diffs - .map((entry, index) => { - if (index === 0) return entry - return generateHistoryEntry(longHistory[index - 1], entry) - }) - ) -} - -function generateHistoryEntry (previousState, newState, note) { - const entry = jsonDiffer.compare(previousState, newState) - // Add a note to the first op, since it breaks if we append it to the entry - if (note && entry[0]) entry[0].note = note - return entry -} - -function replayHistory (_shortHistory) { - const shortHistory = clone(_shortHistory) - return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument) -} - -function snapshotFromTxMeta (txMeta) { - // create txMeta snapshot for history - const snapshot = clone(txMeta) - // dont include previous history in this snapshot - delete snapshot.history - return snapshot -} diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js deleted file mode 100644 index c6d10ee62..000000000 --- a/app/scripts/lib/tx-state-manager.js +++ /dev/null @@ -1,303 +0,0 @@ -const extend = require('xtend') -const EventEmitter = require('events') -const ObservableStore = require('obs-store') -const createId = require('./random-id') -const ethUtil = require('ethereumjs-util') -const txStateHistoryHelper = require('./tx-state-history-helper') - -// 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. - // - `'dropped'` the tx nonce was already used - -module.exports = class TransactionStateManager extends EventEmitter { - constructor ({ initState, txHistoryLimit, getNetwork }) { - super() - - this.store = new ObservableStore( - extend({ - transactions: [], - }, initState)) - this.txHistoryLimit = txHistoryLimit - this.getNetwork = getNetwork - } - - generateTxMeta (opts) { - return extend({ - id: createId(), - time: (new Date()).getTime(), - status: 'unapproved', - metamaskNetworkId: this.getNetwork(), - loadingDefaults: true, - }, opts) - } - - getTxList () { - const network = this.getNetwork() - const fullTxList = this.getFullTxList() - return fullTxList.filter((txMeta) => txMeta.metamaskNetworkId === network) - } - - getFullTxList () { - return this.store.getState().transactions - } - - // Returns the tx list - getUnapprovedTxList () { - const txList = this.getTxsByMetaData('status', 'unapproved') - return txList.reduce((result, tx) => { - result[tx.id] = tx - return result - }, {}) - } - - getPendingTransactions (address) { - const opts = { status: 'submitted' } - if (address) opts.from = address - return this.getFilteredTxList(opts) - } - - getConfirmedTransactions (address) { - const opts = { status: 'confirmed' } - if (address) opts.from = address - return this.getFilteredTxList(opts) - } - - 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 = transactions.length - 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) { - let index = transactions.findIndex((metaTx) => metaTx.status === 'confirmed' || metaTx.status === 'rejected') - if (index !== -1) { - 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, note) { - // validate txParams - if (txMeta.txParams) { - if (typeof txMeta.txParams.data === 'undefined') { - delete txMeta.txParams.data - } - - this.validateTxParams(txMeta.txParams) - } - - // 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, note) - 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, `txStateManager#updateTxParams`) - } - - // validates txParams members by type - validateTxParams(txParams) { - Object.keys(txParams).forEach((key) => { - const value = txParams[key] - // validate types - switch (key) { - case 'chainId': - if (typeof value !== 'number' && typeof value !== 'string') throw new Error(`${key} in txParams is not a Number or hex string. got: (${value})`) - break - default: - if (typeof value !== 'string') throw new Error(`${key} in txParams is not a string. got: (${value})`) - if (!ethUtil.isHexPrefixed(value)) throw new Error(`${key} in txParams is not hex prefixed. got: (${value})`) - break - } - }) - } - -/* - 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 - } - }) - } - - // 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 'unapproved'. - setTxStatusUnapproved (txId) { - this._setTxStatus(txId, 'unapproved') - } - // 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'. - // and add a time stamp for when it was called - setTxStatusSubmitted (txId) { - const txMeta = this.getTx(txId) - txMeta.submittedTime = (new Date()).getTime() - this.updateTx(txMeta, 'txStateManager - add submitted time stamp') - this._setTxStatus(txId, 'submitted') - } - - // should update the status of the tx to 'confirmed'. - setTxStatusConfirmed (txId) { - this._setTxStatus(txId, 'confirmed') - } - - // should update the status dropped - setTxStatusDropped (txId) { - this._setTxStatus(txId, 'dropped') - } - - - setTxStatusFailed (txId, err) { - const txMeta = this.getTx(txId) - txMeta.err = { - message: err.toString(), - stack: err.stack, - } - this.updateTx(txMeta) - this._setTxStatus(txId, 'failed') - } - - wipeTransactions (address) { - // network only tx - const txs = this.getFullTxList() - const network = this.getNetwork() - - // Filter out the ones from the current account and network - const otherAccountTxs = txs.filter((txMeta) => !(txMeta.txParams.from === address && txMeta.metamaskNetworkId === network)) - - // Update state - this._saveTxList(otherAccountTxs) - } -// -// 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) - this.emit(`tx:status-update`, txId, status) - if (['submitted', 'rejected', 'failed'].includes(status)) { - this.emit(`${txMeta.id}:finished`, txMeta) - } - this.updateTx(txMeta, `txStateManager: setting status to ${status}`) - this.emit('update:badge') - } - - // Saves the new/updated txList. - // Function is intended only for internal use - _saveTxList (transactions) { - this.store.updateState({ transactions }) - } -} -- cgit