aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/lib
diff options
context:
space:
mode:
authorkumavis <kumavis@users.noreply.github.com>2018-04-26 06:52:46 +0800
committerGitHub <noreply@github.com>2018-04-26 06:52:46 +0800
commitdcd04091cc0149cbb0a49bfdf7897e2ac480c7bc (patch)
tree3b2ceb36c0dee2dcf4331bc95590161341a17f91 /app/scripts/lib
parentac334d7b1a9cd8b6888f5c4f3309740d5df62474 (diff)
parent8ffce8b59dc95ffa1af72293f40c21f78fd103bb (diff)
downloadtangerine-wallet-browser-dcd04091cc0149cbb0a49bfdf7897e2ac480c7bc.tar
tangerine-wallet-browser-dcd04091cc0149cbb0a49bfdf7897e2ac480c7bc.tar.gz
tangerine-wallet-browser-dcd04091cc0149cbb0a49bfdf7897e2ac480c7bc.tar.bz2
tangerine-wallet-browser-dcd04091cc0149cbb0a49bfdf7897e2ac480c7bc.tar.lz
tangerine-wallet-browser-dcd04091cc0149cbb0a49bfdf7897e2ac480c7bc.tar.xz
tangerine-wallet-browser-dcd04091cc0149cbb0a49bfdf7897e2ac480c7bc.tar.zst
tangerine-wallet-browser-dcd04091cc0149cbb0a49bfdf7897e2ac480c7bc.zip
Merge pull request #4042 from MetaMask/tx-controller-rewrite-v3
docs and file organization for txController
Diffstat (limited to 'app/scripts/lib')
-rw-r--r--app/scripts/lib/nonce-tracker.js148
-rw-r--r--app/scripts/lib/pending-tx-tracker.js189
-rw-r--r--app/scripts/lib/tx-gas-utils.js103
-rw-r--r--app/scripts/lib/tx-state-history-helper.js41
-rw-r--r--app/scripts/lib/tx-state-manager.js303
5 files changed, 0 insertions, 784 deletions
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 })
- }
-}